repl_meta_data: Correctly use msDS-IntId for custom schema, not the prefixMap value
[abartlet/samba.git/.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 };
72
73 struct la_entry {
74         struct la_entry *next, *prev;
75         struct drsuapi_DsReplicaLinkedAttribute *la;
76 };
77
78 struct replmd_replicated_request {
79         struct ldb_module *module;
80         struct ldb_request *req;
81
82         const struct dsdb_schema *schema;
83
84         /* the controls we pass down */
85         struct ldb_control **controls;
86
87         /* details for the mode where we apply a bunch of inbound replication meessages */
88         bool apply_mode;
89         uint32_t index_current;
90         struct dsdb_extended_replicated_objects *objs;
91
92         struct ldb_message *search_msg;
93
94         uint64_t seq_num;
95         bool is_urgent;
96
97         bool isDeleted;
98 };
99
100 static int replmd_replicated_apply_merge(struct replmd_replicated_request *ar);
101 static int replmd_delete_internals(struct ldb_module *module, struct ldb_request *req, bool re_delete);
102
103 enum urgent_situation {
104         REPL_URGENT_ON_CREATE = 1,
105         REPL_URGENT_ON_UPDATE = 2,
106         REPL_URGENT_ON_DELETE = 4
107 };
108
109 enum deletion_state {
110         OBJECT_NOT_DELETED=1,
111         OBJECT_DELETED=2,
112         OBJECT_RECYCLED=3,
113         OBJECT_TOMBSTONE=4,
114         OBJECT_REMOVED=5
115 };
116
117 static void replmd_deletion_state(struct ldb_module *module,
118                                   const struct ldb_message *msg,
119                                   enum deletion_state *current_state,
120                                   enum deletion_state *next_state)
121 {
122         int ret;
123         bool enabled = false;
124
125         if (msg == NULL) {
126                 *current_state = OBJECT_REMOVED;
127                 if (next_state != NULL) {
128                         *next_state = OBJECT_REMOVED;
129                 }
130                 return;
131         }
132
133         ret = dsdb_recyclebin_enabled(module, &enabled);
134         if (ret != LDB_SUCCESS) {
135                 enabled = false;
136         }
137
138         if (ldb_msg_check_string_attribute(msg, "isDeleted", "TRUE")) {
139                 if (!enabled) {
140                         *current_state = OBJECT_TOMBSTONE;
141                         if (next_state != NULL) {
142                                 *next_state = OBJECT_REMOVED;
143                         }
144                         return;
145                 }
146
147                 if (ldb_msg_check_string_attribute(msg, "isRecycled", "TRUE")) {
148                         *current_state = OBJECT_RECYCLED;
149                         if (next_state != NULL) {
150                                 *next_state = OBJECT_REMOVED;
151                         }
152                         return;
153                 }
154
155                 *current_state = OBJECT_DELETED;
156                 if (next_state != NULL) {
157                         *next_state = OBJECT_RECYCLED;
158                 }
159                 return;
160         }
161
162         *current_state = OBJECT_NOT_DELETED;
163         if (next_state == NULL) {
164                 return;
165         }
166
167         if (enabled) {
168                 *next_state = OBJECT_DELETED;
169         } else {
170                 *next_state = OBJECT_TOMBSTONE;
171         }
172 }
173
174 static const struct {
175         const char *update_name;
176         enum urgent_situation repl_situation;
177 } urgent_objects[] = {
178                 {"nTDSDSA", (REPL_URGENT_ON_CREATE | REPL_URGENT_ON_DELETE)},
179                 {"crossRef", (REPL_URGENT_ON_CREATE | REPL_URGENT_ON_DELETE)},
180                 {"attributeSchema", (REPL_URGENT_ON_CREATE | REPL_URGENT_ON_UPDATE)},
181                 {"classSchema", (REPL_URGENT_ON_CREATE | REPL_URGENT_ON_UPDATE)},
182                 {"secret", (REPL_URGENT_ON_CREATE | REPL_URGENT_ON_UPDATE)},
183                 {"rIDManager", (REPL_URGENT_ON_CREATE | REPL_URGENT_ON_UPDATE)},
184                 {NULL, 0}
185 };
186
187 /* Attributes looked for when updating or deleting, to check for a urgent replication needed */
188 static const char *urgent_attrs[] = {
189                 "lockoutTime",
190                 "pwdLastSet",
191                 "userAccountControl",
192                 NULL
193 };
194
195
196 static bool replmd_check_urgent_objectclass(const struct ldb_message_element *objectclass_el,
197                                         enum urgent_situation situation)
198 {
199         unsigned int i, j;
200         for (i=0; urgent_objects[i].update_name; i++) {
201
202                 if ((situation & urgent_objects[i].repl_situation) == 0) {
203                         continue;
204                 }
205
206                 for (j=0; j<objectclass_el->num_values; j++) {
207                         const struct ldb_val *v = &objectclass_el->values[j];
208                         if (ldb_attr_cmp((const char *)v->data, urgent_objects[i].update_name) == 0) {
209                                 return true;
210                         }
211                 }
212         }
213         return false;
214 }
215
216 static bool replmd_check_urgent_attribute(const struct ldb_message_element *el)
217 {
218         if (ldb_attr_in_list(urgent_attrs, el->name)) {
219                 return true;
220         }
221         return false;
222 }
223
224
225 static int replmd_replicated_apply_isDeleted(struct replmd_replicated_request *ar);
226
227 /*
228   initialise the module
229   allocate the private structure and build the list
230   of partition DNs for use by replmd_notify()
231  */
232 static int replmd_init(struct ldb_module *module)
233 {
234         struct replmd_private *replmd_private;
235         struct ldb_context *ldb = ldb_module_get_ctx(module);
236
237         replmd_private = talloc_zero(module, struct replmd_private);
238         if (replmd_private == NULL) {
239                 ldb_oom(ldb);
240                 return LDB_ERR_OPERATIONS_ERROR;
241         }
242         ldb_module_set_private(module, replmd_private);
243
244         replmd_private->schema_dn = ldb_get_schema_basedn(ldb);
245
246         return ldb_next_init(module);
247 }
248
249 /*
250   cleanup our per-transaction contexts
251  */
252 static void replmd_txn_cleanup(struct replmd_private *replmd_private)
253 {
254         talloc_free(replmd_private->la_ctx);
255         replmd_private->la_list = NULL;
256         replmd_private->la_ctx = NULL;
257
258         talloc_free(replmd_private->bl_ctx);
259         replmd_private->la_backlinks = NULL;
260         replmd_private->bl_ctx = NULL;
261 }
262
263
264 struct la_backlink {
265         struct la_backlink *next, *prev;
266         const char *attr_name;
267         struct GUID forward_guid, target_guid;
268         bool active;
269 };
270
271 /*
272   process a backlinks we accumulated during a transaction, adding and
273   deleting the backlinks from the target objects
274  */
275 static int replmd_process_backlink(struct ldb_module *module, struct la_backlink *bl, struct ldb_request *parent)
276 {
277         struct ldb_dn *target_dn, *source_dn;
278         int ret;
279         struct ldb_context *ldb = ldb_module_get_ctx(module);
280         struct ldb_message *msg;
281         TALLOC_CTX *tmp_ctx = talloc_new(bl);
282         char *dn_string;
283
284         /*
285           - find DN of target
286           - find DN of source
287           - construct ldb_message
288               - either an add or a delete
289          */
290         ret = dsdb_module_dn_by_guid(module, tmp_ctx, &bl->target_guid, &target_dn, parent);
291         if (ret != LDB_SUCCESS) {
292                 DEBUG(2,(__location__ ": WARNING: Failed to find target DN for linked attribute with GUID %s\n",
293                          GUID_string(bl, &bl->target_guid)));
294                 return LDB_SUCCESS;
295         }
296
297         ret = dsdb_module_dn_by_guid(module, tmp_ctx, &bl->forward_guid, &source_dn, parent);
298         if (ret != LDB_SUCCESS) {
299                 ldb_asprintf_errstring(ldb, "Failed to find source DN for linked attribute with GUID %s\n",
300                                        GUID_string(bl, &bl->forward_guid));
301                 talloc_free(tmp_ctx);
302                 return ret;
303         }
304
305         msg = ldb_msg_new(tmp_ctx);
306         if (msg == NULL) {
307                 ldb_module_oom(module);
308                 talloc_free(tmp_ctx);
309                 return LDB_ERR_OPERATIONS_ERROR;
310         }
311
312         /* construct a ldb_message for adding/deleting the backlink */
313         msg->dn = target_dn;
314         dn_string = ldb_dn_get_extended_linearized(tmp_ctx, source_dn, 1);
315         if (!dn_string) {
316                 ldb_module_oom(module);
317                 talloc_free(tmp_ctx);
318                 return LDB_ERR_OPERATIONS_ERROR;
319         }
320         ret = ldb_msg_add_steal_string(msg, bl->attr_name, dn_string);
321         if (ret != LDB_SUCCESS) {
322                 talloc_free(tmp_ctx);
323                 return ret;
324         }
325         msg->elements[0].flags = bl->active?LDB_FLAG_MOD_ADD:LDB_FLAG_MOD_DELETE;
326
327         /* a backlink should never be single valued. Unfortunately the
328            exchange schema has a attribute
329            msExchBridgeheadedLocalConnectorsDNBL which is single
330            valued and a backlink. We need to cope with that by
331            ignoring the single value flag */
332         msg->elements[0].flags |= LDB_FLAG_INTERNAL_DISABLE_SINGLE_VALUE_CHECK;
333
334         ret = dsdb_module_modify(module, msg, DSDB_FLAG_NEXT_MODULE, parent);
335         if (ret == LDB_ERR_NO_SUCH_ATTRIBUTE && !bl->active) {
336                 /* we allow LDB_ERR_NO_SUCH_ATTRIBUTE as success to
337                    cope with possible corruption where the backlink has
338                    already been removed */
339                 DEBUG(3,("WARNING: backlink from %s already removed from %s - %s\n",
340                          ldb_dn_get_linearized(target_dn),
341                          ldb_dn_get_linearized(source_dn),
342                          ldb_errstring(ldb)));
343                 ret = LDB_SUCCESS;
344         } else if (ret != LDB_SUCCESS) {
345                 ldb_asprintf_errstring(ldb, "Failed to %s backlink from %s to %s - %s",
346                                        bl->active?"add":"remove",
347                                        ldb_dn_get_linearized(source_dn),
348                                        ldb_dn_get_linearized(target_dn),
349                                        ldb_errstring(ldb));
350                 talloc_free(tmp_ctx);
351                 return ret;
352         }
353         talloc_free(tmp_ctx);
354         return ret;
355 }
356
357 /*
358   add a backlink to the list of backlinks to add/delete in the prepare
359   commit
360  */
361 static int replmd_add_backlink(struct ldb_module *module, const struct dsdb_schema *schema,
362                                struct GUID *forward_guid, struct GUID *target_guid,
363                                bool active, const struct dsdb_attribute *schema_attr, bool immediate)
364 {
365         const struct dsdb_attribute *target_attr;
366         struct la_backlink *bl;
367         struct replmd_private *replmd_private =
368                 talloc_get_type_abort(ldb_module_get_private(module), struct replmd_private);
369
370         target_attr = dsdb_attribute_by_linkID(schema, schema_attr->linkID ^ 1);
371         if (!target_attr) {
372                 /*
373                  * windows 2003 has a broken schema where the
374                  * definition of msDS-IsDomainFor is missing (which is
375                  * supposed to be the backlink of the
376                  * msDS-HasDomainNCs attribute
377                  */
378                 return LDB_SUCCESS;
379         }
380
381         /* see if its already in the list */
382         for (bl=replmd_private->la_backlinks; bl; bl=bl->next) {
383                 if (GUID_equal(forward_guid, &bl->forward_guid) &&
384                     GUID_equal(target_guid, &bl->target_guid) &&
385                     (target_attr->lDAPDisplayName == bl->attr_name ||
386                      strcmp(target_attr->lDAPDisplayName, bl->attr_name) == 0)) {
387                         break;
388                 }
389         }
390
391         if (bl) {
392                 /* we found an existing one */
393                 if (bl->active == active) {
394                         return LDB_SUCCESS;
395                 }
396                 DLIST_REMOVE(replmd_private->la_backlinks, bl);
397                 talloc_free(bl);
398                 return LDB_SUCCESS;
399         }
400
401         if (replmd_private->bl_ctx == NULL) {
402                 replmd_private->bl_ctx = talloc_new(replmd_private);
403                 if (replmd_private->bl_ctx == NULL) {
404                         ldb_module_oom(module);
405                         return LDB_ERR_OPERATIONS_ERROR;
406                 }
407         }
408
409         /* its a new one */
410         bl = talloc(replmd_private->bl_ctx, struct la_backlink);
411         if (bl == NULL) {
412                 ldb_module_oom(module);
413                 return LDB_ERR_OPERATIONS_ERROR;
414         }
415
416         /* Ensure the schema does not go away before the bl->attr_name is used */
417         if (!talloc_reference(bl, schema)) {
418                 talloc_free(bl);
419                 ldb_module_oom(module);
420                 return LDB_ERR_OPERATIONS_ERROR;
421         }
422
423         bl->attr_name = target_attr->lDAPDisplayName;
424         bl->forward_guid = *forward_guid;
425         bl->target_guid = *target_guid;
426         bl->active = active;
427
428         /* the caller may ask for this backlink to be processed
429            immediately */
430         if (immediate) {
431                 int ret = replmd_process_backlink(module, bl, NULL);
432                 talloc_free(bl);
433                 return ret;
434         }
435
436         DLIST_ADD(replmd_private->la_backlinks, bl);
437
438         return LDB_SUCCESS;
439 }
440
441
442 /*
443  * Callback for most write operations in this module:
444  *
445  * notify the repl task that a object has changed. The notifies are
446  * gathered up in the replmd_private structure then written to the
447  * @REPLCHANGED object in each partition during the prepare_commit
448  */
449 static int replmd_op_callback(struct ldb_request *req, struct ldb_reply *ares)
450 {
451         int ret;
452         struct replmd_replicated_request *ac =
453                 talloc_get_type_abort(req->context, struct replmd_replicated_request);
454         struct replmd_private *replmd_private =
455                 talloc_get_type_abort(ldb_module_get_private(ac->module), struct replmd_private);
456         struct nc_entry *modified_partition;
457         struct ldb_control *partition_ctrl;
458         const struct dsdb_control_current_partition *partition;
459
460         struct ldb_control **controls;
461
462         partition_ctrl = ldb_reply_get_control(ares, DSDB_CONTROL_CURRENT_PARTITION_OID);
463
464         controls = ares->controls;
465         if (ldb_request_get_control(ac->req,
466                                     DSDB_CONTROL_CURRENT_PARTITION_OID) == NULL) {
467                 /*
468                  * Remove the current partition control from what we pass up
469                  * the chain if it hasn't been requested manually.
470                  */
471                 controls = ldb_controls_except_specified(ares->controls, ares,
472                                                          partition_ctrl);
473         }
474
475         if (ares->error != LDB_SUCCESS) {
476                 DEBUG(5,("%s failure. Error is: %s\n", __FUNCTION__, ldb_strerror(ares->error)));
477                 return ldb_module_done(ac->req, controls,
478                                         ares->response, ares->error);
479         }
480
481         if (ares->type != LDB_REPLY_DONE) {
482                 ldb_set_errstring(ldb_module_get_ctx(ac->module), "Invalid reply type for notify\n!");
483                 return ldb_module_done(ac->req, NULL,
484                                        NULL, LDB_ERR_OPERATIONS_ERROR);
485         }
486
487         if (!partition_ctrl) {
488                 ldb_set_errstring(ldb_module_get_ctx(ac->module),"No partition control on reply");
489                 return ldb_module_done(ac->req, NULL,
490                                        NULL, LDB_ERR_OPERATIONS_ERROR);
491         }
492
493         partition = talloc_get_type_abort(partition_ctrl->data,
494                                     struct dsdb_control_current_partition);
495
496         if (ac->seq_num > 0) {
497                 for (modified_partition = replmd_private->ncs; modified_partition;
498                      modified_partition = modified_partition->next) {
499                         if (ldb_dn_compare(modified_partition->dn, partition->dn) == 0) {
500                                 break;
501                         }
502                 }
503
504                 if (modified_partition == NULL) {
505                         modified_partition = talloc_zero(replmd_private, struct nc_entry);
506                         if (!modified_partition) {
507                                 ldb_oom(ldb_module_get_ctx(ac->module));
508                                 return ldb_module_done(ac->req, NULL,
509                                                        NULL, LDB_ERR_OPERATIONS_ERROR);
510                         }
511                         modified_partition->dn = ldb_dn_copy(modified_partition, partition->dn);
512                         if (!modified_partition->dn) {
513                                 ldb_oom(ldb_module_get_ctx(ac->module));
514                                 return ldb_module_done(ac->req, NULL,
515                                                        NULL, LDB_ERR_OPERATIONS_ERROR);
516                         }
517                         DLIST_ADD(replmd_private->ncs, modified_partition);
518                 }
519
520                 if (ac->seq_num > modified_partition->mod_usn) {
521                         modified_partition->mod_usn = ac->seq_num;
522                         if (ac->is_urgent) {
523                                 modified_partition->mod_usn_urgent = ac->seq_num;
524                         }
525                 }
526         }
527
528         if (ac->apply_mode) {
529                 ret = replmd_replicated_apply_isDeleted(ac);
530                 if (ret != LDB_SUCCESS) {
531                         return ldb_module_done(ac->req, NULL, NULL, ret);
532                 }
533                 return ret;
534         } else {
535                 /* free the partition control container here, for the
536                  * common path.  Other cases will have it cleaned up
537                  * eventually with the ares */
538                 talloc_free(partition_ctrl);
539                 return ldb_module_done(ac->req, controls,
540                                        ares->response, LDB_SUCCESS);
541         }
542 }
543
544
545 /*
546  * update a @REPLCHANGED record in each partition if there have been
547  * any writes of replicated data in the partition
548  */
549 static int replmd_notify_store(struct ldb_module *module, struct ldb_request *parent)
550 {
551         struct replmd_private *replmd_private =
552                 talloc_get_type(ldb_module_get_private(module), struct replmd_private);
553
554         while (replmd_private->ncs) {
555                 int ret;
556                 struct nc_entry *modified_partition = replmd_private->ncs;
557
558                 ret = dsdb_module_save_partition_usn(module, modified_partition->dn,
559                                                      modified_partition->mod_usn,
560                                                      modified_partition->mod_usn_urgent, parent);
561                 if (ret != LDB_SUCCESS) {
562                         DEBUG(0,(__location__ ": Failed to save partition uSN for %s\n",
563                                  ldb_dn_get_linearized(modified_partition->dn)));
564                         return ret;
565                 }
566                 DLIST_REMOVE(replmd_private->ncs, modified_partition);
567                 talloc_free(modified_partition);
568         }
569
570         return LDB_SUCCESS;
571 }
572
573
574 /*
575   created a replmd_replicated_request context
576  */
577 static struct replmd_replicated_request *replmd_ctx_init(struct ldb_module *module,
578                                                          struct ldb_request *req)
579 {
580         struct ldb_context *ldb;
581         struct replmd_replicated_request *ac;
582
583         ldb = ldb_module_get_ctx(module);
584
585         ac = talloc_zero(req, struct replmd_replicated_request);
586         if (ac == NULL) {
587                 ldb_oom(ldb);
588                 return NULL;
589         }
590
591         ac->module = module;
592         ac->req = req;
593
594         ac->schema = dsdb_get_schema(ldb, ac);
595         if (!ac->schema) {
596                 ldb_debug_set(ldb, LDB_DEBUG_FATAL,
597                               "replmd_modify: no dsdb_schema loaded");
598                 DEBUG(0,(__location__ ": %s\n", ldb_errstring(ldb)));
599                 return NULL;
600         }
601
602         return ac;
603 }
604
605 /*
606   add a time element to a record
607 */
608 static int add_time_element(struct ldb_message *msg, const char *attr, time_t t)
609 {
610         struct ldb_message_element *el;
611         char *s;
612         int ret;
613
614         if (ldb_msg_find_element(msg, attr) != NULL) {
615                 return LDB_SUCCESS;
616         }
617
618         s = ldb_timestring(msg, t);
619         if (s == NULL) {
620                 return LDB_ERR_OPERATIONS_ERROR;
621         }
622
623         ret = ldb_msg_add_string(msg, attr, s);
624         if (ret != LDB_SUCCESS) {
625                 return ret;
626         }
627
628         el = ldb_msg_find_element(msg, attr);
629         /* always set as replace. This works because on add ops, the flag
630            is ignored */
631         el->flags = LDB_FLAG_MOD_REPLACE;
632
633         return LDB_SUCCESS;
634 }
635
636 /*
637   add a uint64_t element to a record
638 */
639 static int add_uint64_element(struct ldb_context *ldb, struct ldb_message *msg,
640                               const char *attr, uint64_t v)
641 {
642         struct ldb_message_element *el;
643         int ret;
644
645         if (ldb_msg_find_element(msg, attr) != NULL) {
646                 return LDB_SUCCESS;
647         }
648
649         ret = samdb_msg_add_uint64(ldb, msg, msg, attr, v);
650         if (ret != LDB_SUCCESS) {
651                 return ret;
652         }
653
654         el = ldb_msg_find_element(msg, attr);
655         /* always set as replace. This works because on add ops, the flag
656            is ignored */
657         el->flags = LDB_FLAG_MOD_REPLACE;
658
659         return LDB_SUCCESS;
660 }
661
662 static int replmd_replPropertyMetaData1_attid_sort(const struct replPropertyMetaData1 *m1,
663                                                    const struct replPropertyMetaData1 *m2,
664                                                    const uint32_t *rdn_attid)
665 {
666         /*
667          * This assignment seems inoccous, but it is critical for the
668          * system, as we need to do the comparisons as a unsigned
669          * quantity, not signed (enums are signed integers)
670          */
671         uint32_t attid_1 = m1->attid;
672         uint32_t attid_2 = m2->attid;
673
674         if (attid_1 == attid_2) {
675                 return 0;
676         }
677
678         /*
679          * the rdn attribute should be at the end!
680          * so we need to return a value greater than zero
681          * which means m1 is greater than m2
682          */
683         if (attid_1 == *rdn_attid) {
684                 return 1;
685         }
686
687         /*
688          * the rdn attribute should be at the end!
689          * so we need to return a value less than zero
690          * which means m2 is greater than m1
691          */
692         if (attid_2 == *rdn_attid) {
693                 return -1;
694         }
695
696         /*
697          * See above regarding this being an unsigned comparison.
698          * Otherwise when the high bit is set on non-standard
699          * attributes, they would end up first, before objectClass
700          * (0).
701          */
702         return attid_1 > attid_2 ? 1 : -1;
703 }
704
705 static int replmd_replPropertyMetaDataCtr1_verify(struct ldb_context *ldb,
706                                                   struct replPropertyMetaDataCtr1 *ctr1,
707                                                   const struct dsdb_attribute *rdn_sa,
708                                                   struct ldb_dn *dn)
709 {
710         if (ctr1->count == 0) {
711                 ldb_debug_set(ldb, LDB_DEBUG_FATAL,
712                               "No elements found in replPropertyMetaData for %s!\n",
713                               ldb_dn_get_linearized(dn));
714                 return LDB_ERR_CONSTRAINT_VIOLATION;
715         }
716         if (ctr1->array[ctr1->count - 1].attid != rdn_sa->attributeID_id) {
717                 ldb_debug_set(ldb, LDB_DEBUG_FATAL,
718                               "No rDN found in replPropertyMetaData for %s!\n",
719                               ldb_dn_get_linearized(dn));
720                 return LDB_ERR_CONSTRAINT_VIOLATION;
721         }
722
723         /* the objectClass attribute is value 0x00000000, so must be first */
724         if (ctr1->array[0].attid != DRSUAPI_ATTID_objectClass) {
725                 ldb_debug_set(ldb, LDB_DEBUG_FATAL,
726                               "No objectClass found in replPropertyMetaData for %s!\n",
727                               ldb_dn_get_linearized(dn));
728                 return LDB_ERR_OBJECT_CLASS_VIOLATION;
729         }
730
731         return LDB_SUCCESS;
732 }
733
734 static int replmd_replPropertyMetaDataCtr1_sort_and_verify(struct ldb_context *ldb,
735                                                            struct replPropertyMetaDataCtr1 *ctr1,
736                                                            const struct dsdb_schema *schema,
737                                                            struct ldb_dn *dn)
738 {
739         const char *rdn_name;
740         const struct dsdb_attribute *rdn_sa;
741
742         rdn_name = ldb_dn_get_rdn_name(dn);
743         if (!rdn_name) {
744                 ldb_debug_set(ldb, LDB_DEBUG_FATAL,
745                               __location__ ": No rDN for %s?\n",
746                               ldb_dn_get_linearized(dn));
747                 return LDB_ERR_INVALID_DN_SYNTAX;
748         }
749
750         rdn_sa = dsdb_attribute_by_lDAPDisplayName(schema, rdn_name);
751         if (rdn_sa == NULL) {
752                 ldb_debug_set(ldb, LDB_DEBUG_FATAL,
753                               __location__ ": No sa found for rDN %s for %s\n",
754                               rdn_name, ldb_dn_get_linearized(dn));
755                 return LDB_ERR_UNDEFINED_ATTRIBUTE_TYPE;
756         }
757
758         DEBUG(6,("Sorting rpmd with attid exception %u rDN=%s DN=%s\n",
759                  rdn_sa->attributeID_id, rdn_name, ldb_dn_get_linearized(dn)));
760
761         LDB_TYPESAFE_QSORT(ctr1->array, ctr1->count, &rdn_sa->attributeID_id,
762                            replmd_replPropertyMetaData1_attid_sort);
763         return replmd_replPropertyMetaDataCtr1_verify(ldb, ctr1, rdn_sa, dn);
764 }
765
766 static int replmd_ldb_message_element_attid_sort(const struct ldb_message_element *e1,
767                                                  const struct ldb_message_element *e2,
768                                                  const struct dsdb_schema *schema)
769 {
770         const struct dsdb_attribute *a1;
771         const struct dsdb_attribute *a2;
772
773         /*
774          * TODO: make this faster by caching the dsdb_attribute pointer
775          *       on the ldb_messag_element
776          */
777
778         a1 = dsdb_attribute_by_lDAPDisplayName(schema, e1->name);
779         a2 = dsdb_attribute_by_lDAPDisplayName(schema, e2->name);
780
781         /*
782          * TODO: remove this check, we should rely on e1 and e2 having valid attribute names
783          *       in the schema
784          */
785         if (!a1 || !a2) {
786                 return strcasecmp(e1->name, e2->name);
787         }
788         if (a1->attributeID_id == a2->attributeID_id) {
789                 return 0;
790         }
791         return a1->attributeID_id > a2->attributeID_id ? 1 : -1;
792 }
793
794 static void replmd_ldb_message_sort(struct ldb_message *msg,
795                                     const struct dsdb_schema *schema)
796 {
797         LDB_TYPESAFE_QSORT(msg->elements, msg->num_elements, schema, replmd_ldb_message_element_attid_sort);
798 }
799
800 static int replmd_build_la_val(TALLOC_CTX *mem_ctx, struct ldb_val *v, struct dsdb_dn *dsdb_dn,
801                                const struct GUID *invocation_id, uint64_t seq_num,
802                                uint64_t local_usn, NTTIME nttime, uint32_t version, bool deleted);
803
804
805 /*
806   fix up linked attributes in replmd_add.
807   This involves setting up the right meta-data in extended DN
808   components, and creating backlinks to the object
809  */
810 static int replmd_add_fix_la(struct ldb_module *module, struct ldb_message_element *el,
811                              uint64_t seq_num, const struct GUID *invocationId, time_t t,
812                              struct GUID *guid, const struct dsdb_attribute *sa, struct ldb_request *parent)
813 {
814         unsigned int i;
815         TALLOC_CTX *tmp_ctx = talloc_new(el->values);
816         struct ldb_context *ldb = ldb_module_get_ctx(module);
817
818         /* We will take a reference to the schema in replmd_add_backlink */
819         const struct dsdb_schema *schema = dsdb_get_schema(ldb, NULL);
820         NTTIME now;
821
822         unix_to_nt_time(&now, t);
823
824         for (i=0; i<el->num_values; i++) {
825                 struct ldb_val *v = &el->values[i];
826                 struct dsdb_dn *dsdb_dn = dsdb_dn_parse(tmp_ctx, ldb, v, sa->syntax->ldap_oid);
827                 struct GUID target_guid;
828                 NTSTATUS status;
829                 int ret;
830
831                 /* note that the DN already has the extended
832                    components from the extended_dn_store module */
833                 status = dsdb_get_extended_dn_guid(dsdb_dn->dn, &target_guid, "GUID");
834                 if (!NT_STATUS_IS_OK(status) || GUID_all_zero(&target_guid)) {
835                         ret = dsdb_module_guid_by_dn(module, dsdb_dn->dn, &target_guid, parent);
836                         if (ret != LDB_SUCCESS) {
837                                 talloc_free(tmp_ctx);
838                                 return ret;
839                         }
840                         ret = dsdb_set_extended_dn_guid(dsdb_dn->dn, &target_guid, "GUID");
841                         if (ret != LDB_SUCCESS) {
842                                 talloc_free(tmp_ctx);
843                                 return ret;
844                         }
845                 }
846
847                 ret = replmd_build_la_val(el->values, v, dsdb_dn, invocationId,
848                                           seq_num, seq_num, now, 0, false);
849                 if (ret != LDB_SUCCESS) {
850                         talloc_free(tmp_ctx);
851                         return ret;
852                 }
853
854                 ret = replmd_add_backlink(module, schema, guid, &target_guid, true, sa, false);
855                 if (ret != LDB_SUCCESS) {
856                         talloc_free(tmp_ctx);
857                         return ret;
858                 }
859         }
860
861         talloc_free(tmp_ctx);
862         return LDB_SUCCESS;
863 }
864
865
866 /*
867   intercept add requests
868  */
869 static int replmd_add(struct ldb_module *module, struct ldb_request *req)
870 {
871         struct samldb_msds_intid_persistant *msds_intid_struct;
872         struct ldb_context *ldb;
873         struct ldb_control *control;
874         struct replmd_replicated_request *ac;
875         enum ndr_err_code ndr_err;
876         struct ldb_request *down_req;
877         struct ldb_message *msg;
878         const DATA_BLOB *guid_blob;
879         struct GUID guid;
880         struct replPropertyMetaDataBlob nmd;
881         struct ldb_val nmd_value;
882         const struct GUID *our_invocation_id;
883         time_t t = time(NULL);
884         NTTIME now;
885         char *time_str;
886         int ret;
887         unsigned int i;
888         unsigned int functional_level;
889         uint32_t ni=0;
890         bool allow_add_guid = false;
891         bool remove_current_guid = false;
892         bool is_urgent = false;
893         bool is_schema_nc = false;
894         struct ldb_message_element *objectclass_el;
895         struct replmd_private *replmd_private =
896                 talloc_get_type_abort(ldb_module_get_private(module), struct replmd_private);
897
898         /* check if there's a show relax control (used by provision to say 'I know what I'm doing') */
899         control = ldb_request_get_control(req, LDB_CONTROL_RELAX_OID);
900         if (control) {
901                 allow_add_guid = true;
902         }
903
904         /* do not manipulate our control entries */
905         if (ldb_dn_is_special(req->op.add.message->dn)) {
906                 return ldb_next_request(module, req);
907         }
908
909         ldb = ldb_module_get_ctx(module);
910
911         ldb_debug(ldb, LDB_DEBUG_TRACE, "replmd_add\n");
912
913         guid_blob = ldb_msg_find_ldb_val(req->op.add.message, "objectGUID");
914         if (guid_blob != NULL) {
915                 if (!allow_add_guid) {
916                         ldb_set_errstring(ldb,
917                                           "replmd_add: it's not allowed to add an object with objectGUID!");
918                         return LDB_ERR_UNWILLING_TO_PERFORM;
919                 } else {
920                         NTSTATUS status = GUID_from_data_blob(guid_blob,&guid);
921                         if (!NT_STATUS_IS_OK(status)) {
922                                 ldb_set_errstring(ldb,
923                                                   "replmd_add: Unable to parse the 'objectGUID' as a GUID!");
924                                 return LDB_ERR_UNWILLING_TO_PERFORM;
925                         }
926                         /* we remove this attribute as it can be a string and
927                          * will not be treated correctly and then we will re-add
928                          * it later on in the good format */
929                         remove_current_guid = true;
930                 }
931         } else {
932                 /* a new GUID */
933                 guid = GUID_random();
934         }
935
936         ac = replmd_ctx_init(module, req);
937         if (ac == NULL) {
938                 return ldb_module_oom(module);
939         }
940
941         functional_level = dsdb_functional_level(ldb);
942
943         /* Get a sequence number from the backend */
944         ret = ldb_sequence_number(ldb, LDB_SEQ_NEXT, &ac->seq_num);
945         if (ret != LDB_SUCCESS) {
946                 talloc_free(ac);
947                 return ret;
948         }
949
950         /* get our invocationId */
951         our_invocation_id = samdb_ntds_invocation_id(ldb);
952         if (!our_invocation_id) {
953                 ldb_debug_set(ldb, LDB_DEBUG_ERROR,
954                               "replmd_add: unable to find invocationId\n");
955                 talloc_free(ac);
956                 return LDB_ERR_OPERATIONS_ERROR;
957         }
958
959         /* we have to copy the message as the caller might have it as a const */
960         msg = ldb_msg_copy_shallow(ac, req->op.add.message);
961         if (msg == NULL) {
962                 ldb_oom(ldb);
963                 talloc_free(ac);
964                 return LDB_ERR_OPERATIONS_ERROR;
965         }
966
967         /* generated times */
968         unix_to_nt_time(&now, t);
969         time_str = ldb_timestring(msg, t);
970         if (!time_str) {
971                 ldb_oom(ldb);
972                 talloc_free(ac);
973                 return LDB_ERR_OPERATIONS_ERROR;
974         }
975         if (remove_current_guid) {
976                 ldb_msg_remove_attr(msg,"objectGUID");
977         }
978
979         /*
980          * remove autogenerated attributes
981          */
982         ldb_msg_remove_attr(msg, "whenCreated");
983         ldb_msg_remove_attr(msg, "whenChanged");
984         ldb_msg_remove_attr(msg, "uSNCreated");
985         ldb_msg_remove_attr(msg, "uSNChanged");
986         ldb_msg_remove_attr(msg, "replPropertyMetaData");
987
988         /*
989          * readd replicated attributes
990          */
991         ret = ldb_msg_add_string(msg, "whenCreated", time_str);
992         if (ret != LDB_SUCCESS) {
993                 ldb_oom(ldb);
994                 talloc_free(ac);
995                 return ret;
996         }
997
998         /* build the replication meta_data */
999         ZERO_STRUCT(nmd);
1000         nmd.version             = 1;
1001         nmd.ctr.ctr1.count      = msg->num_elements;
1002         nmd.ctr.ctr1.array      = talloc_array(msg,
1003                                                struct replPropertyMetaData1,
1004                                                nmd.ctr.ctr1.count);
1005         if (!nmd.ctr.ctr1.array) {
1006                 ldb_oom(ldb);
1007                 talloc_free(ac);
1008                 return LDB_ERR_OPERATIONS_ERROR;
1009         }
1010
1011         is_schema_nc = ldb_dn_compare_base(replmd_private->schema_dn, msg->dn) == 0;
1012
1013         for (i=0; i < msg->num_elements; i++) {
1014                 struct ldb_message_element *e = &msg->elements[i];
1015                 struct replPropertyMetaData1 *m = &nmd.ctr.ctr1.array[ni];
1016                 const struct dsdb_attribute *sa;
1017
1018                 if (e->name[0] == '@') continue;
1019
1020                 sa = dsdb_attribute_by_lDAPDisplayName(ac->schema, e->name);
1021                 if (!sa) {
1022                         ldb_debug_set(ldb, LDB_DEBUG_ERROR,
1023                                       "replmd_add: attribute '%s' not defined in schema\n",
1024                                       e->name);
1025                         talloc_free(ac);
1026                         return LDB_ERR_NO_SUCH_ATTRIBUTE;
1027                 }
1028
1029                 if ((sa->systemFlags & DS_FLAG_ATTR_NOT_REPLICATED) || (sa->systemFlags & DS_FLAG_ATTR_IS_CONSTRUCTED)) {
1030                         /* if the attribute is not replicated (0x00000001)
1031                          * or constructed (0x00000004) it has no metadata
1032                          */
1033                         continue;
1034                 }
1035
1036                 if (sa->linkID != 0 && functional_level > DS_DOMAIN_FUNCTION_2000) {
1037                         ret = replmd_add_fix_la(module, e, ac->seq_num, our_invocation_id, t, &guid, sa, req);
1038                         if (ret != LDB_SUCCESS) {
1039                                 talloc_free(ac);
1040                                 return ret;
1041                         }
1042                         /* linked attributes are not stored in
1043                            replPropertyMetaData in FL above w2k */
1044                         continue;
1045                 }
1046
1047                 m->attid   = dsdb_attribute_get_attid(sa, is_schema_nc);
1048                 m->version = 1;
1049                 if (m->attid == 0x20030) {
1050                         const struct ldb_val *rdn_val = ldb_dn_get_rdn_val(msg->dn);
1051                         const char* rdn;
1052
1053                         if (rdn_val == NULL) {
1054                                 ldb_oom(ldb);
1055                                 talloc_free(ac);
1056                                 return LDB_ERR_OPERATIONS_ERROR;
1057                         }
1058
1059                         rdn = (const char*)rdn_val->data;
1060                         if (strcmp(rdn, "Deleted Objects") == 0) {
1061                                 /*
1062                                  * Set the originating_change_time to 29/12/9999 at 23:59:59
1063                                  * as specified in MS-ADTS 7.1.1.4.2 Deleted Objects Container
1064                                  */
1065                                 m->originating_change_time      = DELETED_OBJECT_CONTAINER_CHANGE_TIME;
1066                         } else {
1067                                 m->originating_change_time      = now;
1068                         }
1069                 } else {
1070                         m->originating_change_time      = now;
1071                 }
1072                 m->originating_invocation_id    = *our_invocation_id;
1073                 m->originating_usn              = ac->seq_num;
1074                 m->local_usn                    = ac->seq_num;
1075                 ni++;
1076         }
1077
1078         /* fix meta data count */
1079         nmd.ctr.ctr1.count = ni;
1080
1081         /*
1082          * sort meta data array, and move the rdn attribute entry to the end
1083          */
1084         ret = replmd_replPropertyMetaDataCtr1_sort_and_verify(ldb, &nmd.ctr.ctr1, ac->schema, msg->dn);
1085         if (ret != LDB_SUCCESS) {
1086                 ldb_asprintf_errstring(ldb, "%s: error during direct ADD: %s", __func__, ldb_errstring(ldb));
1087                 talloc_free(ac);
1088                 return ret;
1089         }
1090
1091         /* generated NDR encoded values */
1092         ndr_err = ndr_push_struct_blob(&nmd_value, msg,
1093                                        &nmd,
1094                                        (ndr_push_flags_fn_t)ndr_push_replPropertyMetaDataBlob);
1095         if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
1096                 ldb_oom(ldb);
1097                 talloc_free(ac);
1098                 return LDB_ERR_OPERATIONS_ERROR;
1099         }
1100
1101         /*
1102          * add the autogenerated values
1103          */
1104         ret = dsdb_msg_add_guid(msg, &guid, "objectGUID");
1105         if (ret != LDB_SUCCESS) {
1106                 ldb_oom(ldb);
1107                 talloc_free(ac);
1108                 return ret;
1109         }
1110         ret = ldb_msg_add_string(msg, "whenChanged", time_str);
1111         if (ret != LDB_SUCCESS) {
1112                 ldb_oom(ldb);
1113                 talloc_free(ac);
1114                 return ret;
1115         }
1116         ret = samdb_msg_add_uint64(ldb, msg, msg, "uSNCreated", ac->seq_num);
1117         if (ret != LDB_SUCCESS) {
1118                 ldb_oom(ldb);
1119                 talloc_free(ac);
1120                 return ret;
1121         }
1122         ret = samdb_msg_add_uint64(ldb, msg, msg, "uSNChanged", ac->seq_num);
1123         if (ret != LDB_SUCCESS) {
1124                 ldb_oom(ldb);
1125                 talloc_free(ac);
1126                 return ret;
1127         }
1128         ret = ldb_msg_add_value(msg, "replPropertyMetaData", &nmd_value, NULL);
1129         if (ret != LDB_SUCCESS) {
1130                 ldb_oom(ldb);
1131                 talloc_free(ac);
1132                 return ret;
1133         }
1134
1135         /*
1136          * sort the attributes by attid before storing the object
1137          */
1138         replmd_ldb_message_sort(msg, ac->schema);
1139
1140         /*
1141          * Assert that we do have an objectClass
1142          */
1143         objectclass_el = ldb_msg_find_element(msg, "objectClass");
1144         if (objectclass_el == NULL) {
1145                 ldb_asprintf_errstring(ldb, __location__
1146                                        ": objectClass missing on %s\n",
1147                                        ldb_dn_get_linearized(msg->dn));
1148                 talloc_free(ac);
1149                 return LDB_ERR_OBJECT_CLASS_VIOLATION;
1150         }
1151         is_urgent = replmd_check_urgent_objectclass(objectclass_el,
1152                                                         REPL_URGENT_ON_CREATE);
1153
1154         ac->is_urgent = is_urgent;
1155         ret = ldb_build_add_req(&down_req, ldb, ac,
1156                                 msg,
1157                                 req->controls,
1158                                 ac, replmd_op_callback,
1159                                 req);
1160
1161         LDB_REQ_SET_LOCATION(down_req);
1162         if (ret != LDB_SUCCESS) {
1163                 talloc_free(ac);
1164                 return ret;
1165         }
1166
1167         /* current partition control is needed by "replmd_op_callback" */
1168         if (ldb_request_get_control(req, DSDB_CONTROL_CURRENT_PARTITION_OID) == NULL) {
1169                 ret = ldb_request_add_control(down_req,
1170                                               DSDB_CONTROL_CURRENT_PARTITION_OID,
1171                                               false, NULL);
1172                 if (ret != LDB_SUCCESS) {
1173                         talloc_free(ac);
1174                         return ret;
1175                 }
1176         }
1177
1178         if (functional_level == DS_DOMAIN_FUNCTION_2000) {
1179                 ret = ldb_request_add_control(down_req, DSDB_CONTROL_APPLY_LINKS, false, NULL);
1180                 if (ret != LDB_SUCCESS) {
1181                         talloc_free(ac);
1182                         return ret;
1183                 }
1184         }
1185
1186         /* mark the control done */
1187         if (control) {
1188                 control->critical = 0;
1189         }
1190         if (ldb_dn_compare_base(replmd_private->schema_dn, req->op.add.message->dn) != 0) {
1191
1192                 /* Update the usn in the SAMLDB_MSDS_INTID_OPAQUE opaque */
1193                 msds_intid_struct = (struct samldb_msds_intid_persistant *) ldb_get_opaque(ldb, SAMLDB_MSDS_INTID_OPAQUE);
1194                 if (msds_intid_struct) {
1195                         msds_intid_struct->usn = ac->seq_num;
1196                 }
1197         }
1198         /* go on with the call chain */
1199         return ldb_next_request(module, down_req);
1200 }
1201
1202
1203 /*
1204  * update the replPropertyMetaData for one element
1205  */
1206 static int replmd_update_rpmd_element(struct ldb_context *ldb,
1207                                       struct ldb_message *msg,
1208                                       struct ldb_message_element *el,
1209                                       struct ldb_message_element *old_el,
1210                                       struct replPropertyMetaDataBlob *omd,
1211                                       const struct dsdb_schema *schema,
1212                                       uint64_t *seq_num,
1213                                       const struct GUID *our_invocation_id,
1214                                       NTTIME now,
1215                                       bool is_schema_nc,
1216                                       struct ldb_request *req)
1217 {
1218         uint32_t i;
1219         const struct dsdb_attribute *a;
1220         struct replPropertyMetaData1 *md1;
1221         bool may_skip = false;
1222         uint32_t attid;
1223
1224         a = dsdb_attribute_by_lDAPDisplayName(schema, el->name);
1225         if (a == NULL) {
1226                 if (ldb_request_get_control(req, LDB_CONTROL_RELAX_OID)) {
1227                         /* allow this to make it possible for dbcheck
1228                            to remove bad attributes */
1229                         return LDB_SUCCESS;
1230                 }
1231
1232                 DEBUG(0,(__location__ ": Unable to find attribute %s in schema\n",
1233                          el->name));
1234                 return LDB_ERR_OPERATIONS_ERROR;
1235         }
1236
1237         attid = dsdb_attribute_get_attid(a, is_schema_nc);
1238
1239         if ((a->systemFlags & DS_FLAG_ATTR_NOT_REPLICATED) || (a->systemFlags & DS_FLAG_ATTR_IS_CONSTRUCTED)) {
1240                 return LDB_SUCCESS;
1241         }
1242
1243         /*
1244          * if the attribute's value haven't changed, and this isn't
1245          * just a delete of everything then return LDB_SUCCESS Unless
1246          * we have the provision control or if the attribute is
1247          * interSiteTopologyGenerator as this page explain:
1248          * http://support.microsoft.com/kb/224815 this attribute is
1249          * periodicaly written by the DC responsible for the intersite
1250          * generation in a given site
1251          *
1252          * Unchanged could be deleting or replacing an already-gone
1253          * thing with an unconstrained delete/empty replace or a
1254          * replace with the same value, but not an add with the same
1255          * value because that could be about adding a duplicate (which
1256          * is for someone else to error out on).
1257          */
1258         if (old_el != NULL && ldb_msg_element_equal_ordered(el, old_el)) {
1259                 if (LDB_FLAG_MOD_TYPE(el->flags) == LDB_FLAG_MOD_REPLACE) {
1260                         may_skip = true;
1261                 }
1262         } else if (old_el == NULL && el->num_values == 0) {
1263                 if (LDB_FLAG_MOD_TYPE(el->flags) == LDB_FLAG_MOD_REPLACE) {
1264                         may_skip = true;
1265                 } else if (LDB_FLAG_MOD_TYPE(el->flags) == LDB_FLAG_MOD_DELETE) {
1266                         may_skip = true;
1267                 }
1268         }
1269
1270         if (may_skip) {
1271                 if (strcmp(el->name, "interSiteTopologyGenerator") != 0 &&
1272                     !ldb_request_get_control(req, LDB_CONTROL_PROVISION_OID)) {
1273                         /*
1274                          * allow this to make it possible for dbcheck
1275                          * to rebuild broken metadata
1276                          */
1277                         return LDB_SUCCESS;
1278                 }
1279         }
1280
1281         for (i=0; i<omd->ctr.ctr1.count; i++) {
1282                 /*
1283                  * First check if we find it under the msDS-IntID,
1284                  * then check if we find it under the OID and
1285                  * prefixMap ID.
1286                  *
1287                  * This allows the administrator to simply re-write
1288                  * the attributes and so restore replication, which is
1289                  * likely what they will try to do.
1290                  */
1291                 if (attid == omd->ctr.ctr1.array[i].attid) {
1292                         break;
1293                 }
1294
1295                 if (a->attributeID_id == omd->ctr.ctr1.array[i].attid) {
1296                         break;
1297                 }
1298         }
1299
1300         if (a->linkID != 0 && dsdb_functional_level(ldb) > DS_DOMAIN_FUNCTION_2000) {
1301                 /* linked attributes are not stored in
1302                    replPropertyMetaData in FL above w2k, but we do
1303                    raise the seqnum for the object  */
1304                 if (*seq_num == 0 &&
1305                     ldb_sequence_number(ldb, LDB_SEQ_NEXT, seq_num) != LDB_SUCCESS) {
1306                         return LDB_ERR_OPERATIONS_ERROR;
1307                 }
1308                 return LDB_SUCCESS;
1309         }
1310
1311         if (i == omd->ctr.ctr1.count) {
1312                 /* we need to add a new one */
1313                 omd->ctr.ctr1.array = talloc_realloc(msg, omd->ctr.ctr1.array,
1314                                                      struct replPropertyMetaData1, omd->ctr.ctr1.count+1);
1315                 if (omd->ctr.ctr1.array == NULL) {
1316                         ldb_oom(ldb);
1317                         return LDB_ERR_OPERATIONS_ERROR;
1318                 }
1319                 omd->ctr.ctr1.count++;
1320                 ZERO_STRUCT(omd->ctr.ctr1.array[i]);
1321         }
1322
1323         /* Get a new sequence number from the backend. We only do this
1324          * if we have a change that requires a new
1325          * replPropertyMetaData element
1326          */
1327         if (*seq_num == 0) {
1328                 int ret = ldb_sequence_number(ldb, LDB_SEQ_NEXT, seq_num);
1329                 if (ret != LDB_SUCCESS) {
1330                         return LDB_ERR_OPERATIONS_ERROR;
1331                 }
1332         }
1333
1334         md1 = &omd->ctr.ctr1.array[i];
1335         md1->version++;
1336         md1->attid = attid;
1337         if (md1->attid == 0x20030) {
1338                 const struct ldb_val *rdn_val = ldb_dn_get_rdn_val(msg->dn);
1339                 const char* rdn;
1340
1341                 if (rdn_val == NULL) {
1342                         ldb_oom(ldb);
1343                         return LDB_ERR_OPERATIONS_ERROR;
1344                 }
1345
1346                 rdn = (const char*)rdn_val->data;
1347                 if (strcmp(rdn, "Deleted Objects") == 0) {
1348                         /*
1349                          * Set the originating_change_time to 29/12/9999 at 23:59:59
1350                          * as specified in MS-ADTS 7.1.1.4.2 Deleted Objects Container
1351                          */
1352                         md1->originating_change_time    = DELETED_OBJECT_CONTAINER_CHANGE_TIME;
1353                 } else {
1354                         md1->originating_change_time    = now;
1355                 }
1356         } else {
1357                 md1->originating_change_time    = now;
1358         }
1359         md1->originating_invocation_id = *our_invocation_id;
1360         md1->originating_usn           = *seq_num;
1361         md1->local_usn                 = *seq_num;
1362
1363         return LDB_SUCCESS;
1364 }
1365
1366 static uint64_t find_max_local_usn(struct replPropertyMetaDataBlob omd)
1367 {
1368         uint32_t count = omd.ctr.ctr1.count;
1369         uint64_t max = 0;
1370         uint32_t i;
1371         for (i=0; i < count; i++) {
1372                 struct replPropertyMetaData1 m = omd.ctr.ctr1.array[i];
1373                 if (max < m.local_usn) {
1374                         max = m.local_usn;
1375                 }
1376         }
1377         return max;
1378 }
1379
1380 /*
1381  * update the replPropertyMetaData object each time we modify an
1382  * object. This is needed for DRS replication, as the merge on the
1383  * client is based on this object
1384  */
1385 static int replmd_update_rpmd(struct ldb_module *module,
1386                               const struct dsdb_schema *schema,
1387                               struct ldb_request *req,
1388                               const char * const *rename_attrs,
1389                               struct ldb_message *msg, uint64_t *seq_num,
1390                               time_t t, bool is_schema_nc,
1391                               bool *is_urgent, bool *rodc)
1392 {
1393         const struct ldb_val *omd_value;
1394         enum ndr_err_code ndr_err;
1395         struct replPropertyMetaDataBlob omd;
1396         unsigned int i;
1397         NTTIME now;
1398         const struct GUID *our_invocation_id;
1399         int ret;
1400         const char * const *attrs = NULL;
1401         const char * const attrs1[] = { "replPropertyMetaData", "*", NULL };
1402         const char * const attrs2[] = { "uSNChanged", "objectClass", "instanceType", NULL };
1403         struct ldb_result *res;
1404         struct ldb_context *ldb;
1405         struct ldb_message_element *objectclass_el;
1406         enum urgent_situation situation;
1407         bool rmd_is_provided;
1408         bool rmd_is_just_resorted = false;
1409
1410         if (rename_attrs) {
1411                 attrs = rename_attrs;
1412         } else {
1413                 attrs = attrs1;
1414         }
1415
1416         ldb = ldb_module_get_ctx(module);
1417
1418         our_invocation_id = samdb_ntds_invocation_id(ldb);
1419         if (!our_invocation_id) {
1420                 /* this happens during an initial vampire while
1421                    updating the schema */
1422                 DEBUG(5,("No invocationID - skipping replPropertyMetaData update\n"));
1423                 return LDB_SUCCESS;
1424         }
1425
1426         unix_to_nt_time(&now, t);
1427
1428         if (ldb_request_get_control(req, DSDB_CONTROL_CHANGEREPLMETADATA_OID)) {
1429                 rmd_is_provided = true;
1430                 if (ldb_request_get_control(req, DSDB_CONTROL_CHANGEREPLMETADATA_RESORT_OID)) {
1431                         rmd_is_just_resorted = true;
1432                 }
1433         } else {
1434                 rmd_is_provided = false;
1435         }
1436
1437         /* if isDeleted is present and is TRUE, then we consider we are deleting,
1438          * otherwise we consider we are updating */
1439         if (ldb_msg_check_string_attribute(msg, "isDeleted", "TRUE")) {
1440                 situation = REPL_URGENT_ON_DELETE;
1441         } else if (rename_attrs) {
1442                 situation = REPL_URGENT_ON_CREATE | REPL_URGENT_ON_DELETE;
1443         } else {
1444                 situation = REPL_URGENT_ON_UPDATE;
1445         }
1446
1447         if (rmd_is_provided) {
1448                 /* In this case the change_replmetadata control was supplied */
1449                 /* We check that it's the only attribute that is provided
1450                  * (it's a rare case so it's better to keep the code simplier)
1451                  * We also check that the highest local_usn is bigger or the same as
1452                  * uSNChanged. */
1453                 uint64_t db_seq;
1454                 if( msg->num_elements != 1 ||
1455                         strncmp(msg->elements[0].name,
1456                                 "replPropertyMetaData", 20) ) {
1457                         DEBUG(0,(__location__ ": changereplmetada control called without "\
1458                                 "a specified replPropertyMetaData attribute or with others\n"));
1459                         return LDB_ERR_OPERATIONS_ERROR;
1460                 }
1461                 if (situation != REPL_URGENT_ON_UPDATE) {
1462                         DEBUG(0,(__location__ ": changereplmetada control can't be called when deleting an object\n"));
1463                         return LDB_ERR_OPERATIONS_ERROR;
1464                 }
1465                 omd_value = ldb_msg_find_ldb_val(msg, "replPropertyMetaData");
1466                 if (!omd_value) {
1467                         DEBUG(0,(__location__ ": replPropertyMetaData was not specified for Object %s\n",
1468                                  ldb_dn_get_linearized(msg->dn)));
1469                         return LDB_ERR_OPERATIONS_ERROR;
1470                 }
1471                 ndr_err = ndr_pull_struct_blob(omd_value, msg, &omd,
1472                                                (ndr_pull_flags_fn_t)ndr_pull_replPropertyMetaDataBlob);
1473                 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
1474                         DEBUG(0,(__location__ ": Failed to parse replPropertyMetaData for %s\n",
1475                                  ldb_dn_get_linearized(msg->dn)));
1476                         return LDB_ERR_OPERATIONS_ERROR;
1477                 }
1478
1479                 ret = dsdb_module_search_dn(module, msg, &res, msg->dn, attrs2,
1480                                             DSDB_FLAG_NEXT_MODULE |
1481                                             DSDB_SEARCH_SHOW_RECYCLED |
1482                                             DSDB_SEARCH_SHOW_EXTENDED_DN |
1483                                             DSDB_SEARCH_SHOW_DN_IN_STORAGE_FORMAT |
1484                                             DSDB_SEARCH_REVEAL_INTERNALS, req);
1485
1486                 if (ret != LDB_SUCCESS) {
1487                         return ret;
1488                 }
1489
1490                 if (rmd_is_just_resorted == false) {
1491                         *seq_num = find_max_local_usn(omd);
1492
1493                         db_seq = ldb_msg_find_attr_as_uint64(res->msgs[0], "uSNChanged", 0);
1494
1495                         /*
1496                          * The test here now allows for a new
1497                          * replPropertyMetaData with no change, if was
1498                          * just dbcheck re-sorting the values.
1499                          */
1500                         if (*seq_num <= db_seq) {
1501                                 DEBUG(0,(__location__ ": changereplmetada control provided but max(local_usn)" \
1502                                          " is less than uSNChanged (max = %lld uSNChanged = %lld)\n",
1503                                          (long long)*seq_num, (long long)db_seq));
1504                                 return LDB_ERR_OPERATIONS_ERROR;
1505                         }
1506                 }
1507
1508         } else {
1509                 /* search for the existing replPropertyMetaDataBlob. We need
1510                  * to use REVEAL and ask for DNs in storage format to support
1511                  * the check for values being the same in
1512                  * replmd_update_rpmd_element()
1513                  */
1514                 ret = dsdb_module_search_dn(module, msg, &res, msg->dn, attrs,
1515                                             DSDB_FLAG_NEXT_MODULE |
1516                                             DSDB_SEARCH_SHOW_RECYCLED |
1517                                             DSDB_SEARCH_SHOW_EXTENDED_DN |
1518                                             DSDB_SEARCH_SHOW_DN_IN_STORAGE_FORMAT |
1519                                             DSDB_SEARCH_REVEAL_INTERNALS, req);
1520                 if (ret != LDB_SUCCESS) {
1521                         return ret;
1522                 }
1523
1524                 omd_value = ldb_msg_find_ldb_val(res->msgs[0], "replPropertyMetaData");
1525                 if (!omd_value) {
1526                         DEBUG(0,(__location__ ": Object %s does not have a replPropertyMetaData attribute\n",
1527                                  ldb_dn_get_linearized(msg->dn)));
1528                         return LDB_ERR_OPERATIONS_ERROR;
1529                 }
1530
1531                 ndr_err = ndr_pull_struct_blob(omd_value, msg, &omd,
1532                                                (ndr_pull_flags_fn_t)ndr_pull_replPropertyMetaDataBlob);
1533                 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
1534                         DEBUG(0,(__location__ ": Failed to parse replPropertyMetaData for %s\n",
1535                                  ldb_dn_get_linearized(msg->dn)));
1536                         return LDB_ERR_OPERATIONS_ERROR;
1537                 }
1538
1539                 if (omd.version != 1) {
1540                         DEBUG(0,(__location__ ": bad version %u in replPropertyMetaData for %s\n",
1541                                  omd.version, ldb_dn_get_linearized(msg->dn)));
1542                         return LDB_ERR_OPERATIONS_ERROR;
1543                 }
1544
1545                 for (i=0; i<msg->num_elements; i++) {
1546                         struct ldb_message_element *old_el;
1547                         old_el = ldb_msg_find_element(res->msgs[0], msg->elements[i].name);
1548                         ret = replmd_update_rpmd_element(ldb, msg, &msg->elements[i], old_el, &omd, schema, seq_num,
1549                                                          our_invocation_id,
1550                                                          now, is_schema_nc,
1551                                                          req);
1552                         if (ret != LDB_SUCCESS) {
1553                                 return ret;
1554                         }
1555
1556                         if (!*is_urgent && (situation == REPL_URGENT_ON_UPDATE)) {
1557                                 *is_urgent = replmd_check_urgent_attribute(&msg->elements[i]);
1558                         }
1559
1560                 }
1561         }
1562
1563         /*
1564          * Assert that we have an objectClass attribute - this is major
1565          * corruption if we don't have this!
1566          */
1567         objectclass_el = ldb_msg_find_element(res->msgs[0], "objectClass");
1568         if (objectclass_el != NULL) {
1569                 /*
1570                  * Now check if this objectClass means we need to do urgent replication
1571                  */
1572                 if (!*is_urgent && replmd_check_urgent_objectclass(objectclass_el,
1573                                                                    situation)) {
1574                         *is_urgent = true;
1575                 }
1576         } else if (!ldb_request_get_control(req, DSDB_CONTROL_DBCHECK)) {
1577                 ldb_asprintf_errstring(ldb, __location__
1578                                        ": objectClass missing on %s\n",
1579                                        ldb_dn_get_linearized(msg->dn));
1580                 return LDB_ERR_OBJECT_CLASS_VIOLATION;
1581         }
1582
1583         /*
1584          * replmd_update_rpmd_element has done an update if the
1585          * seq_num is set
1586          */
1587         if (*seq_num != 0 || rmd_is_just_resorted == true) {
1588                 struct ldb_val *md_value;
1589                 struct ldb_message_element *el;
1590
1591                 /*if we are RODC and this is a DRSR update then its ok*/
1592                 if (!ldb_request_get_control(req, DSDB_CONTROL_REPLICATED_UPDATE_OID)
1593                     && !ldb_request_get_control(req, DSDB_CONTROL_DBCHECK_MODIFY_RO_REPLICA)) {
1594                         unsigned instanceType;
1595
1596                         ret = samdb_rodc(ldb, rodc);
1597                         if (ret != LDB_SUCCESS) {
1598                                 DEBUG(4, (__location__ ": unable to tell if we are an RODC\n"));
1599                         } else if (*rodc) {
1600                                 ldb_set_errstring(ldb, "RODC modify is forbidden!");
1601                                 return LDB_ERR_REFERRAL;
1602                         }
1603
1604                         instanceType = ldb_msg_find_attr_as_uint(res->msgs[0], "instanceType", INSTANCE_TYPE_WRITE);
1605                         if (!(instanceType & INSTANCE_TYPE_WRITE)) {
1606                                 return ldb_error(ldb, LDB_ERR_UNWILLING_TO_PERFORM,
1607                                                  "cannot change replicated attribute on partial replica");
1608                         }
1609                 }
1610
1611                 md_value = talloc(msg, struct ldb_val);
1612                 if (md_value == NULL) {
1613                         ldb_oom(ldb);
1614                         return LDB_ERR_OPERATIONS_ERROR;
1615                 }
1616
1617                 ret = replmd_replPropertyMetaDataCtr1_sort_and_verify(ldb, &omd.ctr.ctr1, schema, msg->dn);
1618                 if (ret != LDB_SUCCESS) {
1619                         ldb_asprintf_errstring(ldb, "%s: %s", __func__, ldb_errstring(ldb));
1620                         return ret;
1621                 }
1622
1623                 ndr_err = ndr_push_struct_blob(md_value, msg, &omd,
1624                                                (ndr_push_flags_fn_t)ndr_push_replPropertyMetaDataBlob);
1625                 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
1626                         DEBUG(0,(__location__ ": Failed to marshall replPropertyMetaData for %s\n",
1627                                  ldb_dn_get_linearized(msg->dn)));
1628                         return LDB_ERR_OPERATIONS_ERROR;
1629                 }
1630
1631                 ret = ldb_msg_add_empty(msg, "replPropertyMetaData", LDB_FLAG_MOD_REPLACE, &el);
1632                 if (ret != LDB_SUCCESS) {
1633                         DEBUG(0,(__location__ ": Failed to add updated replPropertyMetaData %s\n",
1634                                  ldb_dn_get_linearized(msg->dn)));
1635                         return ret;
1636                 }
1637
1638                 el->num_values = 1;
1639                 el->values = md_value;
1640         }
1641
1642         return LDB_SUCCESS;
1643 }
1644
1645 struct parsed_dn {
1646         struct dsdb_dn *dsdb_dn;
1647         struct GUID *guid;
1648         struct ldb_val *v;
1649 };
1650
1651 static int parsed_dn_compare(struct parsed_dn *pdn1, struct parsed_dn *pdn2)
1652 {
1653         return GUID_compare(pdn1->guid, pdn2->guid);
1654 }
1655
1656 static struct parsed_dn *parsed_dn_find(struct parsed_dn *pdn,
1657                                         unsigned int count, struct GUID *guid,
1658                                         struct ldb_dn *dn)
1659 {
1660         struct parsed_dn *ret;
1661         unsigned int i;
1662         if (dn && GUID_all_zero(guid)) {
1663                 /* when updating a link using DRS, we sometimes get a
1664                    NULL GUID. We then need to try and match by DN */
1665                 for (i=0; i<count; i++) {
1666                         if (ldb_dn_compare(pdn[i].dsdb_dn->dn, dn) == 0) {
1667                                 dsdb_get_extended_dn_guid(pdn[i].dsdb_dn->dn, guid, "GUID");
1668                                 return &pdn[i];
1669                         }
1670                 }
1671                 return NULL;
1672         }
1673         BINARY_ARRAY_SEARCH(pdn, count, guid, guid, GUID_compare, ret);
1674         return ret;
1675 }
1676
1677 /*
1678   get a series of message element values as an array of DNs and GUIDs
1679   the result is sorted by GUID
1680  */
1681 static int get_parsed_dns(struct ldb_module *module, TALLOC_CTX *mem_ctx,
1682                           struct ldb_message_element *el, struct parsed_dn **pdn,
1683                           const char *ldap_oid, struct ldb_request *parent)
1684 {
1685         unsigned int i;
1686         struct ldb_context *ldb = ldb_module_get_ctx(module);
1687
1688         if (el == NULL) {
1689                 *pdn = NULL;
1690                 return LDB_SUCCESS;
1691         }
1692
1693         (*pdn) = talloc_array(mem_ctx, struct parsed_dn, el->num_values);
1694         if (!*pdn) {
1695                 ldb_module_oom(module);
1696                 return LDB_ERR_OPERATIONS_ERROR;
1697         }
1698
1699         for (i=0; i<el->num_values; i++) {
1700                 struct ldb_val *v = &el->values[i];
1701                 NTSTATUS status;
1702                 struct ldb_dn *dn;
1703                 struct parsed_dn *p;
1704
1705                 p = &(*pdn)[i];
1706
1707                 p->dsdb_dn = dsdb_dn_parse(*pdn, ldb, v, ldap_oid);
1708                 if (p->dsdb_dn == NULL) {
1709                         return LDB_ERR_INVALID_DN_SYNTAX;
1710                 }
1711
1712                 dn = p->dsdb_dn->dn;
1713
1714                 p->guid = talloc(*pdn, struct GUID);
1715                 if (p->guid == NULL) {
1716                         ldb_module_oom(module);
1717                         return LDB_ERR_OPERATIONS_ERROR;
1718                 }
1719
1720                 status = dsdb_get_extended_dn_guid(dn, p->guid, "GUID");
1721                 if (NT_STATUS_EQUAL(status, NT_STATUS_OBJECT_NAME_NOT_FOUND)) {
1722                         /* we got a DN without a GUID - go find the GUID */
1723                         int ret = dsdb_module_guid_by_dn(module, dn, p->guid, parent);
1724                         if (ret != LDB_SUCCESS) {
1725                                 ldb_asprintf_errstring(ldb, "Unable to find GUID for DN %s\n",
1726                                                        ldb_dn_get_linearized(dn));
1727                                 if (ret == LDB_ERR_NO_SUCH_OBJECT &&
1728                                     LDB_FLAG_MOD_TYPE(el->flags) == LDB_FLAG_MOD_DELETE &&
1729                                     ldb_attr_cmp(el->name, "member") == 0) {
1730                                         return LDB_ERR_UNWILLING_TO_PERFORM;
1731                                 }
1732                                 return ret;
1733                         }
1734                         ret = dsdb_set_extended_dn_guid(dn, p->guid, "GUID");
1735                         if (ret != LDB_SUCCESS) {
1736                                 return ret;
1737                         }
1738                 } else if (!NT_STATUS_IS_OK(status)) {
1739                         return LDB_ERR_OPERATIONS_ERROR;
1740                 }
1741
1742                 /* keep a pointer to the original ldb_val */
1743                 p->v = v;
1744         }
1745
1746         TYPESAFE_QSORT(*pdn, el->num_values, parsed_dn_compare);
1747
1748         return LDB_SUCCESS;
1749 }
1750
1751 /*
1752   build a new extended DN, including all meta data fields
1753
1754   RMD_FLAGS           = DSDB_RMD_FLAG_* bits
1755   RMD_ADDTIME         = originating_add_time
1756   RMD_INVOCID         = originating_invocation_id
1757   RMD_CHANGETIME      = originating_change_time
1758   RMD_ORIGINATING_USN = originating_usn
1759   RMD_LOCAL_USN       = local_usn
1760   RMD_VERSION         = version
1761  */
1762 static int replmd_build_la_val(TALLOC_CTX *mem_ctx, struct ldb_val *v, struct dsdb_dn *dsdb_dn,
1763                                const struct GUID *invocation_id, uint64_t seq_num,
1764                                uint64_t local_usn, NTTIME nttime, uint32_t version, bool deleted)
1765 {
1766         struct ldb_dn *dn = dsdb_dn->dn;
1767         const char *tstring, *usn_string, *flags_string;
1768         struct ldb_val tval;
1769         struct ldb_val iid;
1770         struct ldb_val usnv, local_usnv;
1771         struct ldb_val vers, flagsv;
1772         NTSTATUS status;
1773         int ret;
1774         const char *dnstring;
1775         char *vstring;
1776         uint32_t rmd_flags = deleted?DSDB_RMD_FLAG_DELETED:0;
1777
1778         tstring = talloc_asprintf(mem_ctx, "%llu", (unsigned long long)nttime);
1779         if (!tstring) {
1780                 return LDB_ERR_OPERATIONS_ERROR;
1781         }
1782         tval = data_blob_string_const(tstring);
1783
1784         usn_string = talloc_asprintf(mem_ctx, "%llu", (unsigned long long)seq_num);
1785         if (!usn_string) {
1786                 return LDB_ERR_OPERATIONS_ERROR;
1787         }
1788         usnv = data_blob_string_const(usn_string);
1789
1790         usn_string = talloc_asprintf(mem_ctx, "%llu", (unsigned long long)local_usn);
1791         if (!usn_string) {
1792                 return LDB_ERR_OPERATIONS_ERROR;
1793         }
1794         local_usnv = data_blob_string_const(usn_string);
1795
1796         vstring = talloc_asprintf(mem_ctx, "%lu", (unsigned long)version);
1797         if (!vstring) {
1798                 return LDB_ERR_OPERATIONS_ERROR;
1799         }
1800         vers = data_blob_string_const(vstring);
1801
1802         status = GUID_to_ndr_blob(invocation_id, dn, &iid);
1803         if (!NT_STATUS_IS_OK(status)) {
1804                 return LDB_ERR_OPERATIONS_ERROR;
1805         }
1806
1807         flags_string = talloc_asprintf(mem_ctx, "%u", rmd_flags);
1808         if (!flags_string) {
1809                 return LDB_ERR_OPERATIONS_ERROR;
1810         }
1811         flagsv = data_blob_string_const(flags_string);
1812
1813         ret = ldb_dn_set_extended_component(dn, "RMD_FLAGS", &flagsv);
1814         if (ret != LDB_SUCCESS) return ret;
1815         ret = ldb_dn_set_extended_component(dn, "RMD_ADDTIME", &tval);
1816         if (ret != LDB_SUCCESS) return ret;
1817         ret = ldb_dn_set_extended_component(dn, "RMD_INVOCID", &iid);
1818         if (ret != LDB_SUCCESS) return ret;
1819         ret = ldb_dn_set_extended_component(dn, "RMD_CHANGETIME", &tval);
1820         if (ret != LDB_SUCCESS) return ret;
1821         ret = ldb_dn_set_extended_component(dn, "RMD_LOCAL_USN", &local_usnv);
1822         if (ret != LDB_SUCCESS) return ret;
1823         ret = ldb_dn_set_extended_component(dn, "RMD_ORIGINATING_USN", &usnv);
1824         if (ret != LDB_SUCCESS) return ret;
1825         ret = ldb_dn_set_extended_component(dn, "RMD_VERSION", &vers);
1826         if (ret != LDB_SUCCESS) return ret;
1827
1828         dnstring = dsdb_dn_get_extended_linearized(mem_ctx, dsdb_dn, 1);
1829         if (dnstring == NULL) {
1830                 return LDB_ERR_OPERATIONS_ERROR;
1831         }
1832         *v = data_blob_string_const(dnstring);
1833
1834         return LDB_SUCCESS;
1835 }
1836
1837 static int replmd_update_la_val(TALLOC_CTX *mem_ctx, struct ldb_val *v, struct dsdb_dn *dsdb_dn,
1838                                 struct dsdb_dn *old_dsdb_dn, const struct GUID *invocation_id,
1839                                 uint64_t seq_num, uint64_t local_usn, NTTIME nttime,
1840                                 uint32_t version, bool deleted);
1841
1842 /*
1843   check if any links need upgrading from w2k format
1844
1845   The parent_ctx is the ldb_message_element which contains the values array that dns[i].v points at, and which should be used for allocating any new value.
1846  */
1847 static int replmd_check_upgrade_links(struct parsed_dn *dns, uint32_t count, struct ldb_message_element *parent_ctx, const struct GUID *invocation_id)
1848 {
1849         uint32_t i;
1850         for (i=0; i<count; i++) {
1851                 NTSTATUS status;
1852                 uint32_t version;
1853                 int ret;
1854
1855                 status = dsdb_get_extended_dn_uint32(dns[i].dsdb_dn->dn, &version, "RMD_VERSION");
1856                 if (!NT_STATUS_EQUAL(status, NT_STATUS_OBJECT_NAME_NOT_FOUND)) {
1857                         continue;
1858                 }
1859
1860                 /* it's an old one that needs upgrading */
1861                 ret = replmd_update_la_val(parent_ctx->values, dns[i].v, dns[i].dsdb_dn, dns[i].dsdb_dn, invocation_id,
1862                                            1, 1, 0, 0, false);
1863                 if (ret != LDB_SUCCESS) {
1864                         return ret;
1865                 }
1866         }
1867         return LDB_SUCCESS;
1868 }
1869
1870 /*
1871   update an extended DN, including all meta data fields
1872
1873   see replmd_build_la_val for value names
1874  */
1875 static int replmd_update_la_val(TALLOC_CTX *mem_ctx, struct ldb_val *v, struct dsdb_dn *dsdb_dn,
1876                                 struct dsdb_dn *old_dsdb_dn, const struct GUID *invocation_id,
1877                                 uint64_t usn, uint64_t local_usn, NTTIME nttime,
1878                                 uint32_t version, bool deleted)
1879 {
1880         struct ldb_dn *dn = dsdb_dn->dn;
1881         const char *tstring, *usn_string, *flags_string;
1882         struct ldb_val tval;
1883         struct ldb_val iid;
1884         struct ldb_val usnv, local_usnv;
1885         struct ldb_val vers, flagsv;
1886         const struct ldb_val *old_addtime;
1887         uint32_t old_version;
1888         NTSTATUS status;
1889         int ret;
1890         const char *dnstring;
1891         char *vstring;
1892         uint32_t rmd_flags = deleted?DSDB_RMD_FLAG_DELETED:0;
1893
1894         tstring = talloc_asprintf(mem_ctx, "%llu", (unsigned long long)nttime);
1895         if (!tstring) {
1896                 return LDB_ERR_OPERATIONS_ERROR;
1897         }
1898         tval = data_blob_string_const(tstring);
1899
1900         usn_string = talloc_asprintf(mem_ctx, "%llu", (unsigned long long)usn);
1901         if (!usn_string) {
1902                 return LDB_ERR_OPERATIONS_ERROR;
1903         }
1904         usnv = data_blob_string_const(usn_string);
1905
1906         usn_string = talloc_asprintf(mem_ctx, "%llu", (unsigned long long)local_usn);
1907         if (!usn_string) {
1908                 return LDB_ERR_OPERATIONS_ERROR;
1909         }
1910         local_usnv = data_blob_string_const(usn_string);
1911
1912         status = GUID_to_ndr_blob(invocation_id, dn, &iid);
1913         if (!NT_STATUS_IS_OK(status)) {
1914                 return LDB_ERR_OPERATIONS_ERROR;
1915         }
1916
1917         flags_string = talloc_asprintf(mem_ctx, "%u", rmd_flags);
1918         if (!flags_string) {
1919                 return LDB_ERR_OPERATIONS_ERROR;
1920         }
1921         flagsv = data_blob_string_const(flags_string);
1922
1923         ret = ldb_dn_set_extended_component(dn, "RMD_FLAGS", &flagsv);
1924         if (ret != LDB_SUCCESS) return ret;
1925
1926         /* get the ADDTIME from the original */
1927         old_addtime = ldb_dn_get_extended_component(old_dsdb_dn->dn, "RMD_ADDTIME");
1928         if (old_addtime == NULL) {
1929                 old_addtime = &tval;
1930         }
1931         if (dsdb_dn != old_dsdb_dn ||
1932             ldb_dn_get_extended_component(dn, "RMD_ADDTIME") == NULL) {
1933                 ret = ldb_dn_set_extended_component(dn, "RMD_ADDTIME", old_addtime);
1934                 if (ret != LDB_SUCCESS) return ret;
1935         }
1936
1937         /* use our invocation id */
1938         ret = ldb_dn_set_extended_component(dn, "RMD_INVOCID", &iid);
1939         if (ret != LDB_SUCCESS) return ret;
1940
1941         /* changetime is the current time */
1942         ret = ldb_dn_set_extended_component(dn, "RMD_CHANGETIME", &tval);
1943         if (ret != LDB_SUCCESS) return ret;
1944
1945         /* update the USN */
1946         ret = ldb_dn_set_extended_component(dn, "RMD_ORIGINATING_USN", &usnv);
1947         if (ret != LDB_SUCCESS) return ret;
1948
1949         ret = ldb_dn_set_extended_component(dn, "RMD_LOCAL_USN", &local_usnv);
1950         if (ret != LDB_SUCCESS) return ret;
1951
1952         /* increase the version by 1 */
1953         status = dsdb_get_extended_dn_uint32(old_dsdb_dn->dn, &old_version, "RMD_VERSION");
1954         if (NT_STATUS_IS_OK(status) && old_version >= version) {
1955                 version = old_version+1;
1956         }
1957         vstring = talloc_asprintf(dn, "%lu", (unsigned long)version);
1958         vers = data_blob_string_const(vstring);
1959         ret = ldb_dn_set_extended_component(dn, "RMD_VERSION", &vers);
1960         if (ret != LDB_SUCCESS) return ret;
1961
1962         dnstring = dsdb_dn_get_extended_linearized(mem_ctx, dsdb_dn, 1);
1963         if (dnstring == NULL) {
1964                 return LDB_ERR_OPERATIONS_ERROR;
1965         }
1966         *v = data_blob_string_const(dnstring);
1967
1968         return LDB_SUCCESS;
1969 }
1970
1971 /*
1972   handle adding a linked attribute
1973  */
1974 static int replmd_modify_la_add(struct ldb_module *module,
1975                                 const struct dsdb_schema *schema,
1976                                 struct ldb_message *msg,
1977                                 struct ldb_message_element *el,
1978                                 struct ldb_message_element *old_el,
1979                                 const struct dsdb_attribute *schema_attr,
1980                                 uint64_t seq_num,
1981                                 time_t t,
1982                                 struct GUID *msg_guid,
1983                                 struct ldb_request *parent)
1984 {
1985         unsigned int i;
1986         struct parsed_dn *dns, *old_dns;
1987         TALLOC_CTX *tmp_ctx = talloc_new(msg);
1988         int ret;
1989         struct ldb_val *new_values = NULL;
1990         unsigned int num_new_values = 0;
1991         unsigned old_num_values = old_el?old_el->num_values:0;
1992         const struct GUID *invocation_id;
1993         struct ldb_context *ldb = ldb_module_get_ctx(module);
1994         NTTIME now;
1995
1996         unix_to_nt_time(&now, t);
1997
1998         ret = get_parsed_dns(module, tmp_ctx, el, &dns, schema_attr->syntax->ldap_oid, parent);
1999         if (ret != LDB_SUCCESS) {
2000                 talloc_free(tmp_ctx);
2001                 return ret;
2002         }
2003
2004         ret = get_parsed_dns(module, tmp_ctx, old_el, &old_dns, schema_attr->syntax->ldap_oid, parent);
2005         if (ret != LDB_SUCCESS) {
2006                 talloc_free(tmp_ctx);
2007                 return ret;
2008         }
2009
2010         invocation_id = samdb_ntds_invocation_id(ldb);
2011         if (!invocation_id) {
2012                 talloc_free(tmp_ctx);
2013                 return LDB_ERR_OPERATIONS_ERROR;
2014         }
2015
2016         ret = replmd_check_upgrade_links(old_dns, old_num_values, old_el, invocation_id);
2017         if (ret != LDB_SUCCESS) {
2018                 talloc_free(tmp_ctx);
2019                 return ret;
2020         }
2021
2022         /* for each new value, see if it exists already with the same GUID */
2023         for (i=0; i<el->num_values; i++) {
2024                 struct parsed_dn *p = parsed_dn_find(old_dns, old_num_values, dns[i].guid, NULL);
2025                 if (p == NULL) {
2026                         /* this is a new linked attribute value */
2027                         new_values = talloc_realloc(tmp_ctx, new_values, struct ldb_val, num_new_values+1);
2028                         if (new_values == NULL) {
2029                                 ldb_module_oom(module);
2030                                 talloc_free(tmp_ctx);
2031                                 return LDB_ERR_OPERATIONS_ERROR;
2032                         }
2033                         ret = replmd_build_la_val(new_values, &new_values[num_new_values], dns[i].dsdb_dn,
2034                                                   invocation_id, seq_num, seq_num, now, 0, false);
2035                         if (ret != LDB_SUCCESS) {
2036                                 talloc_free(tmp_ctx);
2037                                 return ret;
2038                         }
2039                         num_new_values++;
2040                 } else {
2041                         /* this is only allowed if the GUID was
2042                            previously deleted. */
2043                         uint32_t rmd_flags = dsdb_dn_rmd_flags(p->dsdb_dn->dn);
2044
2045                         if (!(rmd_flags & DSDB_RMD_FLAG_DELETED)) {
2046                                 ldb_asprintf_errstring(ldb, "Attribute %s already exists for target GUID %s",
2047                                                        el->name, GUID_string(tmp_ctx, p->guid));
2048                                 talloc_free(tmp_ctx);
2049                                 /* error codes for 'member' need to be
2050                                    special cased */
2051                                 if (ldb_attr_cmp(el->name, "member") == 0) {
2052                                         return LDB_ERR_ENTRY_ALREADY_EXISTS;
2053                                 } else {
2054                                         return LDB_ERR_ATTRIBUTE_OR_VALUE_EXISTS;
2055                                 }
2056                         }
2057                         ret = replmd_update_la_val(old_el->values, p->v, dns[i].dsdb_dn, p->dsdb_dn,
2058                                                    invocation_id, seq_num, seq_num, now, 0, false);
2059                         if (ret != LDB_SUCCESS) {
2060                                 talloc_free(tmp_ctx);
2061                                 return ret;
2062                         }
2063                 }
2064
2065                 ret = replmd_add_backlink(module, schema, msg_guid, dns[i].guid, true, schema_attr, true);
2066                 if (ret != LDB_SUCCESS) {
2067                         talloc_free(tmp_ctx);
2068                         return ret;
2069                 }
2070         }
2071
2072         /* add the new ones on to the end of the old values, constructing a new el->values */
2073         el->values = talloc_realloc(msg->elements, old_el?old_el->values:NULL,
2074                                     struct ldb_val,
2075                                     old_num_values+num_new_values);
2076         if (el->values == NULL) {
2077                 ldb_module_oom(module);
2078                 return LDB_ERR_OPERATIONS_ERROR;
2079         }
2080
2081         memcpy(&el->values[old_num_values], new_values, num_new_values*sizeof(struct ldb_val));
2082         el->num_values = old_num_values + num_new_values;
2083
2084         talloc_steal(msg->elements, el->values);
2085         talloc_steal(el->values, new_values);
2086
2087         talloc_free(tmp_ctx);
2088
2089         /* we now tell the backend to replace all existing values
2090            with the one we have constructed */
2091         el->flags = LDB_FLAG_MOD_REPLACE;
2092
2093         return LDB_SUCCESS;
2094 }
2095
2096
2097 /*
2098   handle deleting all active linked attributes
2099  */
2100 static int replmd_modify_la_delete(struct ldb_module *module,
2101                                    const struct dsdb_schema *schema,
2102                                    struct ldb_message *msg,
2103                                    struct ldb_message_element *el,
2104                                    struct ldb_message_element *old_el,
2105                                    const struct dsdb_attribute *schema_attr,
2106                                    uint64_t seq_num,
2107                                    time_t t,
2108                                    struct GUID *msg_guid,
2109                                    struct ldb_request *parent)
2110 {
2111         unsigned int i;
2112         struct parsed_dn *dns, *old_dns;
2113         TALLOC_CTX *tmp_ctx = talloc_new(msg);
2114         int ret;
2115         const struct GUID *invocation_id;
2116         struct ldb_context *ldb = ldb_module_get_ctx(module);
2117         NTTIME now;
2118
2119         unix_to_nt_time(&now, t);
2120
2121         /* check if there is nothing to delete */
2122         if ((!old_el || old_el->num_values == 0) &&
2123             el->num_values == 0) {
2124                 return LDB_SUCCESS;
2125         }
2126
2127         if (!old_el || old_el->num_values == 0) {
2128                 return LDB_ERR_NO_SUCH_ATTRIBUTE;
2129         }
2130
2131         ret = get_parsed_dns(module, tmp_ctx, el, &dns, schema_attr->syntax->ldap_oid, parent);
2132         if (ret != LDB_SUCCESS) {
2133                 talloc_free(tmp_ctx);
2134                 return ret;
2135         }
2136
2137         ret = get_parsed_dns(module, tmp_ctx, old_el, &old_dns, schema_attr->syntax->ldap_oid, parent);
2138         if (ret != LDB_SUCCESS) {
2139                 talloc_free(tmp_ctx);
2140                 return ret;
2141         }
2142
2143         invocation_id = samdb_ntds_invocation_id(ldb);
2144         if (!invocation_id) {
2145                 return LDB_ERR_OPERATIONS_ERROR;
2146         }
2147
2148         ret = replmd_check_upgrade_links(old_dns, old_el->num_values, old_el, invocation_id);
2149         if (ret != LDB_SUCCESS) {
2150                 talloc_free(tmp_ctx);
2151                 return ret;
2152         }
2153
2154         el->values = NULL;
2155
2156         /* see if we are being asked to delete any links that
2157            don't exist or are already deleted */
2158         for (i=0; i<el->num_values; i++) {
2159                 struct parsed_dn *p = &dns[i];
2160                 struct parsed_dn *p2;
2161                 uint32_t rmd_flags;
2162
2163                 p2 = parsed_dn_find(old_dns, old_el->num_values, p->guid, NULL);
2164                 if (!p2) {
2165                         ldb_asprintf_errstring(ldb, "Attribute %s doesn't exist for target GUID %s",
2166                                                el->name, GUID_string(tmp_ctx, p->guid));
2167                         if (ldb_attr_cmp(el->name, "member") == 0) {
2168                                 return LDB_ERR_UNWILLING_TO_PERFORM;
2169                         } else {
2170                                 return LDB_ERR_NO_SUCH_ATTRIBUTE;
2171                         }
2172                 }
2173                 rmd_flags = dsdb_dn_rmd_flags(p2->dsdb_dn->dn);
2174                 if (rmd_flags & DSDB_RMD_FLAG_DELETED) {
2175                         ldb_asprintf_errstring(ldb, "Attribute %s already deleted for target GUID %s",
2176                                                el->name, GUID_string(tmp_ctx, p->guid));
2177                         if (ldb_attr_cmp(el->name, "member") == 0) {
2178                                 return LDB_ERR_UNWILLING_TO_PERFORM;
2179                         } else {
2180                                 return LDB_ERR_NO_SUCH_ATTRIBUTE;
2181                         }
2182                 }
2183         }
2184
2185         /* for each new value, see if it exists already with the same GUID
2186            if it is not already deleted and matches the delete list then delete it
2187         */
2188         for (i=0; i<old_el->num_values; i++) {
2189                 struct parsed_dn *p = &old_dns[i];
2190                 uint32_t rmd_flags;
2191
2192                 if (el->num_values && parsed_dn_find(dns, el->num_values, p->guid, NULL) == NULL) {
2193                         continue;
2194                 }
2195
2196                 rmd_flags = dsdb_dn_rmd_flags(p->dsdb_dn->dn);
2197                 if (rmd_flags & DSDB_RMD_FLAG_DELETED) continue;
2198
2199                 ret = replmd_update_la_val(old_el->values, p->v, p->dsdb_dn, p->dsdb_dn,
2200                                            invocation_id, seq_num, seq_num, now, 0, true);
2201                 if (ret != LDB_SUCCESS) {
2202                         talloc_free(tmp_ctx);
2203                         return ret;
2204                 }
2205
2206                 ret = replmd_add_backlink(module, schema, msg_guid, old_dns[i].guid, false, schema_attr, true);
2207                 if (ret != LDB_SUCCESS) {
2208                         talloc_free(tmp_ctx);
2209                         return ret;
2210                 }
2211         }
2212
2213         el->values = talloc_steal(msg->elements, old_el->values);
2214         el->num_values = old_el->num_values;
2215
2216         talloc_free(tmp_ctx);
2217
2218         /* we now tell the backend to replace all existing values
2219            with the one we have constructed */
2220         el->flags = LDB_FLAG_MOD_REPLACE;
2221
2222         return LDB_SUCCESS;
2223 }
2224
2225 /*
2226   handle replacing a linked attribute
2227  */
2228 static int replmd_modify_la_replace(struct ldb_module *module,
2229                                     const struct dsdb_schema *schema,
2230                                     struct ldb_message *msg,
2231                                     struct ldb_message_element *el,
2232                                     struct ldb_message_element *old_el,
2233                                     const struct dsdb_attribute *schema_attr,
2234                                     uint64_t seq_num,
2235                                     time_t t,
2236                                     struct GUID *msg_guid,
2237                                     struct ldb_request *parent)
2238 {
2239         unsigned int i;
2240         struct parsed_dn *dns, *old_dns;
2241         TALLOC_CTX *tmp_ctx = talloc_new(msg);
2242         int ret;
2243         const struct GUID *invocation_id;
2244         struct ldb_context *ldb = ldb_module_get_ctx(module);
2245         struct ldb_val *new_values = NULL;
2246         unsigned int num_new_values = 0;
2247         unsigned int old_num_values = old_el?old_el->num_values:0;
2248         NTTIME now;
2249
2250         unix_to_nt_time(&now, t);
2251
2252         /* check if there is nothing to replace */
2253         if ((!old_el || old_el->num_values == 0) &&
2254             el->num_values == 0) {
2255                 return LDB_SUCCESS;
2256         }
2257
2258         ret = get_parsed_dns(module, tmp_ctx, el, &dns, schema_attr->syntax->ldap_oid, parent);
2259         if (ret != LDB_SUCCESS) {
2260                 talloc_free(tmp_ctx);
2261                 return ret;
2262         }
2263
2264         ret = get_parsed_dns(module, tmp_ctx, old_el, &old_dns, schema_attr->syntax->ldap_oid, parent);
2265         if (ret != LDB_SUCCESS) {
2266                 talloc_free(tmp_ctx);
2267                 return ret;
2268         }
2269
2270         invocation_id = samdb_ntds_invocation_id(ldb);
2271         if (!invocation_id) {
2272                 return LDB_ERR_OPERATIONS_ERROR;
2273         }
2274
2275         ret = replmd_check_upgrade_links(old_dns, old_num_values, old_el, invocation_id);
2276         if (ret != LDB_SUCCESS) {
2277                 talloc_free(tmp_ctx);
2278                 return ret;
2279         }
2280
2281         /* mark all the old ones as deleted */
2282         for (i=0; i<old_num_values; i++) {
2283                 struct parsed_dn *old_p = &old_dns[i];
2284                 struct parsed_dn *p;
2285                 uint32_t rmd_flags = dsdb_dn_rmd_flags(old_p->dsdb_dn->dn);
2286
2287                 if (rmd_flags & DSDB_RMD_FLAG_DELETED) continue;
2288
2289                 ret = replmd_add_backlink(module, schema, msg_guid, old_dns[i].guid, false, schema_attr, false);
2290                 if (ret != LDB_SUCCESS) {
2291                         talloc_free(tmp_ctx);
2292                         return ret;
2293                 }
2294
2295                 p = parsed_dn_find(dns, el->num_values, old_p->guid, NULL);
2296                 if (p) {
2297                         /* we don't delete it if we are re-adding it */
2298                         continue;
2299                 }
2300
2301                 ret = replmd_update_la_val(old_el->values, old_p->v, old_p->dsdb_dn, old_p->dsdb_dn,
2302                                            invocation_id, seq_num, seq_num, now, 0, true);
2303                 if (ret != LDB_SUCCESS) {
2304                         talloc_free(tmp_ctx);
2305                         return ret;
2306                 }
2307         }
2308
2309         /* for each new value, either update its meta-data, or add it
2310          * to old_el
2311         */
2312         for (i=0; i<el->num_values; i++) {
2313                 struct parsed_dn *p = &dns[i], *old_p;
2314
2315                 if (old_dns &&
2316                     (old_p = parsed_dn_find(old_dns,
2317                                             old_num_values, p->guid, NULL)) != NULL) {
2318                         /* update in place */
2319                         ret = replmd_update_la_val(old_el->values, old_p->v, p->dsdb_dn,
2320                                                    old_p->dsdb_dn, invocation_id,
2321                                                    seq_num, seq_num, now, 0, false);
2322                         if (ret != LDB_SUCCESS) {
2323                                 talloc_free(tmp_ctx);
2324                                 return ret;
2325                         }
2326                 } else {
2327                         /* add a new one */
2328                         new_values = talloc_realloc(tmp_ctx, new_values, struct ldb_val,
2329                                                     num_new_values+1);
2330                         if (new_values == NULL) {
2331                                 ldb_module_oom(module);
2332                                 talloc_free(tmp_ctx);
2333                                 return LDB_ERR_OPERATIONS_ERROR;
2334                         }
2335                         ret = replmd_build_la_val(new_values, &new_values[num_new_values], dns[i].dsdb_dn,
2336                                                   invocation_id, seq_num, seq_num, now, 0, false);
2337                         if (ret != LDB_SUCCESS) {
2338                                 talloc_free(tmp_ctx);
2339                                 return ret;
2340                         }
2341                         num_new_values++;
2342                 }
2343
2344                 ret = replmd_add_backlink(module, schema, msg_guid, dns[i].guid, true, schema_attr, false);
2345                 if (ret != LDB_SUCCESS) {
2346                         talloc_free(tmp_ctx);
2347                         return ret;
2348                 }
2349         }
2350
2351         /* add the new values to the end of old_el */
2352         if (num_new_values != 0) {
2353                 el->values = talloc_realloc(msg->elements, old_el?old_el->values:NULL,
2354                                             struct ldb_val, old_num_values+num_new_values);
2355                 if (el->values == NULL) {
2356                         ldb_module_oom(module);
2357                         return LDB_ERR_OPERATIONS_ERROR;
2358                 }
2359                 memcpy(&el->values[old_num_values], &new_values[0],
2360                        sizeof(struct ldb_val)*num_new_values);
2361                 el->num_values = old_num_values + num_new_values;
2362                 talloc_steal(msg->elements, new_values);
2363         } else {
2364                 el->values = old_el->values;
2365                 el->num_values = old_el->num_values;
2366                 talloc_steal(msg->elements, el->values);
2367         }
2368
2369         talloc_free(tmp_ctx);
2370
2371         /* we now tell the backend to replace all existing values
2372            with the one we have constructed */
2373         el->flags = LDB_FLAG_MOD_REPLACE;
2374
2375         return LDB_SUCCESS;
2376 }
2377
2378
2379 /*
2380   handle linked attributes in modify requests
2381  */
2382 static int replmd_modify_handle_linked_attribs(struct ldb_module *module,
2383                                                struct ldb_message *msg,
2384                                                uint64_t seq_num, time_t t,
2385                                                struct ldb_request *parent)
2386 {
2387         struct ldb_result *res;
2388         unsigned int i;
2389         int ret;
2390         struct ldb_context *ldb = ldb_module_get_ctx(module);
2391         struct ldb_message *old_msg;
2392
2393         const struct dsdb_schema *schema;
2394         struct GUID old_guid;
2395
2396         if (seq_num == 0) {
2397                 /* there the replmd_update_rpmd code has already
2398                  * checked and saw that there are no linked
2399                  * attributes */
2400                 return LDB_SUCCESS;
2401         }
2402
2403         if (dsdb_functional_level(ldb) == DS_DOMAIN_FUNCTION_2000) {
2404                 /* don't do anything special for linked attributes */
2405                 return LDB_SUCCESS;
2406         }
2407
2408         ret = dsdb_module_search_dn(module, msg, &res, msg->dn, NULL,
2409                                     DSDB_FLAG_NEXT_MODULE |
2410                                     DSDB_SEARCH_SHOW_RECYCLED |
2411                                     DSDB_SEARCH_REVEAL_INTERNALS |
2412                                     DSDB_SEARCH_SHOW_DN_IN_STORAGE_FORMAT,
2413                                     parent);
2414         if (ret != LDB_SUCCESS) {
2415                 return ret;
2416         }
2417         schema = dsdb_get_schema(ldb, res);
2418         if (!schema) {
2419                 return LDB_ERR_OPERATIONS_ERROR;
2420         }
2421
2422         old_msg = res->msgs[0];
2423
2424         old_guid = samdb_result_guid(old_msg, "objectGUID");
2425
2426         for (i=0; i<msg->num_elements; i++) {
2427                 struct ldb_message_element *el = &msg->elements[i];
2428                 struct ldb_message_element *old_el, *new_el;
2429                 const struct dsdb_attribute *schema_attr
2430                         = dsdb_attribute_by_lDAPDisplayName(schema, el->name);
2431                 if (!schema_attr) {
2432                         ldb_asprintf_errstring(ldb,
2433                                                "%s: attribute %s is not a valid attribute in schema",
2434                                                __FUNCTION__, el->name);
2435                         return LDB_ERR_OBJECT_CLASS_VIOLATION;
2436                 }
2437                 if (schema_attr->linkID == 0) {
2438                         continue;
2439                 }
2440                 if ((schema_attr->linkID & 1) == 1) {
2441                         if (parent && ldb_request_get_control(parent, DSDB_CONTROL_DBCHECK)) {
2442                                 continue;
2443                         }
2444                         /* Odd is for the target.  Illegal to modify */
2445                         ldb_asprintf_errstring(ldb,
2446                                                "attribute %s must not be modified directly, it is a linked attribute", el->name);
2447                         return LDB_ERR_UNWILLING_TO_PERFORM;
2448                 }
2449                 old_el = ldb_msg_find_element(old_msg, el->name);
2450                 switch (el->flags & LDB_FLAG_MOD_MASK) {
2451                 case LDB_FLAG_MOD_REPLACE:
2452                         ret = replmd_modify_la_replace(module, schema, msg, el, old_el, schema_attr, seq_num, t, &old_guid, parent);
2453                         break;
2454                 case LDB_FLAG_MOD_DELETE:
2455                         ret = replmd_modify_la_delete(module, schema, msg, el, old_el, schema_attr, seq_num, t, &old_guid, parent);
2456                         break;
2457                 case LDB_FLAG_MOD_ADD:
2458                         ret = replmd_modify_la_add(module, schema, msg, el, old_el, schema_attr, seq_num, t, &old_guid, parent);
2459                         break;
2460                 default:
2461                         ldb_asprintf_errstring(ldb,
2462                                                "invalid flags 0x%x for %s linked attribute",
2463                                                el->flags, el->name);
2464                         return LDB_ERR_UNWILLING_TO_PERFORM;
2465                 }
2466                 if (dsdb_check_single_valued_link(schema_attr, el) != LDB_SUCCESS) {
2467                         ldb_asprintf_errstring(ldb,
2468                                                "Attribute %s is single valued but more than one value has been supplied",
2469                                                el->name);
2470                         return LDB_ERR_ATTRIBUTE_OR_VALUE_EXISTS;
2471                 } else {
2472                         el->flags |= LDB_FLAG_INTERNAL_DISABLE_SINGLE_VALUE_CHECK;
2473                 }
2474
2475
2476
2477                 if (ret != LDB_SUCCESS) {
2478                         return ret;
2479                 }
2480                 if (old_el) {
2481                         ldb_msg_remove_attr(old_msg, el->name);
2482                 }
2483                 ldb_msg_add_empty(old_msg, el->name, 0, &new_el);
2484                 new_el->num_values = el->num_values;
2485                 new_el->values = talloc_steal(msg->elements, el->values);
2486
2487                 /* TODO: this relises a bit too heavily on the exact
2488                    behaviour of ldb_msg_find_element and
2489                    ldb_msg_remove_element */
2490                 old_el = ldb_msg_find_element(msg, el->name);
2491                 if (old_el != el) {
2492                         ldb_msg_remove_element(msg, old_el);
2493                         i--;
2494                 }
2495         }
2496
2497         talloc_free(res);
2498         return ret;
2499 }
2500
2501
2502
2503 static int replmd_modify(struct ldb_module *module, struct ldb_request *req)
2504 {
2505         struct samldb_msds_intid_persistant *msds_intid_struct;
2506         struct ldb_context *ldb;
2507         struct replmd_replicated_request *ac;
2508         struct ldb_request *down_req;
2509         struct ldb_message *msg;
2510         time_t t = time(NULL);
2511         int ret;
2512         bool is_urgent = false, rodc = false;
2513         bool is_schema_nc = false;
2514         unsigned int functional_level;
2515         const struct ldb_message_element *guid_el = NULL;
2516         struct ldb_control *sd_propagation_control;
2517         struct replmd_private *replmd_private =
2518                 talloc_get_type(ldb_module_get_private(module), struct replmd_private);
2519
2520         /* do not manipulate our control entries */
2521         if (ldb_dn_is_special(req->op.mod.message->dn)) {
2522                 return ldb_next_request(module, req);
2523         }
2524
2525         sd_propagation_control = ldb_request_get_control(req,
2526                                         DSDB_CONTROL_SEC_DESC_PROPAGATION_OID);
2527         if (sd_propagation_control != NULL) {
2528                 if (req->op.mod.message->num_elements != 1) {
2529                         return ldb_module_operr(module);
2530                 }
2531                 ret = strcmp(req->op.mod.message->elements[0].name,
2532                              "nTSecurityDescriptor");
2533                 if (ret != 0) {
2534                         return ldb_module_operr(module);
2535                 }
2536
2537                 return ldb_next_request(module, req);
2538         }
2539
2540         ldb = ldb_module_get_ctx(module);
2541
2542         ldb_debug(ldb, LDB_DEBUG_TRACE, "replmd_modify\n");
2543
2544         guid_el = ldb_msg_find_element(req->op.mod.message, "objectGUID");
2545         if (guid_el != NULL) {
2546                 ldb_set_errstring(ldb,
2547                                   "replmd_modify: it's not allowed to change the objectGUID!");
2548                 return LDB_ERR_CONSTRAINT_VIOLATION;
2549         }
2550
2551         ac = replmd_ctx_init(module, req);
2552         if (ac == NULL) {
2553                 return ldb_module_oom(module);
2554         }
2555
2556         functional_level = dsdb_functional_level(ldb);
2557
2558         /* we have to copy the message as the caller might have it as a const */
2559         msg = ldb_msg_copy_shallow(ac, req->op.mod.message);
2560         if (msg == NULL) {
2561                 ldb_oom(ldb);
2562                 talloc_free(ac);
2563                 return LDB_ERR_OPERATIONS_ERROR;
2564         }
2565
2566         ldb_msg_remove_attr(msg, "whenChanged");
2567         ldb_msg_remove_attr(msg, "uSNChanged");
2568
2569         is_schema_nc = ldb_dn_compare_base(replmd_private->schema_dn, msg->dn) == 0;
2570
2571         ret = replmd_update_rpmd(module, ac->schema, req, NULL,
2572                                  msg, &ac->seq_num, t, is_schema_nc,
2573                                  &is_urgent, &rodc);
2574         if (rodc && (ret == LDB_ERR_REFERRAL)) {
2575                 struct loadparm_context *lp_ctx;
2576                 char *referral;
2577
2578                 lp_ctx = talloc_get_type(ldb_get_opaque(ldb, "loadparm"),
2579                                          struct loadparm_context);
2580
2581                 referral = talloc_asprintf(req,
2582                                            "ldap://%s/%s",
2583                                            lpcfg_dnsdomain(lp_ctx),
2584                                            ldb_dn_get_linearized(msg->dn));
2585                 ret = ldb_module_send_referral(req, referral);
2586                 talloc_free(ac);
2587                 return ret;
2588         }
2589
2590         if (ret != LDB_SUCCESS) {
2591                 talloc_free(ac);
2592                 return ret;
2593         }
2594
2595         ret = replmd_modify_handle_linked_attribs(module, msg, ac->seq_num, t, req);
2596         if (ret != LDB_SUCCESS) {
2597                 talloc_free(ac);
2598                 return ret;
2599         }
2600
2601         /* TODO:
2602          * - replace the old object with the newly constructed one
2603          */
2604
2605         ac->is_urgent = is_urgent;
2606
2607         ret = ldb_build_mod_req(&down_req, ldb, ac,
2608                                 msg,
2609                                 req->controls,
2610                                 ac, replmd_op_callback,
2611                                 req);
2612         LDB_REQ_SET_LOCATION(down_req);
2613         if (ret != LDB_SUCCESS) {
2614                 talloc_free(ac);
2615                 return ret;
2616         }
2617
2618         /* current partition control is needed by "replmd_op_callback" */
2619         if (ldb_request_get_control(req, DSDB_CONTROL_CURRENT_PARTITION_OID) == NULL) {
2620                 ret = ldb_request_add_control(down_req,
2621                                               DSDB_CONTROL_CURRENT_PARTITION_OID,
2622                                               false, NULL);
2623                 if (ret != LDB_SUCCESS) {
2624                         talloc_free(ac);
2625                         return ret;
2626                 }
2627         }
2628
2629         /* If we are in functional level 2000, then
2630          * replmd_modify_handle_linked_attribs will have done
2631          * nothing */
2632         if (functional_level == DS_DOMAIN_FUNCTION_2000) {
2633                 ret = ldb_request_add_control(down_req, DSDB_CONTROL_APPLY_LINKS, false, NULL);
2634                 if (ret != LDB_SUCCESS) {
2635                         talloc_free(ac);
2636                         return ret;
2637                 }
2638         }
2639
2640         talloc_steal(down_req, msg);
2641
2642         /* we only change whenChanged and uSNChanged if the seq_num
2643            has changed */
2644         if (ac->seq_num != 0) {
2645                 ret = add_time_element(msg, "whenChanged", t);
2646                 if (ret != LDB_SUCCESS) {
2647                         talloc_free(ac);
2648                         ldb_operr(ldb);
2649                         return ret;
2650                 }
2651
2652                 ret = add_uint64_element(ldb, msg, "uSNChanged", ac->seq_num);
2653                 if (ret != LDB_SUCCESS) {
2654                         talloc_free(ac);
2655                         ldb_operr(ldb);
2656                         return ret;
2657                 }
2658         }
2659
2660         if (!ldb_dn_compare_base(replmd_private->schema_dn, msg->dn)) {
2661                 /* Update the usn in the SAMLDB_MSDS_INTID_OPAQUE opaque */
2662                 msds_intid_struct = (struct samldb_msds_intid_persistant *) ldb_get_opaque(ldb, SAMLDB_MSDS_INTID_OPAQUE);
2663                 if (msds_intid_struct) {
2664                         msds_intid_struct->usn = ac->seq_num;
2665                 }
2666         }
2667
2668         /* go on with the call chain */
2669         return ldb_next_request(module, down_req);
2670 }
2671
2672 static int replmd_rename_callback(struct ldb_request *req, struct ldb_reply *ares);
2673
2674 /*
2675   handle a rename request
2676
2677   On a rename we need to do an extra ldb_modify which sets the
2678   whenChanged and uSNChanged attributes.  We do this in a callback after the success.
2679  */
2680 static int replmd_rename(struct ldb_module *module, struct ldb_request *req)
2681 {
2682         struct ldb_context *ldb;
2683         struct replmd_replicated_request *ac;
2684         int ret;
2685         struct ldb_request *down_req;
2686
2687         /* do not manipulate our control entries */
2688         if (ldb_dn_is_special(req->op.mod.message->dn)) {
2689                 return ldb_next_request(module, req);
2690         }
2691
2692         ldb = ldb_module_get_ctx(module);
2693
2694         ldb_debug(ldb, LDB_DEBUG_TRACE, "replmd_rename\n");
2695
2696         ac = replmd_ctx_init(module, req);
2697         if (ac == NULL) {
2698                 return ldb_module_oom(module);
2699         }
2700
2701         ret = ldb_build_rename_req(&down_req, ldb, ac,
2702                                    ac->req->op.rename.olddn,
2703                                    ac->req->op.rename.newdn,
2704                                    ac->req->controls,
2705                                    ac, replmd_rename_callback,
2706                                    ac->req);
2707         LDB_REQ_SET_LOCATION(down_req);
2708         if (ret != LDB_SUCCESS) {
2709                 talloc_free(ac);
2710                 return ret;
2711         }
2712
2713         /* go on with the call chain */
2714         return ldb_next_request(module, down_req);
2715 }
2716
2717 /* After the rename is compleated, update the whenchanged etc */
2718 static int replmd_rename_callback(struct ldb_request *req, struct ldb_reply *ares)
2719 {
2720         struct ldb_context *ldb;
2721         struct ldb_request *down_req;
2722         struct ldb_message *msg;
2723         const struct dsdb_attribute *rdn_attr;
2724         const char *rdn_name;
2725         const struct ldb_val *rdn_val;
2726         const char *attrs[5] = { NULL, };
2727         time_t t = time(NULL);
2728         int ret;
2729         bool is_urgent = false, rodc = false;
2730         bool is_schema_nc;
2731         struct replmd_replicated_request *ac =
2732                 talloc_get_type(req->context, struct replmd_replicated_request);
2733         struct replmd_private *replmd_private =
2734                 talloc_get_type(ldb_module_get_private(ac->module),
2735                                 struct replmd_private);
2736
2737         ldb = ldb_module_get_ctx(ac->module);
2738
2739         if (ares->error != LDB_SUCCESS) {
2740                 return ldb_module_done(ac->req, ares->controls,
2741                                         ares->response, ares->error);
2742         }
2743
2744         if (ares->type != LDB_REPLY_DONE) {
2745                 ldb_set_errstring(ldb,
2746                                   "invalid ldb_reply_type in callback");
2747                 talloc_free(ares);
2748                 return ldb_module_done(ac->req, NULL, NULL,
2749                                         LDB_ERR_OPERATIONS_ERROR);
2750         }
2751
2752         /* TODO:
2753          * - replace the old object with the newly constructed one
2754          */
2755
2756         msg = ldb_msg_new(ac);
2757         if (msg == NULL) {
2758                 ldb_oom(ldb);
2759                 return LDB_ERR_OPERATIONS_ERROR;
2760         }
2761
2762         msg->dn = ac->req->op.rename.newdn;
2763
2764         is_schema_nc = ldb_dn_compare_base(replmd_private->schema_dn, msg->dn) == 0;
2765
2766         rdn_name = ldb_dn_get_rdn_name(msg->dn);
2767         if (rdn_name == NULL) {
2768                 talloc_free(ares);
2769                 return ldb_module_done(ac->req, NULL, NULL,
2770                                        ldb_operr(ldb));
2771         }
2772
2773         /* normalize the rdn attribute name */
2774         rdn_attr = dsdb_attribute_by_lDAPDisplayName(ac->schema, rdn_name);
2775         if (rdn_attr == NULL) {
2776                 talloc_free(ares);
2777                 return ldb_module_done(ac->req, NULL, NULL,
2778                                        ldb_operr(ldb));
2779         }
2780         rdn_name = rdn_attr->lDAPDisplayName;
2781
2782         rdn_val = ldb_dn_get_rdn_val(msg->dn);
2783         if (rdn_val == NULL) {
2784                 talloc_free(ares);
2785                 return ldb_module_done(ac->req, NULL, NULL,
2786                                        ldb_operr(ldb));
2787         }
2788
2789         if (ldb_msg_add_empty(msg, rdn_name, LDB_FLAG_MOD_REPLACE, NULL) != 0) {
2790                 talloc_free(ares);
2791                 return ldb_module_done(ac->req, NULL, NULL,
2792                                        ldb_oom(ldb));
2793         }
2794         if (ldb_msg_add_value(msg, rdn_name, rdn_val, NULL) != 0) {
2795                 talloc_free(ares);
2796                 return ldb_module_done(ac->req, NULL, NULL,
2797                                        ldb_oom(ldb));
2798         }
2799         if (ldb_msg_add_empty(msg, "name", LDB_FLAG_MOD_REPLACE, NULL) != 0) {
2800                 talloc_free(ares);
2801                 return ldb_module_done(ac->req, NULL, NULL,
2802                                        ldb_oom(ldb));
2803         }
2804         if (ldb_msg_add_value(msg, "name", rdn_val, NULL) != 0) {
2805                 talloc_free(ares);
2806                 return ldb_module_done(ac->req, NULL, NULL,
2807                                        ldb_oom(ldb));
2808         }
2809
2810         /*
2811          * here we let replmd_update_rpmd() only search for
2812          * the existing "replPropertyMetaData" and rdn_name attributes.
2813          *
2814          * We do not want the existing "name" attribute as
2815          * the "name" attribute needs to get the version
2816          * updated on rename even if the rdn value hasn't changed.
2817          *
2818          * This is the diff of the meta data, for a moved user
2819          * on a w2k8r2 server:
2820          *
2821          * # record 1
2822          * -dn: CN=sdf df,CN=Users,DC=bla,DC=base
2823          * +dn: CN=sdf df,OU=TestOU,DC=bla,DC=base
2824          *  replPropertyMetaData:     NDR: struct replPropertyMetaDataBlob
2825          *         version                  : 0x00000001 (1)
2826          *         reserved                 : 0x00000000 (0)
2827          * @@ -66,11 +66,11 @@ replPropertyMetaData:     NDR: struct re
2828          *                      local_usn                : 0x00000000000037a5 (14245)
2829          *                 array: struct replPropertyMetaData1
2830          *                      attid                    : DRSUAPI_ATTID_name (0x90001)
2831          * -                    version                  : 0x00000001 (1)
2832          * -                    originating_change_time  : Wed Feb  9 17:20:49 2011 CET
2833          * +                    version                  : 0x00000002 (2)
2834          * +                    originating_change_time  : Wed Apr  6 15:21:01 2011 CEST
2835          *                      originating_invocation_id: 0d36ca05-5507-4e62-aca3-354bab0d39e1
2836          * -                    originating_usn          : 0x00000000000037a5 (14245)
2837          * -                    local_usn                : 0x00000000000037a5 (14245)
2838          * +                    originating_usn          : 0x0000000000003834 (14388)
2839          * +                    local_usn                : 0x0000000000003834 (14388)
2840          *                 array: struct replPropertyMetaData1
2841          *                      attid                    : DRSUAPI_ATTID_userAccountControl (0x90008)
2842          *                      version                  : 0x00000004 (4)
2843          */
2844         attrs[0] = "replPropertyMetaData";
2845         attrs[1] = "objectClass";
2846         attrs[2] = "instanceType";
2847         attrs[3] = rdn_name;
2848         attrs[4] = NULL;
2849
2850         ret = replmd_update_rpmd(ac->module, ac->schema, req, attrs,
2851                                  msg, &ac->seq_num, t,
2852                                  is_schema_nc, &is_urgent, &rodc);
2853         if (rodc && (ret == LDB_ERR_REFERRAL)) {
2854                 struct ldb_dn *olddn = ac->req->op.rename.olddn;
2855                 struct loadparm_context *lp_ctx;
2856                 char *referral;
2857
2858                 lp_ctx = talloc_get_type(ldb_get_opaque(ldb, "loadparm"),
2859                                          struct loadparm_context);
2860
2861                 referral = talloc_asprintf(req,
2862                                            "ldap://%s/%s",
2863                                            lpcfg_dnsdomain(lp_ctx),
2864                                            ldb_dn_get_linearized(olddn));
2865                 ret = ldb_module_send_referral(req, referral);
2866                 talloc_free(ares);
2867                 return ldb_module_done(req, NULL, NULL, ret);
2868         }
2869
2870         if (ret != LDB_SUCCESS) {
2871                 talloc_free(ares);
2872                 return ldb_module_done(ac->req, NULL, NULL, ret);
2873         }
2874
2875         if (ac->seq_num == 0) {
2876                 talloc_free(ares);
2877                 return ldb_module_done(ac->req, NULL, NULL,
2878                                        ldb_error(ldb, ret,
2879                                         "internal error seq_num == 0"));
2880         }
2881         ac->is_urgent = is_urgent;
2882
2883         ret = ldb_build_mod_req(&down_req, ldb, ac,
2884                                 msg,
2885                                 req->controls,
2886                                 ac, replmd_op_callback,
2887                                 req);
2888         LDB_REQ_SET_LOCATION(down_req);
2889         if (ret != LDB_SUCCESS) {
2890                 talloc_free(ac);
2891                 return ret;
2892         }
2893
2894         /* current partition control is needed by "replmd_op_callback" */
2895         if (ldb_request_get_control(req, DSDB_CONTROL_CURRENT_PARTITION_OID) == NULL) {
2896                 ret = ldb_request_add_control(down_req,
2897                                               DSDB_CONTROL_CURRENT_PARTITION_OID,
2898                                               false, NULL);
2899                 if (ret != LDB_SUCCESS) {
2900                         talloc_free(ac);
2901                         return ret;
2902                 }
2903         }
2904
2905         talloc_steal(down_req, msg);
2906
2907         ret = add_time_element(msg, "whenChanged", t);
2908         if (ret != LDB_SUCCESS) {
2909                 talloc_free(ac);
2910                 ldb_operr(ldb);
2911                 return ret;
2912         }
2913
2914         ret = add_uint64_element(ldb, msg, "uSNChanged", ac->seq_num);
2915         if (ret != LDB_SUCCESS) {
2916                 talloc_free(ac);
2917                 ldb_operr(ldb);
2918                 return ret;
2919         }
2920
2921         /* go on with the call chain - do the modify after the rename */
2922         return ldb_next_request(ac->module, down_req);
2923 }
2924
2925 /*
2926  * remove links from objects that point at this object when an object
2927  * is deleted.  We remove it from the NEXT module per MS-DRSR 5.160
2928  * RemoveObj which states that link removal due to the object being
2929  * deleted is NOT an originating update - they just go away!
2930  *
2931  */
2932 static int replmd_delete_remove_link(struct ldb_module *module,
2933                                      const struct dsdb_schema *schema,
2934                                      struct ldb_dn *dn,
2935                                      struct ldb_message_element *el,
2936                                      const struct dsdb_attribute *sa,
2937                                      struct ldb_request *parent)
2938 {
2939         unsigned int i;
2940         TALLOC_CTX *tmp_ctx = talloc_new(module);
2941         struct ldb_context *ldb = ldb_module_get_ctx(module);
2942
2943         for (i=0; i<el->num_values; i++) {
2944                 struct dsdb_dn *dsdb_dn;
2945                 NTSTATUS status;
2946                 int ret;
2947                 struct GUID guid2;
2948                 struct ldb_message *msg;
2949                 const struct dsdb_attribute *target_attr;
2950                 struct ldb_message_element *el2;
2951                 struct ldb_val dn_val;
2952
2953                 if (dsdb_dn_is_deleted_val(&el->values[i])) {
2954                         continue;
2955                 }
2956
2957                 dsdb_dn = dsdb_dn_parse(tmp_ctx, ldb, &el->values[i], sa->syntax->ldap_oid);
2958                 if (!dsdb_dn) {
2959                         talloc_free(tmp_ctx);
2960                         return LDB_ERR_OPERATIONS_ERROR;
2961                 }
2962
2963                 status = dsdb_get_extended_dn_guid(dsdb_dn->dn, &guid2, "GUID");
2964                 if (!NT_STATUS_IS_OK(status)) {
2965                         talloc_free(tmp_ctx);
2966                         return LDB_ERR_OPERATIONS_ERROR;
2967                 }
2968
2969                 /* remove the link */
2970                 msg = ldb_msg_new(tmp_ctx);
2971                 if (!msg) {
2972                         ldb_module_oom(module);
2973                         talloc_free(tmp_ctx);
2974                         return LDB_ERR_OPERATIONS_ERROR;
2975                 }
2976
2977
2978                 msg->dn = dsdb_dn->dn;
2979
2980                 target_attr = dsdb_attribute_by_linkID(schema, sa->linkID ^ 1);
2981                 if (target_attr == NULL) {
2982                         continue;
2983                 }
2984
2985                 ret = ldb_msg_add_empty(msg, target_attr->lDAPDisplayName, LDB_FLAG_MOD_DELETE, &el2);
2986                 if (ret != LDB_SUCCESS) {
2987                         ldb_module_oom(module);
2988                         talloc_free(tmp_ctx);
2989                         return LDB_ERR_OPERATIONS_ERROR;
2990                 }
2991                 dn_val = data_blob_string_const(ldb_dn_get_linearized(dn));
2992                 el2->values = &dn_val;
2993                 el2->num_values = 1;
2994
2995                 ret = dsdb_module_modify(module, msg, DSDB_FLAG_OWN_MODULE, parent);
2996                 if (ret != LDB_SUCCESS) {
2997                         talloc_free(tmp_ctx);
2998                         return ret;
2999                 }
3000         }
3001         talloc_free(tmp_ctx);
3002         return LDB_SUCCESS;
3003 }
3004
3005
3006 /*
3007   handle update of replication meta data for deletion of objects
3008
3009   This also handles the mapping of delete to a rename operation
3010   to allow deletes to be replicated.
3011
3012   It also handles the incoming deleted objects, to ensure they are
3013   fully deleted here.  In that case re_delete is true, and we do not
3014   use this as a signal to change the deleted state, just reinforce it.
3015
3016  */
3017 static int replmd_delete_internals(struct ldb_module *module, struct ldb_request *req, bool re_delete)
3018 {
3019         int ret = LDB_ERR_OTHER;
3020         bool retb, disallow_move_on_delete;
3021         struct ldb_dn *old_dn, *new_dn;
3022         const char *rdn_name;
3023         const struct ldb_val *rdn_value, *new_rdn_value;
3024         struct GUID guid;
3025         struct ldb_context *ldb = ldb_module_get_ctx(module);
3026         const struct dsdb_schema *schema;
3027         struct ldb_message *msg, *old_msg;
3028         struct ldb_message_element *el;
3029         TALLOC_CTX *tmp_ctx;
3030         struct ldb_result *res, *parent_res;
3031         const char *preserved_attrs[] = {
3032                 /* yes, this really is a hard coded list. See MS-ADTS
3033                    section 3.1.1.5.5.1.1 */
3034                 "nTSecurityDescriptor", "attributeID", "attributeSyntax", "dNReferenceUpdate", "dNSHostName",
3035                 "flatName", "governsID", "groupType", "instanceType", "lDAPDisplayName", "legacyExchangeDN",
3036                 "isDeleted", "isRecycled", "lastKnownParent", "msDS-LastKnownRDN", "mS-DS-CreatorSID",
3037                 "mSMQOwnerID", "nCName", "objectClass", "distinguishedName", "objectGUID", "objectSid",
3038                 "oMSyntax", "proxiedObjectName", "name", "replPropertyMetaData", "sAMAccountName",
3039                 "securityIdentifier", "sIDHistory", "subClassOf", "systemFlags", "trustPartner", "trustDirection",
3040                 "trustType", "trustAttributes", "userAccountControl", "uSNChanged", "uSNCreated", "whenCreated",
3041                 "whenChanged", NULL};
3042         unsigned int i, el_count = 0;
3043         enum deletion_state deletion_state, next_deletion_state;
3044
3045         if (ldb_dn_is_special(req->op.del.dn)) {
3046                 return ldb_next_request(module, req);
3047         }
3048
3049         /*
3050          * We have to allow dbcheck to remove an object that
3051          * is beyond repair, and to do so totally.  This could
3052          * mean we we can get a partial object from the other
3053          * DC, causing havoc, so dbcheck suggests
3054          * re-replication first.  dbcheck sets both DBCHECK
3055          * and RELAX in this situation.
3056          */
3057         if (ldb_request_get_control(req, LDB_CONTROL_RELAX_OID)
3058             && ldb_request_get_control(req, DSDB_CONTROL_DBCHECK)) {
3059                 /* really, really remove it */
3060                 return ldb_next_request(module, req);
3061         }
3062
3063         tmp_ctx = talloc_new(ldb);
3064         if (!tmp_ctx) {
3065                 ldb_oom(ldb);
3066                 return LDB_ERR_OPERATIONS_ERROR;
3067         }
3068
3069         schema = dsdb_get_schema(ldb, tmp_ctx);
3070         if (!schema) {
3071                 talloc_free(tmp_ctx);
3072                 return LDB_ERR_OPERATIONS_ERROR;
3073         }
3074
3075         old_dn = ldb_dn_copy(tmp_ctx, req->op.del.dn);
3076
3077         /* we need the complete msg off disk, so we can work out which
3078            attributes need to be removed */
3079         ret = dsdb_module_search_dn(module, tmp_ctx, &res, old_dn, NULL,
3080                                     DSDB_FLAG_NEXT_MODULE |
3081                                     DSDB_SEARCH_SHOW_RECYCLED |
3082                                     DSDB_SEARCH_REVEAL_INTERNALS |
3083                                     DSDB_SEARCH_SHOW_DN_IN_STORAGE_FORMAT, req);
3084         if (ret != LDB_SUCCESS) {
3085                 ldb_asprintf_errstring(ldb_module_get_ctx(module),
3086                                        "repmd_delete: Failed to %s %s, because we failed to find it: %s",
3087                                        re_delete ? "re-delete" : "delete",
3088                                        ldb_dn_get_linearized(old_dn),
3089                                        ldb_errstring(ldb_module_get_ctx(module)));
3090                 talloc_free(tmp_ctx);
3091                 return ret;
3092         }
3093         old_msg = res->msgs[0];
3094
3095         replmd_deletion_state(module, old_msg,
3096                               &deletion_state,
3097                               &next_deletion_state);
3098
3099         /* This supports us noticing an incoming isDeleted and acting on it */
3100         if (re_delete) {
3101                 SMB_ASSERT(deletion_state > OBJECT_NOT_DELETED);
3102                 next_deletion_state = deletion_state;
3103         }
3104
3105         if (next_deletion_state == OBJECT_REMOVED) {
3106                 /*
3107                  * We have to prevent objects being deleted, even if
3108                  * the administrator really wants them gone, as
3109                  * without the tombstone, we can get a partial object
3110                  * from the other DC, causing havoc.
3111                  *
3112                  * The only other valid case is when the 180 day
3113                  * timeout has expired, when relax is specified.
3114                  */
3115                 if (ldb_request_get_control(req, LDB_CONTROL_RELAX_OID)) {
3116                         /* it is already deleted - really remove it this time */
3117                         talloc_free(tmp_ctx);
3118                         return ldb_next_request(module, req);
3119                 }
3120
3121                 ldb_asprintf_errstring(ldb, "Refusing to delete tombstone object %s.  "
3122                                        "This check is to prevent corruption of the replicated state.",
3123                                        ldb_dn_get_linearized(old_msg->dn));
3124                 return LDB_ERR_UNWILLING_TO_PERFORM;
3125         }
3126
3127         rdn_name = ldb_dn_get_rdn_name(old_dn);
3128         rdn_value = ldb_dn_get_rdn_val(old_dn);
3129         if ((rdn_name == NULL) || (rdn_value == NULL)) {
3130                 talloc_free(tmp_ctx);
3131                 return ldb_operr(ldb);
3132         }
3133
3134         msg = ldb_msg_new(tmp_ctx);
3135         if (msg == NULL) {
3136                 ldb_module_oom(module);
3137                 talloc_free(tmp_ctx);
3138                 return LDB_ERR_OPERATIONS_ERROR;
3139         }
3140
3141         msg->dn = old_dn;
3142
3143         /* consider the SYSTEM_FLAG_DISALLOW_MOVE_ON_DELETE flag */
3144         disallow_move_on_delete =
3145                 (ldb_msg_find_attr_as_int(old_msg, "systemFlags", 0)
3146                  & SYSTEM_FLAG_DISALLOW_MOVE_ON_DELETE);
3147
3148         /* work out where we will be renaming this object to */
3149         if (!disallow_move_on_delete) {
3150                 struct ldb_dn *deleted_objects_dn;
3151                 ret = dsdb_get_deleted_objects_dn(ldb, tmp_ctx, old_dn,
3152                                                   &deleted_objects_dn);
3153
3154                 /*
3155                  * We should not move objects if we can't find the
3156                  * deleted objects DN.  Not moving (or otherwise
3157                  * harming) the Deleted Objects DN itself is handled
3158                  * in the caller.
3159                  */
3160                 if (re_delete && (ret != LDB_SUCCESS)) {
3161                         new_dn = ldb_dn_get_parent(tmp_ctx, old_dn);
3162                         if (new_dn == NULL) {
3163                                 ldb_module_oom(module);
3164                                 talloc_free(tmp_ctx);
3165                                 return LDB_ERR_OPERATIONS_ERROR;
3166                         }
3167                 } else if (ret != LDB_SUCCESS) {
3168                         /* this is probably an attempted delete on a partition
3169                          * that doesn't allow delete operations, such as the
3170                          * schema partition */
3171                         ldb_asprintf_errstring(ldb, &