replmd: fix variable names in replmd_check_upgrade_links
[sfrench/samba-autobuild/.git] / source4 / dsdb / samdb / ldb_modules / repl_meta_data.c
1 /*
2    ldb database library
3
4    Copyright (C) Simo Sorce  2004-2008
5    Copyright (C) Andrew Bartlett <abartlet@samba.org> 2005-2013
6    Copyright (C) Andrew Tridgell 2005-2009
7    Copyright (C) Stefan Metzmacher <metze@samba.org> 2007
8    Copyright (C) Matthieu Patou <mat@samba.org> 2010-2011
9
10    This program is free software; you can redistribute it and/or modify
11    it under the terms of the GNU General Public License as published by
12    the Free Software Foundation; either version 3 of the License, or
13    (at your option) any later version.
14
15    This program is distributed in the hope that it will be useful,
16    but WITHOUT ANY WARRANTY; without even the implied warranty of
17    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
18    GNU General Public License for more details.
19
20    You should have received a copy of the GNU General Public License
21    along with this program.  If not, see <http://www.gnu.org/licenses/>.
22 */
23
24 /*
25  *  Name: ldb
26  *
27  *  Component: ldb repl_meta_data module
28  *
29  *  Description: - add a unique objectGUID onto every new record,
30  *               - handle whenCreated, whenChanged timestamps
31  *               - handle uSNCreated, uSNChanged numbers
32  *               - handle replPropertyMetaData attribute
33  *
34  *  Author: Simo Sorce
35  *  Author: Stefan Metzmacher
36  */
37
38 #include "includes.h"
39 #include "ldb_module.h"
40 #include "dsdb/samdb/samdb.h"
41 #include "dsdb/common/proto.h"
42 #include "../libds/common/flags.h"
43 #include "librpc/gen_ndr/ndr_misc.h"
44 #include "librpc/gen_ndr/ndr_drsuapi.h"
45 #include "librpc/gen_ndr/ndr_drsblobs.h"
46 #include "param/param.h"
47 #include "libcli/security/security.h"
48 #include "lib/util/dlinklist.h"
49 #include "dsdb/samdb/ldb_modules/util.h"
50 #include "lib/util/binsearch.h"
51 #include "lib/util/tsort.h"
52
53 /*
54  * It's 29/12/9999 at 23:59:59 UTC as specified in MS-ADTS 7.1.1.4.2
55  * Deleted Objects Container
56  */
57 static const NTTIME DELETED_OBJECT_CONTAINER_CHANGE_TIME = 2650466015990000000ULL;
58
59 struct replmd_private {
60         TALLOC_CTX *la_ctx;
61         struct la_entry *la_list;
62         TALLOC_CTX *bl_ctx;
63         struct la_backlink *la_backlinks;
64         struct nc_entry {
65                 struct nc_entry *prev, *next;
66                 struct ldb_dn *dn;
67                 uint64_t mod_usn;
68                 uint64_t mod_usn_urgent;
69         } *ncs;
70         struct ldb_dn *schema_dn;
71         bool originating_updates;
72 };
73
74 struct la_entry {
75         struct la_entry *next, *prev;
76         struct drsuapi_DsReplicaLinkedAttribute *la;
77 };
78
79 struct replmd_replicated_request {
80         struct ldb_module *module;
81         struct ldb_request *req;
82
83         const struct dsdb_schema *schema;
84         struct GUID our_invocation_id;
85
86         /* the controls we pass down */
87         struct ldb_control **controls;
88
89         /* details for the mode where we apply a bunch of inbound replication meessages */
90         bool apply_mode;
91         uint32_t index_current;
92         struct dsdb_extended_replicated_objects *objs;
93
94         struct ldb_message *search_msg;
95         struct GUID local_parent_guid;
96
97         uint64_t seq_num;
98         bool is_urgent;
99
100         bool isDeleted;
101 };
102
103 static int replmd_replicated_apply_merge(struct replmd_replicated_request *ar);
104 static int replmd_delete_internals(struct ldb_module *module, struct ldb_request *req, bool re_delete);
105
106 enum urgent_situation {
107         REPL_URGENT_ON_CREATE = 1,
108         REPL_URGENT_ON_UPDATE = 2,
109         REPL_URGENT_ON_DELETE = 4
110 };
111
112 enum deletion_state {
113         OBJECT_NOT_DELETED=1,
114         OBJECT_DELETED=2,
115         OBJECT_RECYCLED=3,
116         OBJECT_TOMBSTONE=4,
117         OBJECT_REMOVED=5
118 };
119
120 static void replmd_deletion_state(struct ldb_module *module,
121                                   const struct ldb_message *msg,
122                                   enum deletion_state *current_state,
123                                   enum deletion_state *next_state)
124 {
125         int ret;
126         bool enabled = false;
127
128         if (msg == NULL) {
129                 *current_state = OBJECT_REMOVED;
130                 if (next_state != NULL) {
131                         *next_state = OBJECT_REMOVED;
132                 }
133                 return;
134         }
135
136         ret = dsdb_recyclebin_enabled(module, &enabled);
137         if (ret != LDB_SUCCESS) {
138                 enabled = false;
139         }
140
141         if (ldb_msg_check_string_attribute(msg, "isDeleted", "TRUE")) {
142                 if (!enabled) {
143                         *current_state = OBJECT_TOMBSTONE;
144                         if (next_state != NULL) {
145                                 *next_state = OBJECT_REMOVED;
146                         }
147                         return;
148                 }
149
150                 if (ldb_msg_check_string_attribute(msg, "isRecycled", "TRUE")) {
151                         *current_state = OBJECT_RECYCLED;
152                         if (next_state != NULL) {
153                                 *next_state = OBJECT_REMOVED;
154                         }
155                         return;
156                 }
157
158                 *current_state = OBJECT_DELETED;
159                 if (next_state != NULL) {
160                         *next_state = OBJECT_RECYCLED;
161                 }
162                 return;
163         }
164
165         *current_state = OBJECT_NOT_DELETED;
166         if (next_state == NULL) {
167                 return;
168         }
169
170         if (enabled) {
171                 *next_state = OBJECT_DELETED;
172         } else {
173                 *next_state = OBJECT_TOMBSTONE;
174         }
175 }
176
177 static const struct {
178         const char *update_name;
179         enum urgent_situation repl_situation;
180 } urgent_objects[] = {
181                 {"nTDSDSA", (REPL_URGENT_ON_CREATE | REPL_URGENT_ON_DELETE)},
182                 {"crossRef", (REPL_URGENT_ON_CREATE | REPL_URGENT_ON_DELETE)},
183                 {"attributeSchema", (REPL_URGENT_ON_CREATE | REPL_URGENT_ON_UPDATE)},
184                 {"classSchema", (REPL_URGENT_ON_CREATE | REPL_URGENT_ON_UPDATE)},
185                 {"secret", (REPL_URGENT_ON_CREATE | REPL_URGENT_ON_UPDATE)},
186                 {"rIDManager", (REPL_URGENT_ON_CREATE | REPL_URGENT_ON_UPDATE)},
187                 {NULL, 0}
188 };
189
190 /* Attributes looked for when updating or deleting, to check for a urgent replication needed */
191 static const char *urgent_attrs[] = {
192                 "lockoutTime",
193                 "pwdLastSet",
194                 "userAccountControl",
195                 NULL
196 };
197
198
199 static bool replmd_check_urgent_objectclass(const struct ldb_message_element *objectclass_el,
200                                         enum urgent_situation situation)
201 {
202         unsigned int i, j;
203         for (i=0; urgent_objects[i].update_name; i++) {
204
205                 if ((situation & urgent_objects[i].repl_situation) == 0) {
206                         continue;
207                 }
208
209                 for (j=0; j<objectclass_el->num_values; j++) {
210                         const struct ldb_val *v = &objectclass_el->values[j];
211                         if (ldb_attr_cmp((const char *)v->data, urgent_objects[i].update_name) == 0) {
212                                 return true;
213                         }
214                 }
215         }
216         return false;
217 }
218
219 static bool replmd_check_urgent_attribute(const struct ldb_message_element *el)
220 {
221         if (ldb_attr_in_list(urgent_attrs, el->name)) {
222                 return true;
223         }
224         return false;
225 }
226
227
228 static int replmd_replicated_apply_isDeleted(struct replmd_replicated_request *ar);
229
230 /*
231   initialise the module
232   allocate the private structure and build the list
233   of partition DNs for use by replmd_notify()
234  */
235 static int replmd_init(struct ldb_module *module)
236 {
237         struct replmd_private *replmd_private;
238         struct ldb_context *ldb = ldb_module_get_ctx(module);
239
240         replmd_private = talloc_zero(module, struct replmd_private);
241         if (replmd_private == NULL) {
242                 ldb_oom(ldb);
243                 return LDB_ERR_OPERATIONS_ERROR;
244         }
245         ldb_module_set_private(module, replmd_private);
246
247         replmd_private->schema_dn = ldb_get_schema_basedn(ldb);
248
249         return ldb_next_init(module);
250 }
251
252 /*
253   cleanup our per-transaction contexts
254  */
255 static void replmd_txn_cleanup(struct replmd_private *replmd_private)
256 {
257         talloc_free(replmd_private->la_ctx);
258         replmd_private->la_list = NULL;
259         replmd_private->la_ctx = NULL;
260
261         talloc_free(replmd_private->bl_ctx);
262         replmd_private->la_backlinks = NULL;
263         replmd_private->bl_ctx = NULL;
264 }
265
266
267 struct la_backlink {
268         struct la_backlink *next, *prev;
269         const char *attr_name;
270         struct GUID forward_guid, target_guid;
271         bool active;
272 };
273
274 /*
275   a ldb_modify request operating on modules below the
276   current module
277  */
278 static int linked_attr_modify(struct ldb_module *module,
279                               const struct ldb_message *message,
280                               struct ldb_request *parent)
281 {
282         struct ldb_request *mod_req;
283         int ret;
284         struct ldb_context *ldb = ldb_module_get_ctx(module);
285         TALLOC_CTX *tmp_ctx = talloc_new(module);
286         struct ldb_result *res;
287
288         res = talloc_zero(tmp_ctx, struct ldb_result);
289         if (!res) {
290                 talloc_free(tmp_ctx);
291                 return ldb_oom(ldb_module_get_ctx(module));
292         }
293
294         ret = ldb_build_mod_req(&mod_req, ldb, tmp_ctx,
295                                 message,
296                                 NULL,
297                                 res,
298                                 ldb_modify_default_callback,
299                                 parent);
300         LDB_REQ_SET_LOCATION(mod_req);
301         if (ret != LDB_SUCCESS) {
302                 talloc_free(tmp_ctx);
303                 return ret;
304         }
305
306         ret = ldb_request_add_control(mod_req, DSDB_CONTROL_REPLICATED_UPDATE_OID,
307                                       false, NULL);
308         if (ret != LDB_SUCCESS) {
309                 return ret;
310         }
311
312         /* Run the new request */
313         ret = ldb_next_request(module, mod_req);
314
315         if (ret == LDB_SUCCESS) {
316                 ret = ldb_wait(mod_req->handle, LDB_WAIT_ALL);
317         }
318
319         talloc_free(tmp_ctx);
320         return ret;
321 }
322
323 /*
324   process a backlinks we accumulated during a transaction, adding and
325   deleting the backlinks from the target objects
326  */
327 static int replmd_process_backlink(struct ldb_module *module, struct la_backlink *bl, struct ldb_request *parent)
328 {
329         struct ldb_dn *target_dn, *source_dn;
330         int ret;
331         struct ldb_context *ldb = ldb_module_get_ctx(module);
332         struct ldb_message *msg;
333         TALLOC_CTX *tmp_ctx = talloc_new(bl);
334         char *dn_string;
335
336         /*
337           - find DN of target
338           - find DN of source
339           - construct ldb_message
340               - either an add or a delete
341          */
342         ret = dsdb_module_dn_by_guid(module, tmp_ctx, &bl->target_guid, &target_dn, parent);
343         if (ret != LDB_SUCCESS) {
344                 DEBUG(2,(__location__ ": WARNING: Failed to find target DN for linked attribute with GUID %s\n",
345                          GUID_string(bl, &bl->target_guid)));
346                 return LDB_SUCCESS;
347         }
348
349         ret = dsdb_module_dn_by_guid(module, tmp_ctx, &bl->forward_guid, &source_dn, parent);
350         if (ret != LDB_SUCCESS) {
351                 ldb_asprintf_errstring(ldb, "Failed to find source DN for linked attribute with GUID %s\n",
352                                        GUID_string(bl, &bl->forward_guid));
353                 talloc_free(tmp_ctx);
354                 return ret;
355         }
356
357         msg = ldb_msg_new(tmp_ctx);
358         if (msg == NULL) {
359                 ldb_module_oom(module);
360                 talloc_free(tmp_ctx);
361                 return LDB_ERR_OPERATIONS_ERROR;
362         }
363
364         /* construct a ldb_message for adding/deleting the backlink */
365         msg->dn = target_dn;
366         dn_string = ldb_dn_get_extended_linearized(tmp_ctx, source_dn, 1);
367         if (!dn_string) {
368                 ldb_module_oom(module);
369                 talloc_free(tmp_ctx);
370                 return LDB_ERR_OPERATIONS_ERROR;
371         }
372         ret = ldb_msg_add_steal_string(msg, bl->attr_name, dn_string);
373         if (ret != LDB_SUCCESS) {
374                 talloc_free(tmp_ctx);
375                 return ret;
376         }
377         msg->elements[0].flags = bl->active?LDB_FLAG_MOD_ADD:LDB_FLAG_MOD_DELETE;
378
379         /* a backlink should never be single valued. Unfortunately the
380            exchange schema has a attribute
381            msExchBridgeheadedLocalConnectorsDNBL which is single
382            valued and a backlink. We need to cope with that by
383            ignoring the single value flag */
384         msg->elements[0].flags |= LDB_FLAG_INTERNAL_DISABLE_SINGLE_VALUE_CHECK;
385
386         ret = dsdb_module_modify(module, msg, DSDB_FLAG_NEXT_MODULE, parent);
387         if (ret == LDB_ERR_NO_SUCH_ATTRIBUTE && !bl->active) {
388                 /* we allow LDB_ERR_NO_SUCH_ATTRIBUTE as success to
389                    cope with possible corruption where the backlink has
390                    already been removed */
391                 DEBUG(3,("WARNING: backlink from %s already removed from %s - %s\n",
392                          ldb_dn_get_linearized(target_dn),
393                          ldb_dn_get_linearized(source_dn),
394                          ldb_errstring(ldb)));
395                 ret = LDB_SUCCESS;
396         } else if (ret != LDB_SUCCESS) {
397                 ldb_asprintf_errstring(ldb, "Failed to %s backlink from %s to %s - %s",
398                                        bl->active?"add":"remove",
399                                        ldb_dn_get_linearized(source_dn),
400                                        ldb_dn_get_linearized(target_dn),
401                                        ldb_errstring(ldb));
402                 talloc_free(tmp_ctx);
403                 return ret;
404         }
405         talloc_free(tmp_ctx);
406         return ret;
407 }
408
409 /*
410   add a backlink to the list of backlinks to add/delete in the prepare
411   commit
412  */
413 static int replmd_add_backlink(struct ldb_module *module,
414                                struct replmd_private *replmd_private,
415                                const struct dsdb_schema *schema,
416                                struct GUID *forward_guid,
417                                struct GUID *target_guid, bool active,
418                                const struct dsdb_attribute *schema_attr,
419                                bool immediate)
420 {
421         const struct dsdb_attribute *target_attr;
422         struct la_backlink *bl;
423
424         target_attr = dsdb_attribute_by_linkID(schema, schema_attr->linkID ^ 1);
425         if (!target_attr) {
426                 /*
427                  * windows 2003 has a broken schema where the
428                  * definition of msDS-IsDomainFor is missing (which is
429                  * supposed to be the backlink of the
430                  * msDS-HasDomainNCs attribute
431                  */
432                 return LDB_SUCCESS;
433         }
434
435         /* see if its already in the list */
436         for (bl=replmd_private->la_backlinks; bl; bl=bl->next) {
437                 if (GUID_equal(forward_guid, &bl->forward_guid) &&
438                     GUID_equal(target_guid, &bl->target_guid) &&
439                     (target_attr->lDAPDisplayName == bl->attr_name ||
440                      strcmp(target_attr->lDAPDisplayName, bl->attr_name) == 0)) {
441                         break;
442                 }
443         }
444
445         if (bl) {
446                 /* we found an existing one */
447                 if (bl->active == active) {
448                         return LDB_SUCCESS;
449                 }
450                 DLIST_REMOVE(replmd_private->la_backlinks, bl);
451                 talloc_free(bl);
452                 return LDB_SUCCESS;
453         }
454
455         if (replmd_private->bl_ctx == NULL) {
456                 replmd_private->bl_ctx = talloc_new(replmd_private);
457                 if (replmd_private->bl_ctx == NULL) {
458                         ldb_module_oom(module);
459                         return LDB_ERR_OPERATIONS_ERROR;
460                 }
461         }
462
463         /* its a new one */
464         bl = talloc(replmd_private->bl_ctx, struct la_backlink);
465         if (bl == NULL) {
466                 ldb_module_oom(module);
467                 return LDB_ERR_OPERATIONS_ERROR;
468         }
469
470         /* Ensure the schema does not go away before the bl->attr_name is used */
471         if (!talloc_reference(bl, schema)) {
472                 talloc_free(bl);
473                 ldb_module_oom(module);
474                 return LDB_ERR_OPERATIONS_ERROR;
475         }
476
477         bl->attr_name = target_attr->lDAPDisplayName;
478         bl->forward_guid = *forward_guid;
479         bl->target_guid = *target_guid;
480         bl->active = active;
481
482         /* the caller may ask for this backlink to be processed
483            immediately */
484         if (immediate) {
485                 int ret = replmd_process_backlink(module, bl, NULL);
486                 talloc_free(bl);
487                 return ret;
488         }
489
490         DLIST_ADD(replmd_private->la_backlinks, bl);
491
492         return LDB_SUCCESS;
493 }
494
495
496 /*
497  * Callback for most write operations in this module:
498  *
499  * notify the repl task that a object has changed. The notifies are
500  * gathered up in the replmd_private structure then written to the
501  * @REPLCHANGED object in each partition during the prepare_commit
502  */
503 static int replmd_op_callback(struct ldb_request *req, struct ldb_reply *ares)
504 {
505         int ret;
506         struct replmd_replicated_request *ac =
507                 talloc_get_type_abort(req->context, struct replmd_replicated_request);
508         struct replmd_private *replmd_private =
509                 talloc_get_type_abort(ldb_module_get_private(ac->module), struct replmd_private);
510         struct nc_entry *modified_partition;
511         struct ldb_control *partition_ctrl;
512         const struct dsdb_control_current_partition *partition;
513
514         struct ldb_control **controls;
515
516         partition_ctrl = ldb_reply_get_control(ares, DSDB_CONTROL_CURRENT_PARTITION_OID);
517
518         controls = ares->controls;
519         if (ldb_request_get_control(ac->req,
520                                     DSDB_CONTROL_CURRENT_PARTITION_OID) == NULL) {
521                 /*
522                  * Remove the current partition control from what we pass up
523                  * the chain if it hasn't been requested manually.
524                  */
525                 controls = ldb_controls_except_specified(ares->controls, ares,
526                                                          partition_ctrl);
527         }
528
529         if (ares->error != LDB_SUCCESS) {
530                 DEBUG(5,("%s failure. Error is: %s\n", __FUNCTION__, ldb_strerror(ares->error)));
531                 return ldb_module_done(ac->req, controls,
532                                         ares->response, ares->error);
533         }
534
535         if (ares->type != LDB_REPLY_DONE) {
536                 ldb_set_errstring(ldb_module_get_ctx(ac->module), "Invalid reply type for notify\n!");
537                 return ldb_module_done(ac->req, NULL,
538                                        NULL, LDB_ERR_OPERATIONS_ERROR);
539         }
540
541         if (!partition_ctrl) {
542                 ldb_set_errstring(ldb_module_get_ctx(ac->module),"No partition control on reply");
543                 return ldb_module_done(ac->req, NULL,
544                                        NULL, LDB_ERR_OPERATIONS_ERROR);
545         }
546
547         partition = talloc_get_type_abort(partition_ctrl->data,
548                                     struct dsdb_control_current_partition);
549
550         if (ac->seq_num > 0) {
551                 for (modified_partition = replmd_private->ncs; modified_partition;
552                      modified_partition = modified_partition->next) {
553                         if (ldb_dn_compare(modified_partition->dn, partition->dn) == 0) {
554                                 break;
555                         }
556                 }
557
558                 if (modified_partition == NULL) {
559                         modified_partition = talloc_zero(replmd_private, struct nc_entry);
560                         if (!modified_partition) {
561                                 ldb_oom(ldb_module_get_ctx(ac->module));
562                                 return ldb_module_done(ac->req, NULL,
563                                                        NULL, LDB_ERR_OPERATIONS_ERROR);
564                         }
565                         modified_partition->dn = ldb_dn_copy(modified_partition, partition->dn);
566                         if (!modified_partition->dn) {
567                                 ldb_oom(ldb_module_get_ctx(ac->module));
568                                 return ldb_module_done(ac->req, NULL,
569                                                        NULL, LDB_ERR_OPERATIONS_ERROR);
570                         }
571                         DLIST_ADD(replmd_private->ncs, modified_partition);
572                 }
573
574                 if (ac->seq_num > modified_partition->mod_usn) {
575                         modified_partition->mod_usn = ac->seq_num;
576                         if (ac->is_urgent) {
577                                 modified_partition->mod_usn_urgent = ac->seq_num;
578                         }
579                 }
580                 if (!ac->apply_mode) {
581                         replmd_private->originating_updates = true;
582                 }
583         }
584
585         if (ac->apply_mode) {
586                 ret = replmd_replicated_apply_isDeleted(ac);
587                 if (ret != LDB_SUCCESS) {
588                         return ldb_module_done(ac->req, NULL, NULL, ret);
589                 }
590                 return ret;
591         } else {
592                 /* free the partition control container here, for the
593                  * common path.  Other cases will have it cleaned up
594                  * eventually with the ares */
595                 talloc_free(partition_ctrl);
596                 return ldb_module_done(ac->req, controls,
597                                        ares->response, LDB_SUCCESS);
598         }
599 }
600
601
602 /*
603  * update a @REPLCHANGED record in each partition if there have been
604  * any writes of replicated data in the partition
605  */
606 static int replmd_notify_store(struct ldb_module *module, struct ldb_request *parent)
607 {
608         struct replmd_private *replmd_private =
609                 talloc_get_type(ldb_module_get_private(module), struct replmd_private);
610
611         while (replmd_private->ncs) {
612                 int ret;
613                 struct nc_entry *modified_partition = replmd_private->ncs;
614
615                 ret = dsdb_module_save_partition_usn(module, modified_partition->dn,
616                                                      modified_partition->mod_usn,
617                                                      modified_partition->mod_usn_urgent, parent);
618                 if (ret != LDB_SUCCESS) {
619                         DEBUG(0,(__location__ ": Failed to save partition uSN for %s\n",
620                                  ldb_dn_get_linearized(modified_partition->dn)));
621                         return ret;
622                 }
623
624                 if (ldb_dn_compare(modified_partition->dn,
625                                    replmd_private->schema_dn) == 0) {
626                         struct ldb_result *ext_res;
627                         ret = dsdb_module_extended(module,
628                                                    replmd_private->schema_dn,
629                                                    &ext_res,
630                                                    DSDB_EXTENDED_SCHEMA_UPDATE_NOW_OID,
631                                                    ext_res,
632                                                    DSDB_FLAG_NEXT_MODULE,
633                                                    parent);
634                         if (ret != LDB_SUCCESS) {
635                                 return ret;
636                         }
637                         talloc_free(ext_res);
638                 }
639
640                 DLIST_REMOVE(replmd_private->ncs, modified_partition);
641                 talloc_free(modified_partition);
642         }
643
644         return LDB_SUCCESS;
645 }
646
647
648 /*
649   created a replmd_replicated_request context
650  */
651 static struct replmd_replicated_request *replmd_ctx_init(struct ldb_module *module,
652                                                          struct ldb_request *req)
653 {
654         struct ldb_context *ldb;
655         struct replmd_replicated_request *ac;
656         const struct GUID *our_invocation_id;
657
658         ldb = ldb_module_get_ctx(module);
659
660         ac = talloc_zero(req, struct replmd_replicated_request);
661         if (ac == NULL) {
662                 ldb_oom(ldb);
663                 return NULL;
664         }
665
666         ac->module = module;
667         ac->req = req;
668
669         ac->schema = dsdb_get_schema(ldb, ac);
670         if (!ac->schema) {
671                 ldb_debug_set(ldb, LDB_DEBUG_FATAL,
672                               "replmd_modify: no dsdb_schema loaded");
673                 DEBUG(0,(__location__ ": %s\n", ldb_errstring(ldb)));
674                 talloc_free(ac);
675                 return NULL;
676         }
677
678         /* get our invocationId */
679         our_invocation_id = samdb_ntds_invocation_id(ldb);
680         if (!our_invocation_id) {
681                 ldb_debug_set(ldb, LDB_DEBUG_FATAL,
682                               "replmd_add: unable to find invocationId\n");
683                 talloc_free(ac);
684                 return NULL;
685         }
686         ac->our_invocation_id = *our_invocation_id;
687
688         return ac;
689 }
690
691 /*
692   add a time element to a record
693 */
694 static int add_time_element(struct ldb_message *msg, const char *attr, time_t t)
695 {
696         struct ldb_message_element *el;
697         char *s;
698         int ret;
699
700         if (ldb_msg_find_element(msg, attr) != NULL) {
701                 return LDB_SUCCESS;
702         }
703
704         s = ldb_timestring(msg, t);
705         if (s == NULL) {
706                 return LDB_ERR_OPERATIONS_ERROR;
707         }
708
709         ret = ldb_msg_add_string(msg, attr, s);
710         if (ret != LDB_SUCCESS) {
711                 return ret;
712         }
713
714         el = ldb_msg_find_element(msg, attr);
715         /* always set as replace. This works because on add ops, the flag
716            is ignored */
717         el->flags = LDB_FLAG_MOD_REPLACE;
718
719         return LDB_SUCCESS;
720 }
721
722 /*
723   add a uint64_t element to a record
724 */
725 static int add_uint64_element(struct ldb_context *ldb, struct ldb_message *msg,
726                               const char *attr, uint64_t v)
727 {
728         struct ldb_message_element *el;
729         int ret;
730
731         if (ldb_msg_find_element(msg, attr) != NULL) {
732                 return LDB_SUCCESS;
733         }
734
735         ret = samdb_msg_add_uint64(ldb, msg, msg, attr, v);
736         if (ret != LDB_SUCCESS) {
737                 return ret;
738         }
739
740         el = ldb_msg_find_element(msg, attr);
741         /* always set as replace. This works because on add ops, the flag
742            is ignored */
743         el->flags = LDB_FLAG_MOD_REPLACE;
744
745         return LDB_SUCCESS;
746 }
747
748 static int replmd_replPropertyMetaData1_attid_sort(const struct replPropertyMetaData1 *m1,
749                                                    const struct replPropertyMetaData1 *m2,
750                                                    const uint32_t *rdn_attid)
751 {
752         /*
753          * This assignment seems inoccous, but it is critical for the
754          * system, as we need to do the comparisons as a unsigned
755          * quantity, not signed (enums are signed integers)
756          */
757         uint32_t attid_1 = m1->attid;
758         uint32_t attid_2 = m2->attid;
759
760         if (attid_1 == attid_2) {
761                 return 0;
762         }
763
764         /*
765          * See above regarding this being an unsigned comparison.
766          * Otherwise when the high bit is set on non-standard
767          * attributes, they would end up first, before objectClass
768          * (0).
769          */
770         return attid_1 > attid_2 ? 1 : -1;
771 }
772
773 static int replmd_replPropertyMetaDataCtr1_verify(struct ldb_context *ldb,
774                                                   struct replPropertyMetaDataCtr1 *ctr1,
775                                                   struct ldb_dn *dn)
776 {
777         if (ctr1->count == 0) {
778                 ldb_debug_set(ldb, LDB_DEBUG_FATAL,
779                               "No elements found in replPropertyMetaData for %s!\n",
780                               ldb_dn_get_linearized(dn));
781                 return LDB_ERR_CONSTRAINT_VIOLATION;
782         }
783
784         /* the objectClass attribute is value 0x00000000, so must be first */
785         if (ctr1->array[0].attid != DRSUAPI_ATTID_objectClass) {
786                 ldb_debug_set(ldb, LDB_DEBUG_FATAL,
787                               "No objectClass found in replPropertyMetaData for %s!\n",
788                               ldb_dn_get_linearized(dn));
789                 return LDB_ERR_OBJECT_CLASS_VIOLATION;
790         }
791
792         return LDB_SUCCESS;
793 }
794
795 static int replmd_replPropertyMetaDataCtr1_sort_and_verify(struct ldb_context *ldb,
796                                                            struct replPropertyMetaDataCtr1 *ctr1,
797                                                            struct ldb_dn *dn)
798 {
799         /* Note this is O(n^2) for the almost-sorted case, which this is */
800         LDB_TYPESAFE_QSORT(ctr1->array, ctr1->count, NULL,
801                            replmd_replPropertyMetaData1_attid_sort);
802         return replmd_replPropertyMetaDataCtr1_verify(ldb, ctr1, dn);
803 }
804
805 static int replmd_ldb_message_element_attid_sort(const struct ldb_message_element *e1,
806                                                  const struct ldb_message_element *e2,
807                                                  const struct dsdb_schema *schema)
808 {
809         const struct dsdb_attribute *a1;
810         const struct dsdb_attribute *a2;
811
812         /*
813          * TODO: make this faster by caching the dsdb_attribute pointer
814          *       on the ldb_messag_element
815          */
816
817         a1 = dsdb_attribute_by_lDAPDisplayName(schema, e1->name);
818         a2 = dsdb_attribute_by_lDAPDisplayName(schema, e2->name);
819
820         /*
821          * TODO: remove this check, we should rely on e1 and e2 having valid attribute names
822          *       in the schema
823          */
824         if (!a1 || !a2) {
825                 return strcasecmp(e1->name, e2->name);
826         }
827         if (a1->attributeID_id == a2->attributeID_id) {
828                 return 0;
829         }
830         return a1->attributeID_id > a2->attributeID_id ? 1 : -1;
831 }
832
833 static void replmd_ldb_message_sort(struct ldb_message *msg,
834                                     const struct dsdb_schema *schema)
835 {
836         LDB_TYPESAFE_QSORT(msg->elements, msg->num_elements, schema, replmd_ldb_message_element_attid_sort);
837 }
838
839 static int replmd_build_la_val(TALLOC_CTX *mem_ctx, struct ldb_val *v, struct dsdb_dn *dsdb_dn,
840                                const struct GUID *invocation_id, uint64_t seq_num,
841                                uint64_t local_usn, NTTIME nttime, uint32_t version, bool deleted);
842
843
844 /*
845   fix up linked attributes in replmd_add.
846   This involves setting up the right meta-data in extended DN
847   components, and creating backlinks to the object
848  */
849 static int replmd_add_fix_la(struct ldb_module *module,
850                              struct replmd_private *replmd_private,
851                              struct ldb_message_element *el,
852                              uint64_t seq_num, const struct GUID *invocationId, NTTIME now,
853                              struct GUID *guid, const struct dsdb_attribute *sa, struct ldb_request *parent)
854 {
855         unsigned int i;
856         TALLOC_CTX *tmp_ctx = talloc_new(el->values);
857         struct ldb_context *ldb = ldb_module_get_ctx(module);
858
859         /* We will take a reference to the schema in replmd_add_backlink */
860         const struct dsdb_schema *schema = dsdb_get_schema(ldb, NULL);
861
862         for (i=0; i<el->num_values; i++) {
863                 struct ldb_val *v = &el->values[i];
864                 struct dsdb_dn *dsdb_dn = dsdb_dn_parse(tmp_ctx, ldb, v, sa->syntax->ldap_oid);
865                 struct GUID target_guid;
866                 NTSTATUS status;
867                 int ret;
868
869                 if (dsdb_dn == NULL) {
870                         talloc_free(tmp_ctx);
871                         return LDB_ERR_INVALID_DN_SYNTAX;
872                 }
873
874                 /* note that the DN already has the extended
875                    components from the extended_dn_store module */
876                 status = dsdb_get_extended_dn_guid(dsdb_dn->dn, &target_guid, "GUID");
877                 if (!NT_STATUS_IS_OK(status) || GUID_all_zero(&target_guid)) {
878                         ret = dsdb_module_guid_by_dn(module, dsdb_dn->dn, &target_guid, parent);
879                         if (ret != LDB_SUCCESS) {
880                                 talloc_free(tmp_ctx);
881                                 return ret;
882                         }
883                         ret = dsdb_set_extended_dn_guid(dsdb_dn->dn, &target_guid, "GUID");
884                         if (ret != LDB_SUCCESS) {
885                                 talloc_free(tmp_ctx);
886                                 return ret;
887                         }
888                 }
889
890                 ret = replmd_build_la_val(el->values, v, dsdb_dn, invocationId,
891                                           seq_num, seq_num, now, 0, false);
892                 if (ret != LDB_SUCCESS) {
893                         talloc_free(tmp_ctx);
894                         return ret;
895                 }
896
897                 ret = replmd_add_backlink(module, replmd_private,
898                                           schema, guid, &target_guid, true, sa,
899                                           false);
900                 if (ret != LDB_SUCCESS) {
901                         talloc_free(tmp_ctx);
902                         return ret;
903                 }
904         }
905
906         talloc_free(tmp_ctx);
907         return LDB_SUCCESS;
908 }
909
910
911 /*
912   intercept add requests
913  */
914 static int replmd_add(struct ldb_module *module, struct ldb_request *req)
915 {
916         struct ldb_context *ldb;
917         struct ldb_control *control;
918         struct replmd_replicated_request *ac;
919         enum ndr_err_code ndr_err;
920         struct ldb_request *down_req;
921         struct ldb_message *msg;
922         const DATA_BLOB *guid_blob;
923         struct GUID guid;
924         struct replPropertyMetaDataBlob nmd;
925         struct ldb_val nmd_value;
926
927         /*
928          * The use of a time_t here seems odd, but as the NTTIME
929          * elements are actually declared as NTTIME_1sec in the IDL,
930          * getting a higher resolution timestamp is not required.
931          */
932         time_t t = time(NULL);
933         NTTIME now;
934         char *time_str;
935         int ret;
936         unsigned int i;
937         unsigned int functional_level;
938         uint32_t ni=0;
939         bool allow_add_guid = false;
940         bool remove_current_guid = false;
941         bool is_urgent = false;
942         bool is_schema_nc = false;
943         struct ldb_message_element *objectclass_el;
944         struct replmd_private *replmd_private =
945                 talloc_get_type_abort(ldb_module_get_private(module), struct replmd_private);
946
947         /* check if there's a show relax control (used by provision to say 'I know what I'm doing') */
948         control = ldb_request_get_control(req, LDB_CONTROL_RELAX_OID);
949         if (control) {
950                 allow_add_guid = true;
951         }
952
953         /* do not manipulate our control entries */
954         if (ldb_dn_is_special(req->op.add.message->dn)) {
955                 return ldb_next_request(module, req);
956         }
957
958         ldb = ldb_module_get_ctx(module);
959
960         ldb_debug(ldb, LDB_DEBUG_TRACE, "replmd_add\n");
961
962         guid_blob = ldb_msg_find_ldb_val(req->op.add.message, "objectGUID");
963         if (guid_blob != NULL) {
964                 if (!allow_add_guid) {
965                         ldb_set_errstring(ldb,
966                                           "replmd_add: it's not allowed to add an object with objectGUID!");
967                         return LDB_ERR_UNWILLING_TO_PERFORM;
968                 } else {
969                         NTSTATUS status = GUID_from_data_blob(guid_blob,&guid);
970                         if (!NT_STATUS_IS_OK(status)) {
971                                 ldb_set_errstring(ldb,
972                                                   "replmd_add: Unable to parse the 'objectGUID' as a GUID!");
973                                 return LDB_ERR_UNWILLING_TO_PERFORM;
974                         }
975                         /* we remove this attribute as it can be a string and
976                          * will not be treated correctly and then we will re-add
977                          * it later on in the good format */
978                         remove_current_guid = true;
979                 }
980         } else {
981                 /* a new GUID */
982                 guid = GUID_random();
983         }
984
985         ac = replmd_ctx_init(module, req);
986         if (ac == NULL) {
987                 return ldb_module_oom(module);
988         }
989
990         functional_level = dsdb_functional_level(ldb);
991
992         /* Get a sequence number from the backend */
993         ret = ldb_sequence_number(ldb, LDB_SEQ_NEXT, &ac->seq_num);
994         if (ret != LDB_SUCCESS) {
995                 talloc_free(ac);
996                 return ret;
997         }
998
999         /* we have to copy the message as the caller might have it as a const */
1000         msg = ldb_msg_copy_shallow(ac, req->op.add.message);
1001         if (msg == NULL) {
1002                 ldb_oom(ldb);
1003                 talloc_free(ac);
1004                 return LDB_ERR_OPERATIONS_ERROR;
1005         }
1006
1007         /* generated times */
1008         unix_to_nt_time(&now, t);
1009         time_str = ldb_timestring(msg, t);
1010         if (!time_str) {
1011                 ldb_oom(ldb);
1012                 talloc_free(ac);
1013                 return LDB_ERR_OPERATIONS_ERROR;
1014         }
1015         if (remove_current_guid) {
1016                 ldb_msg_remove_attr(msg,"objectGUID");
1017         }
1018
1019         /*
1020          * remove autogenerated attributes
1021          */
1022         ldb_msg_remove_attr(msg, "whenCreated");
1023         ldb_msg_remove_attr(msg, "whenChanged");
1024         ldb_msg_remove_attr(msg, "uSNCreated");
1025         ldb_msg_remove_attr(msg, "uSNChanged");
1026         ldb_msg_remove_attr(msg, "replPropertyMetaData");
1027
1028         /*
1029          * readd replicated attributes
1030          */
1031         ret = ldb_msg_add_string(msg, "whenCreated", time_str);
1032         if (ret != LDB_SUCCESS) {
1033                 ldb_oom(ldb);
1034                 talloc_free(ac);
1035                 return ret;
1036         }
1037
1038         /* build the replication meta_data */
1039         ZERO_STRUCT(nmd);
1040         nmd.version             = 1;
1041         nmd.ctr.ctr1.count      = msg->num_elements;
1042         nmd.ctr.ctr1.array      = talloc_array(msg,
1043                                                struct replPropertyMetaData1,
1044                                                nmd.ctr.ctr1.count);
1045         if (!nmd.ctr.ctr1.array) {
1046                 ldb_oom(ldb);
1047                 talloc_free(ac);
1048                 return LDB_ERR_OPERATIONS_ERROR;
1049         }
1050
1051         is_schema_nc = ldb_dn_compare_base(replmd_private->schema_dn, msg->dn) == 0;
1052
1053         for (i=0; i < msg->num_elements;) {
1054                 struct ldb_message_element *e = &msg->elements[i];
1055                 struct replPropertyMetaData1 *m = &nmd.ctr.ctr1.array[ni];
1056                 const struct dsdb_attribute *sa;
1057
1058                 if (e->name[0] == '@') {
1059                         i++;
1060                         continue;
1061                 }
1062
1063                 sa = dsdb_attribute_by_lDAPDisplayName(ac->schema, e->name);
1064                 if (!sa) {
1065                         ldb_debug_set(ldb, LDB_DEBUG_ERROR,
1066                                       "replmd_add: attribute '%s' not defined in schema\n",
1067                                       e->name);
1068                         talloc_free(ac);
1069                         return LDB_ERR_NO_SUCH_ATTRIBUTE;
1070                 }
1071
1072                 if ((sa->systemFlags & DS_FLAG_ATTR_NOT_REPLICATED) || (sa->systemFlags & DS_FLAG_ATTR_IS_CONSTRUCTED)) {
1073                         /* if the attribute is not replicated (0x00000001)
1074                          * or constructed (0x00000004) it has no metadata
1075                          */
1076                         i++;
1077                         continue;
1078                 }
1079
1080                 if (sa->linkID != 0 && functional_level > DS_DOMAIN_FUNCTION_2000) {
1081                         ret = replmd_add_fix_la(module, replmd_private, e,
1082                                                 ac->seq_num,
1083                                                 &ac->our_invocation_id, now,
1084                                                 &guid, sa, req);
1085                         if (ret != LDB_SUCCESS) {
1086                                 talloc_free(ac);
1087                                 return ret;
1088                         }
1089                         /* linked attributes are not stored in
1090                            replPropertyMetaData in FL above w2k */
1091                         i++;
1092                         continue;
1093                 }
1094
1095                 m->attid   = dsdb_attribute_get_attid(sa, is_schema_nc);
1096                 m->version = 1;
1097                 if (m->attid == DRSUAPI_ATTID_isDeleted) {
1098                         const struct ldb_val *rdn_val = ldb_dn_get_rdn_val(msg->dn);
1099                         const char* rdn;
1100
1101                         if (rdn_val == NULL) {
1102                                 ldb_oom(ldb);
1103                                 talloc_free(ac);
1104                                 return LDB_ERR_OPERATIONS_ERROR;
1105                         }
1106
1107                         rdn = (const char*)rdn_val->data;
1108                         if (strcmp(rdn, "Deleted Objects") == 0) {
1109                                 /*
1110                                  * Set the originating_change_time to 29/12/9999 at 23:59:59
1111                                  * as specified in MS-ADTS 7.1.1.4.2 Deleted Objects Container
1112                                  */
1113                                 m->originating_change_time      = DELETED_OBJECT_CONTAINER_CHANGE_TIME;
1114                         } else {
1115                                 m->originating_change_time      = now;
1116                         }
1117                 } else {
1118                         m->originating_change_time      = now;
1119                 }
1120                 m->originating_invocation_id    = ac->our_invocation_id;
1121                 m->originating_usn              = ac->seq_num;
1122                 m->local_usn                    = ac->seq_num;
1123                 ni++;
1124
1125                 if (!(e->flags & DSDB_FLAG_INTERNAL_FORCE_META_DATA)) {
1126                         i++;
1127                         continue;
1128                 }
1129
1130                 e->flags &= ~DSDB_FLAG_INTERNAL_FORCE_META_DATA;
1131
1132                 if (e->num_values != 0) {
1133                         i++;
1134                         continue;
1135                 }
1136
1137                 ldb_msg_remove_element(msg, e);
1138         }
1139
1140         /* fix meta data count */
1141         nmd.ctr.ctr1.count = ni;
1142
1143         /*
1144          * sort meta data array
1145          */
1146         ret = replmd_replPropertyMetaDataCtr1_sort_and_verify(ldb, &nmd.ctr.ctr1, msg->dn);
1147         if (ret != LDB_SUCCESS) {
1148                 ldb_asprintf_errstring(ldb, "%s: error during direct ADD: %s", __func__, ldb_errstring(ldb));
1149                 talloc_free(ac);
1150                 return ret;
1151         }
1152
1153         /* generated NDR encoded values */
1154         ndr_err = ndr_push_struct_blob(&nmd_value, msg,
1155                                        &nmd,
1156                                        (ndr_push_flags_fn_t)ndr_push_replPropertyMetaDataBlob);
1157         if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
1158                 ldb_oom(ldb);
1159                 talloc_free(ac);
1160                 return LDB_ERR_OPERATIONS_ERROR;
1161         }
1162
1163         /*
1164          * add the autogenerated values
1165          */
1166         ret = dsdb_msg_add_guid(msg, &guid, "objectGUID");
1167         if (ret != LDB_SUCCESS) {
1168                 ldb_oom(ldb);
1169                 talloc_free(ac);
1170                 return ret;
1171         }
1172         ret = ldb_msg_add_string(msg, "whenChanged", time_str);
1173         if (ret != LDB_SUCCESS) {
1174                 ldb_oom(ldb);
1175                 talloc_free(ac);
1176                 return ret;
1177         }
1178         ret = samdb_msg_add_uint64(ldb, msg, msg, "uSNCreated", ac->seq_num);
1179         if (ret != LDB_SUCCESS) {
1180                 ldb_oom(ldb);
1181                 talloc_free(ac);
1182                 return ret;
1183         }
1184         ret = samdb_msg_add_uint64(ldb, msg, msg, "uSNChanged", ac->seq_num);
1185         if (ret != LDB_SUCCESS) {
1186                 ldb_oom(ldb);
1187                 talloc_free(ac);
1188                 return ret;
1189         }
1190         ret = ldb_msg_add_value(msg, "replPropertyMetaData", &nmd_value, NULL);
1191         if (ret != LDB_SUCCESS) {
1192                 ldb_oom(ldb);
1193                 talloc_free(ac);
1194                 return ret;
1195         }
1196
1197         /*
1198          * sort the attributes by attid before storing the object
1199          */
1200         replmd_ldb_message_sort(msg, ac->schema);
1201
1202         /*
1203          * Assert that we do have an objectClass
1204          */
1205         objectclass_el = ldb_msg_find_element(msg, "objectClass");
1206         if (objectclass_el == NULL) {
1207                 ldb_asprintf_errstring(ldb, __location__
1208                                        ": objectClass missing on %s\n",
1209                                        ldb_dn_get_linearized(msg->dn));
1210                 talloc_free(ac);
1211                 return LDB_ERR_OBJECT_CLASS_VIOLATION;
1212         }
1213         is_urgent = replmd_check_urgent_objectclass(objectclass_el,
1214                                                         REPL_URGENT_ON_CREATE);
1215
1216         ac->is_urgent = is_urgent;
1217         ret = ldb_build_add_req(&down_req, ldb, ac,
1218                                 msg,
1219                                 req->controls,
1220                                 ac, replmd_op_callback,
1221                                 req);
1222
1223         LDB_REQ_SET_LOCATION(down_req);
1224         if (ret != LDB_SUCCESS) {
1225                 talloc_free(ac);
1226                 return ret;
1227         }
1228
1229         /* current partition control is needed by "replmd_op_callback" */
1230         if (ldb_request_get_control(req, DSDB_CONTROL_CURRENT_PARTITION_OID) == NULL) {
1231                 ret = ldb_request_add_control(down_req,
1232                                               DSDB_CONTROL_CURRENT_PARTITION_OID,
1233                                               false, NULL);
1234                 if (ret != LDB_SUCCESS) {
1235                         talloc_free(ac);
1236                         return ret;
1237                 }
1238         }
1239
1240         if (functional_level == DS_DOMAIN_FUNCTION_2000) {
1241                 ret = ldb_request_add_control(down_req, DSDB_CONTROL_APPLY_LINKS, false, NULL);
1242                 if (ret != LDB_SUCCESS) {
1243                         talloc_free(ac);
1244                         return ret;
1245                 }
1246         }
1247
1248         /* mark the control done */
1249         if (control) {
1250                 control->critical = 0;
1251         }
1252         /* go on with the call chain */
1253         return ldb_next_request(module, down_req);
1254 }
1255
1256
1257 /*
1258  * update the replPropertyMetaData for one element
1259  */
1260 static int replmd_update_rpmd_element(struct ldb_context *ldb,
1261                                       struct ldb_message *msg,
1262                                       struct ldb_message_element *el,
1263                                       struct ldb_message_element *old_el,
1264                                       struct replPropertyMetaDataBlob *omd,
1265                                       const struct dsdb_schema *schema,
1266                                       uint64_t *seq_num,
1267                                       const struct GUID *our_invocation_id,
1268                                       NTTIME now,
1269                                       bool is_schema_nc,
1270                                       struct ldb_request *req)
1271 {
1272         uint32_t i;
1273         const struct dsdb_attribute *a;
1274         struct replPropertyMetaData1 *md1;
1275         bool may_skip = false;
1276         uint32_t attid;
1277
1278         a = dsdb_attribute_by_lDAPDisplayName(schema, el->name);
1279         if (a == NULL) {
1280                 if (ldb_request_get_control(req, LDB_CONTROL_RELAX_OID)) {
1281                         /* allow this to make it possible for dbcheck
1282                            to remove bad attributes */
1283                         return LDB_SUCCESS;
1284                 }
1285
1286                 DEBUG(0,(__location__ ": Unable to find attribute %s in schema\n",
1287                          el->name));
1288                 return LDB_ERR_OPERATIONS_ERROR;
1289         }
1290
1291         attid = dsdb_attribute_get_attid(a, is_schema_nc);
1292
1293         if ((a->systemFlags & DS_FLAG_ATTR_NOT_REPLICATED) || (a->systemFlags & DS_FLAG_ATTR_IS_CONSTRUCTED)) {
1294                 return LDB_SUCCESS;
1295         }
1296
1297         /*
1298          * if the attribute's value haven't changed, and this isn't
1299          * just a delete of everything then return LDB_SUCCESS Unless
1300          * we have the provision control or if the attribute is
1301          * interSiteTopologyGenerator as this page explain:
1302          * http://support.microsoft.com/kb/224815 this attribute is
1303          * periodicaly written by the DC responsible for the intersite
1304          * generation in a given site
1305          *
1306          * Unchanged could be deleting or replacing an already-gone
1307          * thing with an unconstrained delete/empty replace or a
1308          * replace with the same value, but not an add with the same
1309          * value because that could be about adding a duplicate (which
1310          * is for someone else to error out on).
1311          */
1312         if (old_el != NULL && ldb_msg_element_equal_ordered(el, old_el)) {
1313                 if (LDB_FLAG_MOD_TYPE(el->flags) == LDB_FLAG_MOD_REPLACE) {
1314                         may_skip = true;
1315                 }
1316         } else if (old_el == NULL && el->num_values == 0) {
1317                 if (LDB_FLAG_MOD_TYPE(el->flags) == LDB_FLAG_MOD_REPLACE) {
1318                         may_skip = true;
1319                 } else if (LDB_FLAG_MOD_TYPE(el->flags) == LDB_FLAG_MOD_DELETE) {
1320                         may_skip = true;
1321                 }
1322         } else if (a->linkID != 0 && LDB_FLAG_MOD_TYPE(el->flags) == LDB_FLAG_MOD_DELETE &&
1323                    ldb_request_get_control(req, DSDB_CONTROL_REPLMD_VANISH_LINKS) != NULL) {
1324                 /*
1325                  * We intentionally skip the version bump when attempting to
1326                  * vanish links.
1327                  *
1328                  * The control is set by dbcheck and expunge-tombstones which
1329                  * both attempt to be non-replicating. Otherwise, making an
1330                  * alteration to the replication state would trigger a
1331                  * broadcast of all expunged objects.
1332                  */
1333                 may_skip = true;
1334         }
1335
1336         if (el->flags & DSDB_FLAG_INTERNAL_FORCE_META_DATA) {
1337                 may_skip = false;
1338                 el->flags &= ~DSDB_FLAG_INTERNAL_FORCE_META_DATA;
1339         }
1340
1341         if (may_skip) {
1342                 if (strcmp(el->name, "interSiteTopologyGenerator") != 0 &&
1343                     !ldb_request_get_control(req, LDB_CONTROL_PROVISION_OID)) {
1344                         /*
1345                          * allow this to make it possible for dbcheck
1346                          * to rebuild broken metadata
1347                          */
1348                         return LDB_SUCCESS;
1349                 }
1350         }
1351
1352         for (i=0; i<omd->ctr.ctr1.count; i++) {
1353                 /*
1354                  * First check if we find it under the msDS-IntID,
1355                  * then check if we find it under the OID and
1356                  * prefixMap ID.
1357                  *
1358                  * This allows the administrator to simply re-write
1359                  * the attributes and so restore replication, which is
1360                  * likely what they will try to do.
1361                  */
1362                 if (attid == omd->ctr.ctr1.array[i].attid) {
1363                         break;
1364                 }
1365
1366                 if (a->attributeID_id == omd->ctr.ctr1.array[i].attid) {
1367                         break;
1368                 }
1369         }
1370
1371         if (a->linkID != 0 && dsdb_functional_level(ldb) > DS_DOMAIN_FUNCTION_2000) {
1372                 /* linked attributes are not stored in
1373                    replPropertyMetaData in FL above w2k, but we do
1374                    raise the seqnum for the object  */
1375                 if (*seq_num == 0 &&
1376                     ldb_sequence_number(ldb, LDB_SEQ_NEXT, seq_num) != LDB_SUCCESS) {
1377                         return LDB_ERR_OPERATIONS_ERROR;
1378                 }
1379                 return LDB_SUCCESS;
1380         }
1381
1382         if (i == omd->ctr.ctr1.count) {
1383                 /* we need to add a new one */
1384                 omd->ctr.ctr1.array = talloc_realloc(msg, omd->ctr.ctr1.array,
1385                                                      struct replPropertyMetaData1, omd->ctr.ctr1.count+1);
1386                 if (omd->ctr.ctr1.array == NULL) {
1387                         ldb_oom(ldb);
1388                         return LDB_ERR_OPERATIONS_ERROR;
1389                 }
1390                 omd->ctr.ctr1.count++;
1391                 ZERO_STRUCT(omd->ctr.ctr1.array[i]);
1392         }
1393
1394         /* Get a new sequence number from the backend. We only do this
1395          * if we have a change that requires a new
1396          * replPropertyMetaData element
1397          */
1398         if (*seq_num == 0) {
1399                 int ret = ldb_sequence_number(ldb, LDB_SEQ_NEXT, seq_num);
1400                 if (ret != LDB_SUCCESS) {
1401                         return LDB_ERR_OPERATIONS_ERROR;
1402                 }
1403         }
1404
1405         md1 = &omd->ctr.ctr1.array[i];
1406         md1->version++;
1407         md1->attid = attid;
1408         if (md1->attid == DRSUAPI_ATTID_isDeleted) {
1409                 const struct ldb_val *rdn_val = ldb_dn_get_rdn_val(msg->dn);
1410                 const char* rdn;
1411
1412                 if (rdn_val == NULL) {
1413                         ldb_oom(ldb);
1414                         return LDB_ERR_OPERATIONS_ERROR;
1415                 }
1416
1417                 rdn = (const char*)rdn_val->data;
1418                 if (strcmp(rdn, "Deleted Objects") == 0) {
1419                         /*
1420                          * Set the originating_change_time to 29/12/9999 at 23:59:59
1421                          * as specified in MS-ADTS 7.1.1.4.2 Deleted Objects Container
1422                          */
1423                         md1->originating_change_time    = DELETED_OBJECT_CONTAINER_CHANGE_TIME;
1424                 } else {
1425                         md1->originating_change_time    = now;
1426                 }
1427         } else {
1428                 md1->originating_change_time    = now;
1429         }
1430         md1->originating_invocation_id = *our_invocation_id;
1431         md1->originating_usn           = *seq_num;
1432         md1->local_usn                 = *seq_num;
1433
1434         return LDB_SUCCESS;
1435 }
1436
1437 /*
1438  * Bump the replPropertyMetaData version on an attribute, and if it
1439  * has changed (or forced by leaving rdn_old NULL), update the value
1440  * in the entry.
1441  *
1442  * This is important, as calling a modify operation may not change the
1443  * version number if the values appear unchanged, but a rename between
1444  * parents bumps this value.
1445  *
1446  */
1447 static int replmd_update_rpmd_rdn_attr(struct ldb_context *ldb,
1448                                        struct ldb_message *msg,
1449                                        const struct ldb_val *rdn_new,
1450                                        const struct ldb_val *rdn_old,
1451                                        struct replPropertyMetaDataBlob *omd,
1452                                        struct replmd_replicated_request *ar,
1453                                        NTTIME now,
1454                                        bool is_schema_nc)
1455 {
1456         const char *rdn_name = ldb_dn_get_rdn_name(msg->dn);
1457         const struct dsdb_attribute *rdn_attr =
1458                 dsdb_attribute_by_lDAPDisplayName(ar->schema, rdn_name);
1459         const char *attr_name = rdn_attr != NULL ?
1460                                 rdn_attr->lDAPDisplayName :
1461                                 rdn_name;
1462         struct ldb_message_element new_el = {
1463                 .flags = LDB_FLAG_MOD_REPLACE,
1464                 .name = attr_name,
1465                 .num_values = 1,
1466                 .values = discard_const_p(struct ldb_val, rdn_new)
1467         };
1468         struct ldb_message_element old_el = {
1469                 .flags = LDB_FLAG_MOD_REPLACE,
1470                 .name = attr_name,
1471                 .num_values = rdn_old ? 1 : 0,
1472                 .values = discard_const_p(struct ldb_val, rdn_old)
1473         };
1474
1475         if (ldb_msg_element_equal_ordered(&new_el, &old_el) == false) {
1476                 int ret = ldb_msg_add(msg, &new_el, LDB_FLAG_MOD_REPLACE);
1477                 if (ret != LDB_SUCCESS) {
1478                         return ldb_oom(ldb);
1479                 }
1480         }
1481
1482         return replmd_update_rpmd_element(ldb, msg, &new_el, NULL,
1483                                           omd, ar->schema, &ar->seq_num,
1484                                           &ar->our_invocation_id,
1485                                           now, is_schema_nc, ar->req);
1486
1487 }
1488
1489 static uint64_t find_max_local_usn(struct replPropertyMetaDataBlob omd)
1490 {
1491         uint32_t count = omd.ctr.ctr1.count;
1492         uint64_t max = 0;
1493         uint32_t i;
1494         for (i=0; i < count; i++) {
1495                 struct replPropertyMetaData1 m = omd.ctr.ctr1.array[i];
1496                 if (max < m.local_usn) {
1497                         max = m.local_usn;
1498                 }
1499         }
1500         return max;
1501 }
1502
1503 /*
1504  * update the replPropertyMetaData object each time we modify an
1505  * object. This is needed for DRS replication, as the merge on the
1506  * client is based on this object
1507  */
1508 static int replmd_update_rpmd(struct ldb_module *module,
1509                               const struct dsdb_schema *schema,
1510                               struct ldb_request *req,
1511                               const char * const *rename_attrs,
1512                               struct ldb_message *msg, uint64_t *seq_num,
1513                               time_t t, bool is_schema_nc,
1514                               bool *is_urgent, bool *rodc)
1515 {
1516         const struct ldb_val *omd_value;
1517         enum ndr_err_code ndr_err;
1518         struct replPropertyMetaDataBlob omd;
1519         unsigned int i;
1520         NTTIME now;
1521         const struct GUID *our_invocation_id;
1522         int ret;
1523         const char * const *attrs = NULL;
1524         const char * const attrs2[] = { "uSNChanged", "objectClass", "instanceType", NULL };
1525         struct ldb_result *res;
1526         struct ldb_context *ldb;
1527         struct ldb_message_element *objectclass_el;
1528         enum urgent_situation situation;
1529         bool rmd_is_provided;
1530         bool rmd_is_just_resorted = false;
1531         const char *not_rename_attrs[4 + msg->num_elements];
1532
1533         if (rename_attrs) {
1534                 attrs = rename_attrs;
1535         } else {
1536                 for (i = 0; i < msg->num_elements; i++) {
1537                         not_rename_attrs[i] = msg->elements[i].name;
1538                 }
1539                 not_rename_attrs[i] = "replPropertyMetaData";
1540                 not_rename_attrs[i+1] = "objectClass";
1541                 not_rename_attrs[i+2] = "instanceType";
1542                 not_rename_attrs[i+3] = NULL;
1543                 attrs = not_rename_attrs;
1544         }
1545
1546         ldb = ldb_module_get_ctx(module);
1547
1548         our_invocation_id = samdb_ntds_invocation_id(ldb);
1549         if (!our_invocation_id) {
1550                 /* this happens during an initial vampire while
1551                    updating the schema */
1552                 DEBUG(5,("No invocationID - skipping replPropertyMetaData update\n"));
1553                 return LDB_SUCCESS;
1554         }
1555
1556         unix_to_nt_time(&now, t);
1557
1558         if (ldb_request_get_control(req, DSDB_CONTROL_CHANGEREPLMETADATA_OID)) {
1559                 rmd_is_provided = true;
1560                 if (ldb_request_get_control(req, DSDB_CONTROL_CHANGEREPLMETADATA_RESORT_OID)) {
1561                         rmd_is_just_resorted = true;
1562                 }
1563         } else {
1564                 rmd_is_provided = false;
1565         }
1566
1567         /* if isDeleted is present and is TRUE, then we consider we are deleting,
1568          * otherwise we consider we are updating */
1569         if (ldb_msg_check_string_attribute(msg, "isDeleted", "TRUE")) {
1570                 situation = REPL_URGENT_ON_DELETE;
1571         } else if (rename_attrs) {
1572                 situation = REPL_URGENT_ON_CREATE | REPL_URGENT_ON_DELETE;
1573         } else {
1574                 situation = REPL_URGENT_ON_UPDATE;
1575         }
1576
1577         if (rmd_is_provided) {
1578                 /* In this case the change_replmetadata control was supplied */
1579                 /* We check that it's the only attribute that is provided
1580                  * (it's a rare case so it's better to keep the code simplier)
1581                  * We also check that the highest local_usn is bigger or the same as
1582                  * uSNChanged. */
1583                 uint64_t db_seq;
1584                 if( msg->num_elements != 1 ||
1585                         strncmp(msg->elements[0].name,
1586                                 "replPropertyMetaData", 20) ) {
1587                         DEBUG(0,(__location__ ": changereplmetada control called without "\
1588                                 "a specified replPropertyMetaData attribute or with others\n"));
1589                         return LDB_ERR_OPERATIONS_ERROR;
1590                 }
1591                 if (situation != REPL_URGENT_ON_UPDATE) {
1592                         DEBUG(0,(__location__ ": changereplmetada control can't be called when deleting an object\n"));
1593                         return LDB_ERR_OPERATIONS_ERROR;
1594                 }
1595                 omd_value = ldb_msg_find_ldb_val(msg, "replPropertyMetaData");
1596                 if (!omd_value) {
1597                         DEBUG(0,(__location__ ": replPropertyMetaData was not specified for Object %s\n",
1598                                  ldb_dn_get_linearized(msg->dn)));
1599                         return LDB_ERR_OPERATIONS_ERROR;
1600                 }
1601                 ndr_err = ndr_pull_struct_blob(omd_value, msg, &omd,
1602                                                (ndr_pull_flags_fn_t)ndr_pull_replPropertyMetaDataBlob);
1603                 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
1604                         DEBUG(0,(__location__ ": Failed to parse replPropertyMetaData for %s\n",
1605                                  ldb_dn_get_linearized(msg->dn)));
1606                         return LDB_ERR_OPERATIONS_ERROR;
1607                 }
1608
1609                 ret = dsdb_module_search_dn(module, msg, &res, msg->dn, attrs2,
1610                                             DSDB_FLAG_NEXT_MODULE |
1611                                             DSDB_SEARCH_SHOW_RECYCLED |
1612                                             DSDB_SEARCH_SHOW_EXTENDED_DN |
1613                                             DSDB_SEARCH_SHOW_DN_IN_STORAGE_FORMAT |
1614                                             DSDB_SEARCH_REVEAL_INTERNALS, req);
1615
1616                 if (ret != LDB_SUCCESS) {
1617                         return ret;
1618                 }
1619
1620                 if (rmd_is_just_resorted == false) {
1621                         *seq_num = find_max_local_usn(omd);
1622
1623                         db_seq = ldb_msg_find_attr_as_uint64(res->msgs[0], "uSNChanged", 0);
1624
1625                         /*
1626                          * The test here now allows for a new
1627                          * replPropertyMetaData with no change, if was
1628                          * just dbcheck re-sorting the values.
1629                          */
1630                         if (*seq_num <= db_seq) {
1631                                 DEBUG(0,(__location__ ": changereplmetada control provided but max(local_usn)" \
1632                                          " is less than uSNChanged (max = %lld uSNChanged = %lld)\n",
1633                                          (long long)*seq_num, (long long)db_seq));
1634                                 return LDB_ERR_OPERATIONS_ERROR;
1635                         }
1636                 }
1637
1638         } else {
1639                 /* search for the existing replPropertyMetaDataBlob. We need
1640                  * to use REVEAL and ask for DNs in storage format to support
1641                  * the check for values being the same in
1642                  * replmd_update_rpmd_element()
1643                  */
1644                 ret = dsdb_module_search_dn(module, msg, &res, msg->dn, attrs,
1645                                             DSDB_FLAG_NEXT_MODULE |
1646                                             DSDB_SEARCH_SHOW_RECYCLED |
1647                                             DSDB_SEARCH_SHOW_EXTENDED_DN |
1648                                             DSDB_SEARCH_SHOW_DN_IN_STORAGE_FORMAT |
1649                                             DSDB_SEARCH_REVEAL_INTERNALS, req);
1650                 if (ret != LDB_SUCCESS) {
1651                         return ret;
1652                 }
1653
1654                 omd_value = ldb_msg_find_ldb_val(res->msgs[0], "replPropertyMetaData");
1655                 if (!omd_value) {
1656                         DEBUG(0,(__location__ ": Object %s does not have a replPropertyMetaData attribute\n",
1657                                  ldb_dn_get_linearized(msg->dn)));
1658                         return LDB_ERR_OPERATIONS_ERROR;
1659                 }
1660
1661                 ndr_err = ndr_pull_struct_blob(omd_value, msg, &omd,
1662                                                (ndr_pull_flags_fn_t)ndr_pull_replPropertyMetaDataBlob);
1663                 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
1664                         DEBUG(0,(__location__ ": Failed to parse replPropertyMetaData for %s\n",
1665                                  ldb_dn_get_linearized(msg->dn)));
1666                         return LDB_ERR_OPERATIONS_ERROR;
1667                 }
1668
1669                 if (omd.version != 1) {
1670                         DEBUG(0,(__location__ ": bad version %u in replPropertyMetaData for %s\n",
1671                                  omd.version, ldb_dn_get_linearized(msg->dn)));
1672                         return LDB_ERR_OPERATIONS_ERROR;
1673                 }
1674
1675                 for (i=0; i<msg->num_elements;) {
1676                         struct ldb_message_element *el = &msg->elements[i];
1677                         struct ldb_message_element *old_el;
1678
1679                         old_el = ldb_msg_find_element(res->msgs[0], el->name);
1680                         ret = replmd_update_rpmd_element(ldb, msg, el, old_el,
1681                                                          &omd, schema, seq_num,
1682                                                          our_invocation_id,
1683                                                          now, is_schema_nc,
1684                                                          req);
1685                         if (ret != LDB_SUCCESS) {
1686                                 return ret;
1687                         }
1688
1689                         if (!*is_urgent && (situation == REPL_URGENT_ON_UPDATE)) {
1690                                 *is_urgent = replmd_check_urgent_attribute(el);
1691                         }
1692
1693                         if (!(el->flags & DSDB_FLAG_INTERNAL_FORCE_META_DATA)) {
1694                                 i++;
1695                                 continue;
1696                         }
1697
1698                         el->flags &= ~DSDB_FLAG_INTERNAL_FORCE_META_DATA;
1699
1700                         if (el->num_values != 0) {
1701                                 i++;
1702                                 continue;
1703                         }
1704
1705                         ldb_msg_remove_element(msg, el);
1706                 }
1707         }
1708
1709         /*
1710          * Assert that we have an objectClass attribute - this is major
1711          * corruption if we don't have this!
1712          */
1713         objectclass_el = ldb_msg_find_element(res->msgs[0], "objectClass");
1714         if (objectclass_el != NULL) {
1715                 /*
1716                  * Now check if this objectClass means we need to do urgent replication
1717                  */
1718                 if (!*is_urgent && replmd_check_urgent_objectclass(objectclass_el,
1719                                                                    situation)) {
1720                         *is_urgent = true;
1721                 }
1722         } else if (!ldb_request_get_control(req, DSDB_CONTROL_DBCHECK)) {
1723                 ldb_asprintf_errstring(ldb, __location__
1724                                        ": objectClass missing on %s\n",
1725                                        ldb_dn_get_linearized(msg->dn));
1726                 return LDB_ERR_OBJECT_CLASS_VIOLATION;
1727         }
1728
1729         /*
1730          * replmd_update_rpmd_element has done an update if the
1731          * seq_num is set
1732          */
1733         if (*seq_num != 0 || rmd_is_just_resorted == true) {
1734                 struct ldb_val *md_value;
1735                 struct ldb_message_element *el;
1736
1737                 /*if we are RODC and this is a DRSR update then its ok*/
1738                 if (!ldb_request_get_control(req, DSDB_CONTROL_REPLICATED_UPDATE_OID)
1739                     && !ldb_request_get_control(req, DSDB_CONTROL_DBCHECK_MODIFY_RO_REPLICA)) {
1740                         unsigned instanceType;
1741
1742                         ret = samdb_rodc(ldb, rodc);
1743                         if (ret != LDB_SUCCESS) {
1744                                 DEBUG(4, (__location__ ": unable to tell if we are an RODC\n"));
1745                         } else if (*rodc) {
1746                                 ldb_set_errstring(ldb, "RODC modify is forbidden!");
1747                                 return LDB_ERR_REFERRAL;
1748                         }
1749
1750                         instanceType = ldb_msg_find_attr_as_uint(res->msgs[0], "instanceType", INSTANCE_TYPE_WRITE);
1751                         if (!(instanceType & INSTANCE_TYPE_WRITE)) {
1752                                 return ldb_error(ldb, LDB_ERR_UNWILLING_TO_PERFORM,
1753                                                  "cannot change replicated attribute on partial replica");
1754                         }
1755                 }
1756
1757                 md_value = talloc(msg, struct ldb_val);
1758                 if (md_value == NULL) {
1759                         ldb_oom(ldb);
1760                         return LDB_ERR_OPERATIONS_ERROR;
1761                 }
1762
1763                 ret = replmd_replPropertyMetaDataCtr1_sort_and_verify(ldb, &omd.ctr.ctr1, msg->dn);
1764                 if (ret != LDB_SUCCESS) {
1765                         ldb_asprintf_errstring(ldb, "%s: %s", __func__, ldb_errstring(ldb));
1766                         return ret;
1767                 }
1768
1769                 ndr_err = ndr_push_struct_blob(md_value, msg, &omd,
1770                                                (ndr_push_flags_fn_t)ndr_push_replPropertyMetaDataBlob);
1771                 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
1772                         DEBUG(0,(__location__ ": Failed to marshall replPropertyMetaData for %s\n",
1773                                  ldb_dn_get_linearized(msg->dn)));
1774                         return LDB_ERR_OPERATIONS_ERROR;
1775                 }
1776
1777                 ret = ldb_msg_add_empty(msg, "replPropertyMetaData", LDB_FLAG_MOD_REPLACE, &el);
1778                 if (ret != LDB_SUCCESS) {
1779                         DEBUG(0,(__location__ ": Failed to add updated replPropertyMetaData %s\n",
1780                                  ldb_dn_get_linearized(msg->dn)));
1781                         return ret;
1782                 }
1783
1784                 el->num_values = 1;
1785                 el->values = md_value;
1786         }
1787
1788         return LDB_SUCCESS;
1789 }
1790
1791 struct parsed_dn {
1792         struct dsdb_dn *dsdb_dn;
1793         struct GUID guid;
1794         struct ldb_val *v;
1795 };
1796
1797 static int parsed_dn_compare(struct parsed_dn *pdn1, struct parsed_dn *pdn2)
1798 {
1799         return GUID_compare(&pdn1->guid, &pdn2->guid);
1800 }
1801
1802 static int GUID_compare_struct(struct GUID *g1, struct GUID g2)
1803 {
1804         return GUID_compare(g1, &g2);
1805 }
1806
1807 static struct parsed_dn *parsed_dn_find(struct parsed_dn *pdn,
1808                                         unsigned int count, struct GUID *guid,
1809                                         struct ldb_dn *dn)
1810 {
1811         struct parsed_dn *ret;
1812         unsigned int i;
1813         if (dn && GUID_all_zero(guid)) {
1814                 /* when updating a link using DRS, we sometimes get a
1815                    NULL GUID. We then need to try and match by DN */
1816                 for (i=0; i<count; i++) {
1817                         if (ldb_dn_compare(pdn[i].dsdb_dn->dn, dn) == 0) {
1818                                 dsdb_get_extended_dn_guid(pdn[i].dsdb_dn->dn, guid, "GUID");
1819                                 return &pdn[i];
1820                         }
1821                 }
1822                 return NULL;
1823         }
1824         BINARY_ARRAY_SEARCH(pdn, count, guid, guid, GUID_compare_struct, ret);
1825         return ret;
1826 }
1827
1828 /*
1829   get a series of message element values as an array of DNs and GUIDs
1830   the result is sorted by GUID
1831  */
1832 static int get_parsed_dns(struct ldb_module *module, TALLOC_CTX *mem_ctx,
1833                           struct ldb_message_element *el, struct parsed_dn **pdn,
1834                           const char *ldap_oid, struct ldb_request *parent)
1835 {
1836         unsigned int i;
1837         bool values_are_sorted = true;
1838         struct ldb_context *ldb = ldb_module_get_ctx(module);
1839
1840         if (el == NULL) {
1841                 *pdn = NULL;
1842                 return LDB_SUCCESS;
1843         }
1844
1845         (*pdn) = talloc_array(mem_ctx, struct parsed_dn, el->num_values);
1846         if (!*pdn) {
1847                 ldb_module_oom(module);
1848                 return LDB_ERR_OPERATIONS_ERROR;
1849         }
1850
1851         for (i=0; i<el->num_values; i++) {
1852                 struct ldb_val *v = &el->values[i];
1853                 NTSTATUS status;
1854                 struct ldb_dn *dn;
1855                 struct parsed_dn *p;
1856
1857                 p = &(*pdn)[i];
1858
1859                 p->dsdb_dn = dsdb_dn_parse(*pdn, ldb, v, ldap_oid);
1860                 if (p->dsdb_dn == NULL) {
1861                         return LDB_ERR_INVALID_DN_SYNTAX;
1862                 }
1863
1864                 dn = p->dsdb_dn->dn;
1865
1866                 status = dsdb_get_extended_dn_guid(dn, &p->guid, "GUID");
1867                 if (NT_STATUS_EQUAL(status, NT_STATUS_OBJECT_NAME_NOT_FOUND)) {
1868                         /* we got a DN without a GUID - go find the GUID */
1869                         int ret = dsdb_module_guid_by_dn(module, dn, &p->guid, parent);
1870                         if (ret != LDB_SUCCESS) {
1871                                 ldb_asprintf_errstring(ldb, "Unable to find GUID for DN %s\n",
1872                                                        ldb_dn_get_linearized(dn));
1873                                 if (ret == LDB_ERR_NO_SUCH_OBJECT &&
1874                                     LDB_FLAG_MOD_TYPE(el->flags) == LDB_FLAG_MOD_DELETE &&
1875                                     ldb_attr_cmp(el->name, "member") == 0) {
1876                                         return LDB_ERR_UNWILLING_TO_PERFORM;
1877                                 }
1878                                 return ret;
1879                         }
1880                         ret = dsdb_set_extended_dn_guid(dn, &p->guid, "GUID");
1881                         if (ret != LDB_SUCCESS) {
1882                                 return ret;
1883                         }
1884                 } else if (!NT_STATUS_IS_OK(status)) {
1885                         return LDB_ERR_OPERATIONS_ERROR;
1886                 }
1887                 if (i > 0 && values_are_sorted) {
1888                         int cmp = parsed_dn_compare(p, &(*pdn)[i - 1]);
1889                         if (cmp < 0) {
1890                                 values_are_sorted = false;
1891                         }
1892                 }
1893                 /* keep a pointer to the original ldb_val */
1894                 p->v = v;
1895         }
1896         if (! values_are_sorted) {
1897                 TYPESAFE_QSORT(*pdn, el->num_values, parsed_dn_compare);
1898         }
1899         return LDB_SUCCESS;
1900 }
1901
1902 /*
1903   build a new extended DN, including all meta data fields
1904
1905   RMD_FLAGS           = DSDB_RMD_FLAG_* bits
1906   RMD_ADDTIME         = originating_add_time
1907   RMD_INVOCID         = originating_invocation_id
1908   RMD_CHANGETIME      = originating_change_time
1909   RMD_ORIGINATING_USN = originating_usn
1910   RMD_LOCAL_USN       = local_usn
1911   RMD_VERSION         = version
1912  */
1913 static int replmd_build_la_val(TALLOC_CTX *mem_ctx, struct ldb_val *v, struct dsdb_dn *dsdb_dn,
1914                                const struct GUID *invocation_id, uint64_t seq_num,
1915                                uint64_t local_usn, NTTIME nttime, uint32_t version, bool deleted)
1916 {
1917         struct ldb_dn *dn = dsdb_dn->dn;
1918         const char *tstring, *usn_string, *flags_string;
1919         struct ldb_val tval;
1920         struct ldb_val iid;
1921         struct ldb_val usnv, local_usnv;
1922         struct ldb_val vers, flagsv;
1923         NTSTATUS status;
1924         int ret;
1925         const char *dnstring;
1926         char *vstring;
1927         uint32_t rmd_flags = deleted?DSDB_RMD_FLAG_DELETED:0;
1928
1929         tstring = talloc_asprintf(mem_ctx, "%llu", (unsigned long long)nttime);
1930         if (!tstring) {
1931                 return LDB_ERR_OPERATIONS_ERROR;
1932         }
1933         tval = data_blob_string_const(tstring);
1934
1935         usn_string = talloc_asprintf(mem_ctx, "%llu", (unsigned long long)seq_num);
1936         if (!usn_string) {
1937                 return LDB_ERR_OPERATIONS_ERROR;
1938         }
1939         usnv = data_blob_string_const(usn_string);
1940
1941         usn_string = talloc_asprintf(mem_ctx, "%llu", (unsigned long long)local_usn);
1942         if (!usn_string) {
1943                 return LDB_ERR_OPERATIONS_ERROR;
1944         }
1945         local_usnv = data_blob_string_const(usn_string);
1946
1947         vstring = talloc_asprintf(mem_ctx, "%lu", (unsigned long)version);
1948         if (!vstring) {
1949                 return LDB_ERR_OPERATIONS_ERROR;
1950         }
1951         vers = data_blob_string_const(vstring);
1952
1953         status = GUID_to_ndr_blob(invocation_id, dn, &iid);
1954         if (!NT_STATUS_IS_OK(status)) {
1955                 return LDB_ERR_OPERATIONS_ERROR;
1956         }
1957
1958         flags_string = talloc_asprintf(mem_ctx, "%u", rmd_flags);
1959         if (!flags_string) {
1960                 return LDB_ERR_OPERATIONS_ERROR;
1961         }
1962         flagsv = data_blob_string_const(flags_string);
1963
1964         ret = ldb_dn_set_extended_component(dn, "RMD_FLAGS", &flagsv);
1965         if (ret != LDB_SUCCESS) return ret;
1966         ret = ldb_dn_set_extended_component(dn, "RMD_ADDTIME", &tval);
1967         if (ret != LDB_SUCCESS) return ret;
1968         ret = ldb_dn_set_extended_component(dn, "RMD_INVOCID", &iid);
1969         if (ret != LDB_SUCCESS) return ret;
1970         ret = ldb_dn_set_extended_component(dn, "RMD_CHANGETIME", &tval);
1971         if (ret != LDB_SUCCESS) return ret;
1972         ret = ldb_dn_set_extended_component(dn, "RMD_LOCAL_USN", &local_usnv);
1973         if (ret != LDB_SUCCESS) return ret;
1974         ret = ldb_dn_set_extended_component(dn, "RMD_ORIGINATING_USN", &usnv);
1975         if (ret != LDB_SUCCESS) return ret;
1976         ret = ldb_dn_set_extended_component(dn, "RMD_VERSION", &vers);
1977         if (ret != LDB_SUCCESS) return ret;
1978
1979         dnstring = dsdb_dn_get_extended_linearized(mem_ctx, dsdb_dn, 1);
1980         if (dnstring == NULL) {
1981                 return LDB_ERR_OPERATIONS_ERROR;
1982         }
1983         *v = data_blob_string_const(dnstring);
1984
1985         return LDB_SUCCESS;
1986 }
1987
1988 static int replmd_update_la_val(TALLOC_CTX *mem_ctx, struct ldb_val *v, struct dsdb_dn *dsdb_dn,
1989                                 struct dsdb_dn *old_dsdb_dn, const struct GUID *invocation_id,
1990                                 uint64_t seq_num, uint64_t local_usn, NTTIME nttime,
1991                                 uint32_t version, bool deleted);
1992
1993 /*
1994   check if any links need upgrading from w2k format
1995  */
1996 static int replmd_check_upgrade_links(struct parsed_dn *dns, uint32_t count,
1997                                       struct ldb_message_element *el,
1998                                       const struct GUID *invocation_id)
1999 {
2000         uint32_t i;
2001         for (i=0; i<count; i++) {
2002                 NTSTATUS status;
2003                 uint32_t version;
2004                 int ret;
2005
2006                 status = dsdb_get_extended_dn_uint32(dns[i].dsdb_dn->dn,
2007                                                      &version, "RMD_VERSION");
2008                 if (!NT_STATUS_EQUAL(status, NT_STATUS_OBJECT_NAME_NOT_FOUND)) {
2009                         /*
2010                          *  We optimistically assume they are all the same; if
2011                          *  the first one is fixed, they are all fixed.
2012                          *
2013                          *  If the first one was *not* fixed and we find a
2014                          *  later one that is, that is an occasion to shout
2015                          *  with DEBUG(0).
2016                          */
2017                         if (i == 0) {
2018                                 return LDB_SUCCESS;
2019                         }
2020                         DEBUG(0, ("Mixed w2k and fixed format "
2021                                   "linked attributes\n"));
2022                         continue;
2023                 }
2024
2025                 /* it's an old one that needs upgrading */
2026                 ret = replmd_update_la_val(el->values, dns[i].v,
2027                                            dns[i].dsdb_dn, dns[i].dsdb_dn,
2028                                            invocation_id, 1, 1, 0, 0, false);
2029                 if (ret != LDB_SUCCESS) {
2030                         return ret;
2031                 }
2032         }
2033         return LDB_SUCCESS;
2034 }
2035
2036 /*
2037   update an extended DN, including all meta data fields
2038
2039   see replmd_build_la_val for value names
2040  */
2041 static int replmd_update_la_val(TALLOC_CTX *mem_ctx, struct ldb_val *v, struct dsdb_dn *dsdb_dn,
2042                                 struct dsdb_dn *old_dsdb_dn, const struct GUID *invocation_id,
2043                                 uint64_t usn, uint64_t local_usn, NTTIME nttime,
2044                                 uint32_t version, bool deleted)
2045 {
2046         struct ldb_dn *dn = dsdb_dn->dn;
2047         const char *tstring, *usn_string, *flags_string;
2048         struct ldb_val tval;
2049         struct ldb_val iid;
2050         struct ldb_val usnv, local_usnv;
2051         struct ldb_val vers, flagsv;
2052         const struct ldb_val *old_addtime;
2053         uint32_t old_version;
2054         NTSTATUS status;
2055         int ret;
2056         const char *dnstring;
2057         char *vstring;
2058         uint32_t rmd_flags = deleted?DSDB_RMD_FLAG_DELETED:0;
2059
2060         tstring = talloc_asprintf(mem_ctx, "%llu", (unsigned long long)nttime);
2061         if (!tstring) {
2062                 return LDB_ERR_OPERATIONS_ERROR;
2063         }
2064         tval = data_blob_string_const(tstring);
2065
2066         usn_string = talloc_asprintf(mem_ctx, "%llu", (unsigned long long)usn);
2067         if (!usn_string) {
2068                 return LDB_ERR_OPERATIONS_ERROR;
2069         }
2070         usnv = data_blob_string_const(usn_string);
2071
2072         usn_string = talloc_asprintf(mem_ctx, "%llu", (unsigned long long)local_usn);
2073         if (!usn_string) {
2074                 return LDB_ERR_OPERATIONS_ERROR;
2075         }
2076         local_usnv = data_blob_string_const(usn_string);
2077
2078         status = GUID_to_ndr_blob(invocation_id, dn, &iid);
2079         if (!NT_STATUS_IS_OK(status)) {
2080                 return LDB_ERR_OPERATIONS_ERROR;
2081         }
2082
2083         flags_string = talloc_asprintf(mem_ctx, "%u", rmd_flags);
2084         if (!flags_string) {
2085                 return LDB_ERR_OPERATIONS_ERROR;
2086         }
2087         flagsv = data_blob_string_const(flags_string);
2088
2089         ret = ldb_dn_set_extended_component(dn, "RMD_FLAGS", &flagsv);
2090         if (ret != LDB_SUCCESS) return ret;
2091
2092         /* get the ADDTIME from the original */
2093         old_addtime = ldb_dn_get_extended_component(old_dsdb_dn->dn, "RMD_ADDTIME");
2094         if (old_addtime == NULL) {
2095                 old_addtime = &tval;
2096         }
2097         if (dsdb_dn != old_dsdb_dn ||
2098             ldb_dn_get_extended_component(dn, "RMD_ADDTIME") == NULL) {
2099                 ret = ldb_dn_set_extended_component(dn, "RMD_ADDTIME", old_addtime);
2100                 if (ret != LDB_SUCCESS) return ret;
2101         }
2102
2103         /* use our invocation id */
2104         ret = ldb_dn_set_extended_component(dn, "RMD_INVOCID", &iid);
2105         if (ret != LDB_SUCCESS) return ret;
2106
2107         /* changetime is the current time */
2108         ret = ldb_dn_set_extended_component(dn, "RMD_CHANGETIME", &tval);
2109         if (ret != LDB_SUCCESS) return ret;
2110
2111         /* update the USN */
2112         ret = ldb_dn_set_extended_component(dn, "RMD_ORIGINATING_USN", &usnv);
2113         if (ret != LDB_SUCCESS) return ret;
2114
2115         ret = ldb_dn_set_extended_component(dn, "RMD_LOCAL_USN", &local_usnv);
2116         if (ret != LDB_SUCCESS) return ret;
2117
2118         /* increase the version by 1 */
2119         status = dsdb_get_extended_dn_uint32(old_dsdb_dn->dn, &old_version, "RMD_VERSION");
2120         if (NT_STATUS_IS_OK(status) && old_version >= version) {
2121                 version = old_version+1;
2122         }
2123         vstring = talloc_asprintf(dn, "%lu", (unsigned long)version);
2124         vers = data_blob_string_const(vstring);
2125         ret = ldb_dn_set_extended_component(dn, "RMD_VERSION", &vers);
2126         if (ret != LDB_SUCCESS) return ret;
2127
2128         dnstring = dsdb_dn_get_extended_linearized(mem_ctx, dsdb_dn, 1);
2129         if (dnstring == NULL) {
2130                 return LDB_ERR_OPERATIONS_ERROR;
2131         }
2132         *v = data_blob_string_const(dnstring);
2133
2134         return LDB_SUCCESS;
2135 }
2136
2137 /*
2138   handle adding a linked attribute
2139  */
2140 static int replmd_modify_la_add(struct ldb_module *module,
2141                                 struct replmd_private *replmd_private,
2142                                 const struct dsdb_schema *schema,
2143                                 struct ldb_message *msg,
2144                                 struct ldb_message_element *el,
2145                                 struct ldb_message_element *old_el,
2146                                 const struct dsdb_attribute *schema_attr,
2147                                 uint64_t seq_num,
2148                                 time_t t,
2149                                 struct GUID *msg_guid,
2150                                 struct ldb_request *parent)
2151 {
2152         unsigned int i;
2153         struct parsed_dn *dns, *old_dns;
2154         TALLOC_CTX *tmp_ctx = talloc_new(msg);
2155         int ret;
2156         struct ldb_val *new_values = NULL;
2157         unsigned int num_new_values = 0;
2158         unsigned old_num_values = old_el?old_el->num_values:0;
2159         const struct GUID *invocation_id;
2160         struct ldb_context *ldb = ldb_module_get_ctx(module);
2161         NTTIME now;
2162
2163         unix_to_nt_time(&now, t);
2164
2165         ret = get_parsed_dns(module, tmp_ctx, el, &dns, schema_attr->syntax->ldap_oid, parent);
2166         if (ret != LDB_SUCCESS) {
2167                 talloc_free(tmp_ctx);
2168                 return ret;
2169         }
2170
2171         ret = get_parsed_dns(module, tmp_ctx, old_el, &old_dns, schema_attr->syntax->ldap_oid, parent);
2172         if (ret != LDB_SUCCESS) {
2173                 talloc_free(tmp_ctx);
2174                 return ret;
2175         }
2176
2177         invocation_id = samdb_ntds_invocation_id(ldb);
2178         if (!invocation_id) {
2179                 talloc_free(tmp_ctx);
2180                 return LDB_ERR_OPERATIONS_ERROR;
2181         }
2182
2183         ret = replmd_check_upgrade_links(old_dns, old_num_values, old_el, invocation_id);
2184         if (ret != LDB_SUCCESS) {
2185                 talloc_free(tmp_ctx);
2186                 return ret;
2187         }
2188
2189         /* for each new value, see if it exists already with the same GUID */
2190         for (i=0; i<el->num_values; i++) {
2191                 struct parsed_dn *p = parsed_dn_find(old_dns, old_num_values, &dns[i].guid, NULL);
2192                 if (p == NULL) {
2193                         /* this is a new linked attribute value */
2194                         new_values = talloc_realloc(tmp_ctx, new_values, struct ldb_val, num_new_values+1);
2195                         if (new_values == NULL) {
2196                                 ldb_module_oom(module);
2197                                 talloc_free(tmp_ctx);
2198                                 return LDB_ERR_OPERATIONS_ERROR;
2199                         }
2200                         ret = replmd_build_la_val(new_values, &new_values[num_new_values], dns[i].dsdb_dn,
2201                                                   invocation_id, seq_num, seq_num, now, 0, false);
2202                         if (ret != LDB_SUCCESS) {
2203                                 talloc_free(tmp_ctx);
2204                                 return ret;
2205                         }
2206                         num_new_values++;
2207                 } else {
2208                         /* this is only allowed if the GUID was
2209                            previously deleted. */
2210                         uint32_t rmd_flags = dsdb_dn_rmd_flags(p->dsdb_dn->dn);
2211
2212                         if (!(rmd_flags & DSDB_RMD_FLAG_DELETED)) {
2213                                 struct GUID_txt_buf guid_str;
2214                                 ldb_asprintf_errstring(ldb, "Attribute %s already exists for target GUID %s",
2215                                                        el->name, GUID_buf_string(&p->guid, &guid_str));
2216                                 talloc_free(tmp_ctx);
2217                                 /* error codes for 'member' need to be
2218                                    special cased */
2219                                 if (ldb_attr_cmp(el->name, "member") == 0) {
2220                                         return LDB_ERR_ENTRY_ALREADY_EXISTS;
2221                                 } else {
2222                                         return LDB_ERR_ATTRIBUTE_OR_VALUE_EXISTS;
2223                                 }
2224                         }
2225                         ret = replmd_update_la_val(old_el->values, p->v, dns[i].dsdb_dn, p->dsdb_dn,
2226                                                    invocation_id, seq_num, seq_num, now, 0, false);
2227                         if (ret != LDB_SUCCESS) {
2228                                 talloc_free(tmp_ctx);
2229                                 return ret;
2230                         }
2231                 }
2232
2233                 ret = replmd_add_backlink(module, replmd_private,
2234                                           schema, msg_guid, &dns[i].guid,
2235                                           true, schema_attr, true);
2236                 if (ret != LDB_SUCCESS) {
2237                         talloc_free(tmp_ctx);
2238                         return ret;
2239                 }
2240         }
2241
2242         /* add the new ones on to the end of the old values, constructing a new el->values */
2243         el->values = talloc_realloc(msg->elements, old_el?old_el->values:NULL,
2244                                     struct ldb_val,
2245                                     old_num_values+num_new_values);
2246         if (el->values == NULL) {
2247                 ldb_module_oom(module);
2248                 return LDB_ERR_OPERATIONS_ERROR;
2249         }
2250
2251         memcpy(&el->values[old_num_values], new_values, num_new_values*sizeof(struct ldb_val));
2252         el->num_values = old_num_values + num_new_values;
2253
2254         talloc_steal(msg->elements, el->values);
2255         talloc_steal(el->values, new_values);
2256
2257         talloc_free(tmp_ctx);
2258
2259         /* we now tell the backend to replace all existing values
2260            with the one we have constructed */
2261         el->flags = LDB_FLAG_MOD_REPLACE;
2262
2263         return LDB_SUCCESS;
2264 }
2265
2266
2267 /*
2268   handle deleting all active linked attributes
2269  */
2270 static int replmd_modify_la_delete(struct ldb_module *module,
2271                                    struct replmd_private *replmd_private,
2272                                    const struct dsdb_schema *schema,
2273                                    struct ldb_message *msg,
2274                                    struct ldb_message_element *el,
2275                                    struct ldb_message_element *old_el,
2276                                    const struct dsdb_attribute *schema_attr,
2277                                    uint64_t seq_num,
2278                                    time_t t,
2279                                    struct GUID *msg_guid,
2280                                    struct ldb_request *parent)
2281 {
2282         unsigned int i;
2283         struct parsed_dn *dns, *old_dns;
2284         TALLOC_CTX *tmp_ctx = NULL;
2285         int ret;
2286         const struct GUID *invocation_id;
2287         struct ldb_context *ldb = ldb_module_get_ctx(module);
2288         struct ldb_control *vanish_links_ctrl = NULL;
2289         bool vanish_links = false;
2290         unsigned int num_to_delete = el->num_values;
2291         NTTIME now;
2292
2293         unix_to_nt_time(&now, t);
2294
2295         /* check if there is nothing to delete */
2296         if ((!old_el || old_el->num_values == 0) &&
2297             el->num_values == 0) {
2298                 return LDB_SUCCESS;
2299         }
2300
2301         if (!old_el || old_el->num_values == 0) {
2302                 return LDB_ERR_NO_SUCH_ATTRIBUTE;
2303         }
2304
2305         tmp_ctx = talloc_new(msg);
2306         if (tmp_ctx == NULL) {
2307                 return LDB_ERR_OPERATIONS_ERROR;
2308         }
2309
2310         ret = get_parsed_dns(module, tmp_ctx, el, &dns, schema_attr->syntax->ldap_oid, parent);
2311         if (ret != LDB_SUCCESS) {
2312                 talloc_free(tmp_ctx);
2313                 return ret;
2314         }
2315
2316         ret = get_parsed_dns(module, tmp_ctx, old_el, &old_dns, schema_attr->syntax->ldap_oid, parent);
2317         if (ret != LDB_SUCCESS) {
2318                 talloc_free(tmp_ctx);
2319                 return ret;
2320         }
2321
2322         invocation_id = samdb_ntds_invocation_id(ldb);
2323         if (!invocation_id) {
2324                 talloc_free(tmp_ctx);
2325                 return LDB_ERR_OPERATIONS_ERROR;
2326         }
2327
2328         ret = replmd_check_upgrade_links(old_dns, old_el->num_values, old_el, invocation_id);
2329         if (ret != LDB_SUCCESS) {
2330                 talloc_free(tmp_ctx);
2331                 return ret;
2332         }
2333
2334         if (parent) {
2335                 vanish_links_ctrl = ldb_request_get_control(parent, DSDB_CONTROL_REPLMD_VANISH_LINKS);
2336                 if (vanish_links_ctrl) {
2337                         vanish_links = true;
2338                         vanish_links_ctrl->critical = false;
2339                 }
2340         }
2341
2342         el->num_values = 0;
2343         el->values = NULL;
2344
2345         /* see if we are being asked to delete any links that
2346            don't exist or are already deleted */
2347         for (i=0; i < num_to_delete; i++) {
2348                 struct parsed_dn *p = &dns[i];
2349                 struct parsed_dn *p2;
2350                 uint32_t rmd_flags;
2351
2352                 p2 = parsed_dn_find(old_dns, old_el->num_values, &p->guid, NULL);
2353                 if (!p2) {
2354                         struct GUID_txt_buf buf;
2355                         ldb_asprintf_errstring(ldb, "Attribute %s doesn't exist for target GUID %s",
2356                                                el->name, GUID_buf_string(&p->guid, &buf));
2357                         if (ldb_attr_cmp(el->name, "member") == 0) {
2358                                 talloc_free(tmp_ctx);
2359                                 return LDB_ERR_UNWILLING_TO_PERFORM;
2360                         } else {
2361                                 talloc_free(tmp_ctx);
2362                                 return LDB_ERR_NO_SUCH_ATTRIBUTE;
2363                         }
2364                 }
2365                 rmd_flags = dsdb_dn_rmd_flags(p2->dsdb_dn->dn);
2366                 if (rmd_flags & DSDB_RMD_FLAG_DELETED) {
2367                         struct GUID_txt_buf buf;
2368                         const char *guid_str = GUID_buf_string(&p->guid, &buf);
2369                         if (vanish_links) {
2370                                 DEBUG(0, ("Deleting deleted linked attribute %s to %s, "
2371                                           "because vanish_links control is set\n",
2372                                           el->name, guid_str));
2373                                 continue;
2374                         }
2375                         ldb_asprintf_errstring(ldb, "Attribute %s already deleted for target GUID %s",
2376                                                el->name, guid_str);
2377                         if (ldb_attr_cmp(el->name, "member") == 0) {
2378                                 talloc_free(tmp_ctx);
2379                                 return LDB_ERR_UNWILLING_TO_PERFORM;
2380                         } else {
2381                                 talloc_free(tmp_ctx);
2382                                 return LDB_ERR_NO_SUCH_ATTRIBUTE;
2383                         }
2384                 }
2385         }
2386
2387         if (vanish_links) {
2388                 if (num_to_delete == old_el->num_values || num_to_delete == 0) {
2389                         el->flags = LDB_FLAG_MOD_REPLACE;
2390
2391                         for (i = 0; i < old_el->num_values; i++) {
2392                                 ret = replmd_add_backlink(module,
2393                                                           replmd_private,
2394                                                           schema, msg_guid,
2395                                                           &old_dns[i].guid,
2396                                                           false, schema_attr,
2397                                                           true);
2398                                 if (ret != LDB_SUCCESS) {
2399                                         talloc_free(tmp_ctx);
2400                                         return ret;
2401                                 }
2402                         }
2403                         talloc_free(tmp_ctx);
2404                         return LDB_SUCCESS;
2405                 } else {
2406                         unsigned int num_values = 0;
2407                         unsigned int j = 0;
2408                         for (i = 0; i < old_el->num_values; i++) {
2409                                 if (parsed_dn_find(dns, num_to_delete, &old_dns[i].guid, NULL) != NULL) {
2410                                         /* The element is in the delete list.
2411                                            mark it dead. */
2412                                         ret = replmd_add_backlink(module,
2413                                                                   replmd_private,
2414                                                                   schema,
2415                                                                   msg_guid,
2416                                                                   &old_dns[i].guid,
2417                                                                   false,
2418                                                                   schema_attr,
2419                                                                   true);
2420                                         if (ret != LDB_SUCCESS) {
2421                                                 talloc_free(tmp_ctx);
2422                                                 return ret;
2423                                         }
2424                                         old_dns[i].v->length = 0;
2425                                 } else {
2426                                         num_values++;
2427                                 }
2428                         }
2429                         for (i = 0; i < old_el->num_values; i++) {
2430                                 if (old_el->values[i].length != 0) {
2431                                         old_el->values[j] = old_el->values[i];
2432                                         j++;
2433                                         if (j == num_values) {
2434                                                 break;
2435                                         }
2436                                 }
2437                         }
2438                         old_el->num_values = num_values;
2439                 }
2440         } else {
2441
2442                 /* for each new value, see if it exists already with the same GUID
2443                    if it is not already deleted and matches the delete list then delete it
2444                 */
2445                 for (i=0; i<old_el->num_values; i++) {
2446                         struct parsed_dn *p = &old_dns[i];
2447                         uint32_t rmd_flags;
2448
2449                         if (num_to_delete && parsed_dn_find(dns, num_to_delete, &p->guid, NULL) == NULL) {
2450                                 continue;
2451                         }
2452
2453                         rmd_flags = dsdb_dn_rmd_flags(p->dsdb_dn->dn);
2454                         if (rmd_flags & DSDB_RMD_FLAG_DELETED) continue;
2455
2456                         ret = replmd_update_la_val(old_el->values, p->v, p->dsdb_dn, p->dsdb_dn,
2457                                                    invocation_id, seq_num, seq_num, now, 0, true);
2458                         if (ret != LDB_SUCCESS) {
2459                                 talloc_free(tmp_ctx);
2460                                 return ret;
2461                         }
2462                         ret = replmd_add_backlink(module, replmd_private,
2463                                                   schema, msg_guid, &p->guid,
2464                                                   false, schema_attr, true);
2465                         if (ret != LDB_SUCCESS) {
2466                                 talloc_free(tmp_ctx);
2467                                 return ret;
2468                         }
2469                 }
2470         }
2471         el->values = talloc_steal(msg->elements, old_el->values);
2472         el->num_values = old_el->num_values;
2473
2474         talloc_free(tmp_ctx);
2475
2476         /* we now tell the backend to replace all existing values
2477            with the one we have constructed */
2478         el->flags = LDB_FLAG_MOD_REPLACE;
2479
2480         return LDB_SUCCESS;
2481 }
2482
2483 /*
2484   handle replacing a linked attribute
2485  */
2486 static int replmd_modify_la_replace(struct ldb_module *module,
2487                                     struct replmd_private *replmd_private,
2488                                     const struct dsdb_schema *schema,
2489                                     struct ldb_message *msg,
2490                                     struct ldb_message_element *el,
2491                                     struct ldb_message_element *old_el,
2492                                     const struct dsdb_attribute *schema_attr,
2493                                     uint64_t seq_num,
2494                                     time_t t,
2495                                     struct GUID *msg_guid,
2496                                     struct ldb_request *parent)
2497 {
2498         unsigned int i;
2499         struct parsed_dn *dns, *old_dns;
2500         TALLOC_CTX *tmp_ctx = talloc_new(msg);
2501         int ret;
2502         const struct GUID *invocation_id;
2503         struct ldb_context *ldb = ldb_module_get_ctx(module);
2504         struct ldb_val *new_values = NULL;
2505         unsigned int num_new_values = 0;
2506         unsigned int old_num_values = old_el?old_el->num_values:0;
2507         NTTIME now;
2508
2509         unix_to_nt_time(&now, t);
2510
2511         /* check if there is nothing to replace */
2512         if ((!old_el || old_el->num_values == 0) &&
2513             el->num_values == 0) {
2514                 return LDB_SUCCESS;
2515         }
2516
2517         ret = get_parsed_dns(module, tmp_ctx, el, &dns, schema_attr->syntax->ldap_oid, parent);
2518         if (ret != LDB_SUCCESS) {
2519                 talloc_free(tmp_ctx);
2520                 return ret;
2521         }
2522
2523         ret = get_parsed_dns(module, tmp_ctx, old_el, &old_dns, schema_attr->syntax->ldap_oid, parent);
2524         if (ret != LDB_SUCCESS) {
2525                 talloc_free(tmp_ctx);
2526                 return ret;
2527         }
2528
2529         invocation_id = samdb_ntds_invocation_id(ldb);
2530         if (!invocation_id) {
2531                 return LDB_ERR_OPERATIONS_ERROR;
2532         }
2533
2534         ret = replmd_check_upgrade_links(old_dns, old_num_values, old_el, invocation_id);
2535         if (ret != LDB_SUCCESS) {
2536                 talloc_free(tmp_ctx);
2537                 return ret;
2538         }
2539
2540         /* mark all the old ones as deleted */
2541         for (i=0; i<old_num_values; i++) {
2542                 struct parsed_dn *old_p = &old_dns[i];
2543                 struct parsed_dn *p;
2544                 uint32_t rmd_flags = dsdb_dn_rmd_flags(old_p->dsdb_dn->dn);
2545
2546                 if (rmd_flags & DSDB_RMD_FLAG_DELETED) continue;
2547
2548                 ret = replmd_add_backlink(module, replmd_private,
2549                                           schema, msg_guid, &old_dns[i].guid,
2550                                           false, schema_attr, false);
2551                 if (ret != LDB_SUCCESS) {
2552                         talloc_free(tmp_ctx);
2553                         return ret;
2554                 }
2555
2556                 p = parsed_dn_find(dns, el->num_values, &old_p->guid, NULL);
2557                 if (p) {
2558                         /* we don't delete it if we are re-adding it */
2559                         continue;
2560                 }
2561
2562                 ret = replmd_update_la_val(old_el->values, old_p->v, old_p->dsdb_dn, old_p->dsdb_dn,
2563                                            invocation_id, seq_num, seq_num, now, 0, true);
2564                 if (ret != LDB_SUCCESS) {
2565                         talloc_free(tmp_ctx);
2566                         return ret;
2567                 }
2568         }
2569
2570         /* for each new value, either update its meta-data, or add it
2571          * to old_el
2572         */
2573         for (i=0; i<el->num_values; i++) {
2574                 struct parsed_dn *p = &dns[i], *old_p;
2575
2576                 if (old_dns &&
2577                     (old_p = parsed_dn_find(old_dns,
2578                                             old_num_values, &p->guid, NULL)) != NULL) {
2579                         /* update in place */
2580                         ret = replmd_update_la_val(old_el->values, old_p->v, p->dsdb_dn,
2581                                                    old_p->dsdb_dn, invocation_id,
2582                                                    seq_num, seq_num, now, 0, false);
2583                         if (ret != LDB_SUCCESS) {
2584                                 talloc_free(tmp_ctx);
2585                                 return ret;
2586                         }
2587                 } else {
2588                         /* add a new one */
2589                         new_values = talloc_realloc(tmp_ctx, new_values, struct ldb_val,
2590                                                     num_new_values+1);
2591                         if (new_values == NULL) {
2592                                 ldb_module_oom(module);
2593                                 talloc_free(tmp_ctx);
2594                                 return LDB_ERR_OPERATIONS_ERROR;
2595                         }
2596                         ret = replmd_build_la_val(new_values, &new_values[num_new_values], dns[i].dsdb_dn,
2597                                                   invocation_id, seq_num, seq_num, now, 0, false);
2598                         if (ret != LDB_SUCCESS) {
2599                                 talloc_free(tmp_ctx);
2600                                 return ret;
2601                         }
2602                         num_new_values++;
2603                 }
2604
2605                 ret = replmd_add_backlink(module, replmd_private,
2606                                           schema, msg_guid, &dns[i].guid,
2607                                           true, schema_attr, false);
2608                 if (ret != LDB_SUCCESS) {
2609                         talloc_free(tmp_ctx);
2610                         return ret;
2611                 }
2612         }
2613
2614         /* add the new values to the end of old_el */
2615         if (num_new_values != 0) {
2616                 el->values = talloc_realloc(msg->elements, old_el?old_el->values:NULL,
2617                                             struct ldb_val, old_num_values+num_new_values);
2618                 if (el->values == NULL) {
2619                         ldb_module_oom(module);
2620                         return LDB_ERR_OPERATIONS_ERROR;
2621                 }
2622                 memcpy(&el->values[old_num_values], &new_values[0],
2623                        sizeof(struct ldb_val)*num_new_values);
2624                 el->num_values = old_num_values + num_new_values;
2625                 talloc_steal(msg->elements, new_values);
2626         } else {
2627                 el->values = old_el->values;
2628                 el->num_values = old_el->num_values;
2629                 talloc_steal(msg->elements, el->values);
2630         }
2631
2632         talloc_free(tmp_ctx);
2633
2634         /* we now tell the backend to replace all existing values
2635            with the one we have constructed */
2636         el->flags = LDB_FLAG_MOD_REPLACE;
2637
2638         return LDB_SUCCESS;
2639 }
2640
2641
2642 /*
2643   handle linked attributes in modify requests
2644  */
2645 static int replmd_modify_handle_linked_attribs(struct ldb_module *module,
2646                                                struct replmd_private *replmd_private,
2647                                                struct ldb_message *msg,
2648                                                uint64_t seq_num, time_t t,
2649                                                struct ldb_request *parent)
2650 {
2651         struct ldb_result *res;
2652         unsigned int i;
2653         int ret;
2654         struct ldb_context *ldb = ldb_module_get_ctx(module);
2655         struct ldb_message *old_msg;
2656
2657         const struct dsdb_schema *schema;
2658         struct GUID old_guid;
2659
2660         if (dsdb_functional_level(ldb) == DS_DOMAIN_FUNCTION_2000) {
2661                 /*
2662                  * Nothing special is required for modifying or vanishing links
2663                  * in fl2000 since they are just strings in a multi-valued
2664                  * attribute.
2665                  */
2666                 struct ldb_control *ctrl = ldb_request_get_control(parent,
2667                                                                    DSDB_CONTROL_REPLMD_VANISH_LINKS);
2668                 if (ctrl) {
2669                         ctrl->critical = false;
2670                 }
2671                 return LDB_SUCCESS;
2672         }
2673
2674         /*
2675          * TODO:
2676          *
2677          * We should restrict this to the intersection of the list of
2678          * linked attributes in the schema and the list of attributes
2679          * being modified.
2680          *
2681          * This will help performance a little, as otherwise we have
2682          * to allocate the entire object value-by-value.
2683          */
2684         ret = dsdb_module_search_dn(module, msg, &res, msg->dn, NULL,
2685                                     DSDB_FLAG_NEXT_MODULE |
2686                                     DSDB_SEARCH_SHOW_RECYCLED |
2687                                     DSDB_SEARCH_REVEAL_INTERNALS |
2688                                     DSDB_SEARCH_SHOW_DN_IN_STORAGE_FORMAT,
2689                                     parent);
2690         if (ret != LDB_SUCCESS) {
2691                 return ret;
2692         }
2693         schema = dsdb_get_schema(ldb, res);
2694         if (!schema) {
2695                 return LDB_ERR_OPERATIONS_ERROR;
2696         }
2697
2698         old_msg = res->msgs[0];
2699
2700         old_guid = samdb_result_guid(old_msg, "objectGUID");
2701
2702         for (i=0; i<msg->num_elements; i++) {
2703                 struct ldb_message_element *el = &msg->elements[i];
2704                 struct ldb_message_element *old_el, *new_el;
2705                 const struct dsdb_attribute *schema_attr
2706                         = dsdb_attribute_by_lDAPDisplayName(schema, el->name);
2707                 if (!schema_attr) {
2708                         ldb_asprintf_errstring(ldb,
2709                                                "%s: attribute %s is not a valid attribute in schema",
2710                                                __FUNCTION__, el->name);
2711                         return LDB_ERR_OBJECT_CLASS_VIOLATION;
2712                 }
2713                 if (schema_attr->linkID == 0) {
2714                         continue;
2715                 }
2716                 if ((schema_attr->linkID & 1) == 1) {
2717                         if (parent && ldb_request_get_control(parent, DSDB_CONTROL_DBCHECK)) {
2718                                 continue;
2719                         }
2720                         /* Odd is for the target.  Illegal to modify */
2721                         ldb_asprintf_errstring(ldb,
2722                                                "attribute %s must not be modified directly, it is a linked attribute", el->name);
2723         &nb