repl: Remove duplicated delete of sAMAccountType
[metze/samba/wip.git] / source4 / dsdb / samdb / ldb_modules / repl_meta_data.c
1 /*
2    ldb database library
3
4    Copyright (C) Simo Sorce  2004-2008
5    Copyright (C) Andrew Bartlett <abartlet@samba.org> 2005-2013
6    Copyright (C) Andrew Tridgell 2005-2009
7    Copyright (C) Stefan Metzmacher <metze@samba.org> 2007
8    Copyright (C) Matthieu Patou <mat@samba.org> 2010-2011
9
10    This program is free software; you can redistribute it and/or modify
11    it under the terms of the GNU General Public License as published by
12    the Free Software Foundation; either version 3 of the License, or
13    (at your option) any later version.
14
15    This program is distributed in the hope that it will be useful,
16    but WITHOUT ANY WARRANTY; without even the implied warranty of
17    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
18    GNU General Public License for more details.
19
20    You should have received a copy of the GNU General Public License
21    along with this program.  If not, see <http://www.gnu.org/licenses/>.
22 */
23
24 /*
25  *  Name: ldb
26  *
27  *  Component: ldb repl_meta_data module
28  *
29  *  Description: - add a unique objectGUID onto every new record,
30  *               - handle whenCreated, whenChanged timestamps
31  *               - handle uSNCreated, uSNChanged numbers
32  *               - handle replPropertyMetaData attribute
33  *
34  *  Author: Simo Sorce
35  *  Author: Stefan Metzmacher
36  */
37
38 #include "includes.h"
39 #include "ldb_module.h"
40 #include "dsdb/samdb/samdb.h"
41 #include "dsdb/common/proto.h"
42 #include "../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
717         /* the objectClass attribute is value 0x00000000, so must be first */
718         if (ctr1->array[0].attid != DRSUAPI_ATTID_objectClass) {
719                 ldb_debug_set(ldb, LDB_DEBUG_FATAL,
720                               "No objectClass found in replPropertyMetaData for %s!\n",
721                               ldb_dn_get_linearized(dn));
722                 return LDB_ERR_OBJECT_CLASS_VIOLATION;
723         }
724
725         return LDB_SUCCESS;
726 }
727
728 static int replmd_replPropertyMetaDataCtr1_sort_and_verify(struct ldb_context *ldb,
729                                                            struct replPropertyMetaDataCtr1 *ctr1,
730                                                            const struct dsdb_schema *schema,
731                                                            struct ldb_dn *dn)
732 {
733         const char *rdn_name;
734         const struct dsdb_attribute *rdn_sa;
735
736         rdn_name = ldb_dn_get_rdn_name(dn);
737         if (!rdn_name) {
738                 ldb_debug_set(ldb, LDB_DEBUG_FATAL,
739                               __location__ ": No rDN for %s?\n",
740                               ldb_dn_get_linearized(dn));
741                 return LDB_ERR_INVALID_DN_SYNTAX;
742         }
743
744         rdn_sa = dsdb_attribute_by_lDAPDisplayName(schema, rdn_name);
745         if (rdn_sa == NULL) {
746                 ldb_debug_set(ldb, LDB_DEBUG_FATAL,
747                               __location__ ": No sa found for rDN %s for %s\n",
748                               rdn_name, ldb_dn_get_linearized(dn));
749                 return LDB_ERR_UNDEFINED_ATTRIBUTE_TYPE;
750         }
751
752         DEBUG(6,("Sorting rpmd with attid exception %u rDN=%s DN=%s\n",
753                  rdn_sa->attributeID_id, rdn_name, ldb_dn_get_linearized(dn)));
754
755         LDB_TYPESAFE_QSORT(ctr1->array, ctr1->count, &rdn_sa->attributeID_id,
756                            replmd_replPropertyMetaData1_attid_sort);
757         return replmd_replPropertyMetaDataCtr1_verify(ldb, ctr1, rdn_sa, dn);
758 }
759
760 static int replmd_ldb_message_element_attid_sort(const struct ldb_message_element *e1,
761                                                  const struct ldb_message_element *e2,
762                                                  const struct dsdb_schema *schema)
763 {
764         const struct dsdb_attribute *a1;
765         const struct dsdb_attribute *a2;
766
767         /*
768          * TODO: make this faster by caching the dsdb_attribute pointer
769          *       on the ldb_messag_element
770          */
771
772         a1 = dsdb_attribute_by_lDAPDisplayName(schema, e1->name);
773         a2 = dsdb_attribute_by_lDAPDisplayName(schema, e2->name);
774
775         /*
776          * TODO: remove this check, we should rely on e1 and e2 having valid attribute names
777          *       in the schema
778          */
779         if (!a1 || !a2) {
780                 return strcasecmp(e1->name, e2->name);
781         }
782         if (a1->attributeID_id == a2->attributeID_id) {
783                 return 0;
784         }
785         return a1->attributeID_id > a2->attributeID_id ? 1 : -1;
786 }
787
788 static void replmd_ldb_message_sort(struct ldb_message *msg,
789                                     const struct dsdb_schema *schema)
790 {
791         LDB_TYPESAFE_QSORT(msg->elements, msg->num_elements, schema, replmd_ldb_message_element_attid_sort);
792 }
793
794 static int replmd_build_la_val(TALLOC_CTX *mem_ctx, struct ldb_val *v, struct dsdb_dn *dsdb_dn,
795                                const struct GUID *invocation_id, uint64_t seq_num,
796                                uint64_t local_usn, NTTIME nttime, uint32_t version, bool deleted);
797
798
799 /*
800   fix up linked attributes in replmd_add.
801   This involves setting up the right meta-data in extended DN
802   components, and creating backlinks to the object
803  */
804 static int replmd_add_fix_la(struct ldb_module *module, struct ldb_message_element *el,
805                              uint64_t seq_num, const struct GUID *invocationId, time_t t,
806                              struct GUID *guid, const struct dsdb_attribute *sa, struct ldb_request *parent)
807 {
808         unsigned int i;
809         TALLOC_CTX *tmp_ctx = talloc_new(el->values);
810         struct ldb_context *ldb = ldb_module_get_ctx(module);
811
812         /* We will take a reference to the schema in replmd_add_backlink */
813         const struct dsdb_schema *schema = dsdb_get_schema(ldb, NULL);
814         NTTIME now;
815
816         unix_to_nt_time(&now, t);
817
818         for (i=0; i<el->num_values; i++) {
819                 struct ldb_val *v = &el->values[i];
820                 struct dsdb_dn *dsdb_dn = dsdb_dn_parse(tmp_ctx, ldb, v, sa->syntax->ldap_oid);
821                 struct GUID target_guid;
822                 NTSTATUS status;
823                 int ret;
824
825                 /* note that the DN already has the extended
826                    components from the extended_dn_store module */
827                 status = dsdb_get_extended_dn_guid(dsdb_dn->dn, &target_guid, "GUID");
828                 if (!NT_STATUS_IS_OK(status) || GUID_all_zero(&target_guid)) {
829                         ret = dsdb_module_guid_by_dn(module, dsdb_dn->dn, &target_guid, parent);
830                         if (ret != LDB_SUCCESS) {
831                                 talloc_free(tmp_ctx);
832                                 return ret;
833                         }
834                         ret = dsdb_set_extended_dn_guid(dsdb_dn->dn, &target_guid, "GUID");
835                         if (ret != LDB_SUCCESS) {
836                                 talloc_free(tmp_ctx);
837                                 return ret;
838                         }
839                 }
840
841                 ret = replmd_build_la_val(el->values, v, dsdb_dn, invocationId,
842                                           seq_num, seq_num, now, 0, false);
843                 if (ret != LDB_SUCCESS) {
844                         talloc_free(tmp_ctx);
845                         return ret;
846                 }
847
848                 ret = replmd_add_backlink(module, schema, guid, &target_guid, true, sa, false);
849                 if (ret != LDB_SUCCESS) {
850                         talloc_free(tmp_ctx);
851                         return ret;
852                 }
853         }
854
855         talloc_free(tmp_ctx);
856         return LDB_SUCCESS;
857 }
858
859
860 /*
861   intercept add requests
862  */
863 static int replmd_add(struct ldb_module *module, struct ldb_request *req)
864 {
865         struct samldb_msds_intid_persistant *msds_intid_struct;
866         struct ldb_context *ldb;
867         struct ldb_control *control;
868         struct replmd_replicated_request *ac;
869         enum ndr_err_code ndr_err;
870         struct ldb_request *down_req;
871         struct ldb_message *msg;
872         const DATA_BLOB *guid_blob;
873         struct GUID guid;
874         struct replPropertyMetaDataBlob nmd;
875         struct ldb_val nmd_value;
876         const struct GUID *our_invocation_id;
877
878         /*
879          * The use of a time_t here seems odd, but as the NTTIME
880          * elements are actually declared as NTTIME_1sec in the IDL,
881          * getting a higher resolution timestamp is not required.
882          */
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 == DRSUAPI_ATTID_isDeleted) {
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 == DRSUAPI_ATTID_isDeleted) {
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, "No Deleted Objects container for DN %s",
3172                                                ldb_dn_get_linearized(old_dn));
3173                         talloc_free(tmp_ctx);
3174                         return LDB_ERR_UNWILLING_TO_PERFORM;
3175                 } else {
3176                         new_dn = deleted_objects_dn;
3177                 }
3178         } else {
3179                 new_dn = ldb_dn_get_parent(tmp_ctx, old_dn);
3180                 if (new_dn == NULL) {
3181                         ldb_module_oom(module);
3182                         talloc_free(tmp_ctx);
3183                         return LDB_ERR_OPERATIONS_ERROR;
3184                 }
3185         }
3186
3187         if (deletion_state == OBJECT_NOT_DELETED) {
3188                 /* get the objects GUID from the search we just did */
3189                 guid = samdb_result_guid(old_msg, "objectGUID");
3190
3191                 /* Add a formatted child */
3192                 retb = ldb_dn_add_child_fmt(new_dn, "%s=%s\\0ADEL:%s",
3193                                             rdn_name,
3194                                             ldb_dn_escape_value(tmp_ctx, *rdn_value),
3195                                             GUID_string(tmp_ctx, &guid));
3196                 if (!retb) {
3197                         ldb_asprintf_errstring(ldb, __location__
3198                                                ": Unable to add a formatted child to dn: %s",
3199                                                ldb_dn_get_linearized(new_dn));
3200                         talloc_free(tmp_ctx);
3201                         return LDB_ERR_OPERATIONS_ERROR;
3202                 }
3203
3204                 ret = ldb_msg_add_string(msg, "isDeleted", "TRUE");
3205                 if (ret != LDB_SUCCESS) {
3206                         ldb_asprintf_errstring(ldb, __location__
3207                                                ": Failed to add isDeleted string to the msg");
3208                         talloc_free(tmp_ctx);
3209                         return ret;
3210                 }
3211                 msg->elements[el_count++].flags = LDB_FLAG_MOD_REPLACE;
3212         } else {
3213                 /*
3214                  * No matter what has happened with other renames etc, try again to
3215                  * get this to be under the deleted DN. See MS-DRSR 5.160 RemoveObj
3216                  */
3217
3218                 struct ldb_dn *rdn = ldb_dn_copy(tmp_ctx, old_dn);
3219                 retb = ldb_dn_remove_base_components(rdn, ldb_dn_get_comp_num(rdn) - 1);
3220                 if (!retb) {
3221                         ldb_asprintf_errstring(ldb, __location__
3222                                                ": Unable to add a prepare rdn of %s",
3223                                                ldb_dn_get_linearized(rdn));
3224                         talloc_free(tmp_ctx);
3225                         return LDB_ERR_OPERATIONS_ERROR;
3226                 }
3227                 SMB_ASSERT(ldb_dn_get_comp_num(rdn) == 1);
3228
3229                 retb = ldb_dn_add_child(new_dn, rdn);
3230                 if (!retb) {
3231                         ldb_asprintf_errstring(ldb, __location__
3232                                                ": Unable to add rdn %s to base dn: %s",
3233                                                ldb_dn_get_linearized(rdn),
3234                                                ldb_dn_get_linearized(new_dn));
3235                         talloc_free(tmp_ctx);
3236                         return LDB_ERR_OPERATIONS_ERROR;
3237                 }
3238         }
3239
3240         /*
3241           now we need to modify the object in the following ways:
3242
3243           - add isDeleted=TRUE
3244           - update rDN and name, with new rDN
3245           - remove linked attributes
3246           - remove objectCategory and sAMAccountType
3247           - remove attribs not on the preserved list
3248              - preserved if in above list, or is rDN
3249           - remove all linked attribs from this object
3250           - remove all links from other objects to this object
3251           - add lastKnownParent
3252           - update replPropertyMetaData?
3253
3254           see MS-ADTS "Tombstone Requirements" section 3.1.1.5.5.1.1
3255          */
3256
3257         if (deletion_state == OBJECT_NOT_DELETED) {
3258                 struct ldb_dn *parent_dn = ldb_dn_get_parent(tmp_ctx, old_dn);
3259                 char *parent_dn_str = NULL;
3260
3261                 /* we need the storage form of the parent GUID */
3262                 ret = dsdb_module_search_dn(module, tmp_ctx, &parent_res,
3263                                             parent_dn, NULL,
3264                                             DSDB_FLAG_NEXT_MODULE |
3265                                             DSDB_SEARCH_SHOW_DN_IN_STORAGE_FORMAT |
3266                                             DSDB_SEARCH_REVEAL_INTERNALS|
3267                                             DSDB_SEARCH_SHOW_RECYCLED, req);
3268                 if (ret != LDB_SUCCESS) {
3269                         ldb_asprintf_errstring(ldb_module_get_ctx(module),
3270                                                "repmd_delete: Failed to %s %s, "
3271                                                "because we failed to find it's parent (%s): %s",
3272                                                re_delete ? "re-delete" : "delete",
3273                                                ldb_dn_get_linearized(old_dn),
3274                                                ldb_dn_get_linearized(parent_dn),
3275                                                ldb_errstring(ldb_module_get_ctx(module)));
3276                         talloc_free(tmp_ctx);
3277                         return ret;
3278                 }
3279
3280                 /*
3281                  * Now we can use the DB version,
3282                  * it will have the extended DN info in it
3283                  */
3284                 parent_dn = parent_res->msgs[0]->dn;
3285                 parent_dn_str = ldb_dn_get_extended_linearized(tmp_ctx,
3286                                                                parent_dn,
3287                                                                1);
3288                 if (parent_dn_str == NULL) {
3289                         talloc_free(tmp_ctx);
3290                         return ldb_module_oom(module);
3291                 }
3292
3293                 ret = ldb_msg_add_steal_string(msg, "lastKnownParent",
3294                                                parent_dn_str);
3295                 if (ret != LDB_SUCCESS) {
3296                         ldb_asprintf_errstring(ldb, __location__
3297                                                ": Failed to add lastKnownParent "
3298                                                "string when deleting %s",
3299                                                ldb_dn_get_linearized(old_dn));
3300                         talloc_free(tmp_ctx);
3301                         return ret;
3302                 }
3303                 msg->elements[el_count++].flags = LDB_FLAG_MOD_REPLACE;
3304
3305                 if (next_deletion_state == OBJECT_DELETED) {
3306                         ret = ldb_msg_add_value(msg, "msDS-LastKnownRDN", rdn_value, NULL);
3307                         if (ret != LDB_SUCCESS) {
3308                                 ldb_asprintf_errstring(ldb, __location__
3309                                                        ": Failed to add msDS-LastKnownRDN "
3310                                                        "string when deleting %s",
3311                                                        ldb_dn_get_linearized(old_dn));
3312                                 talloc_free(tmp_ctx);
3313                                 return ret;
3314                         }
3315                         msg->elements[el_count++].flags = LDB_FLAG_MOD_ADD;
3316                 }
3317         }
3318
3319         switch (next_deletion_state) {
3320
3321         case OBJECT_RECYCLED:
3322         case OBJECT_TOMBSTONE:
3323
3324                 /*
3325                  * MS-ADTS 3.1.1.5.5.1.1 Tombstone Requirements
3326                  * describes what must be removed from a tombstone
3327                  * object
3328                  *
3329                  * MS-ADTS 3.1.1.5.5.1.3 Recycled-Object Requirements
3330                  * describes what must be removed from a recycled
3331                  * object
3332                  *
3333                  */
3334
3335                 /*
3336                  * we also mark it as recycled, meaning this object can't be
3337                  * recovered (we are stripping its attributes).
3338                  * This is done only if we have this schema object of course ...
3339                  * This behavior is identical to the one of Windows 2008R2 which
3340                  * always set the isRecycled attribute, even if the recycle-bin is
3341                  * not activated and what ever the forest level is.
3342                  */
3343                 if (dsdb_attribute_by_lDAPDisplayName(schema, "isRecycled") != NULL) {
3344                         ret = ldb_msg_add_string(msg, "isRecycled", "TRUE");
3345                         if (ret != LDB_SUCCESS) {
3346                                 DEBUG(0,(__location__ ": Failed to add isRecycled string to the msg\n"));
3347                                 ldb_module_oom(module);
3348                                 talloc_free(tmp_ctx);
3349                                 return ret;
3350                         }
3351                         msg->elements[el_count++].flags = LDB_FLAG_MOD_REPLACE;
3352                 }
3353
3354                 /* work out which of the old attributes we will be removing */
3355                 for (i=0; i<old_msg->num_elements; i++) {
3356                         const struct dsdb_attribute *sa;
3357                         el = &old_msg->elements[i];
3358                         sa = dsdb_attribute_by_lDAPDisplayName(schema, el->name);
3359                         if (!sa) {
3360                                 talloc_free(tmp_ctx);
3361                                 return LDB_ERR_OPERATIONS_ERROR;
3362                         }
3363                         if (ldb_attr_cmp(el->name, rdn_name) == 0) {
3364                                 /* don't remove the rDN */
3365                                 continue;
3366                         }
3367                         if (sa->linkID && (sa->linkID & 1)) {
3368                                 /*
3369                                   we have a backlink in this object
3370                                   that needs to be removed. We're not
3371                                   allowed to remove it directly
3372                                   however, so we instead setup a
3373                                   modify to delete the corresponding
3374                                   forward link
3375                                  */
3376                                 ret = replmd_delete_remove_link(module, schema, old_dn, el, sa, req);
3377                                 if (ret != LDB_SUCCESS) {
3378                                         const char *old_dn_str
3379                                                 = ldb_dn_get_linearized(old_dn);
3380                                         ldb_asprintf_errstring(ldb,
3381                                                                __location__
3382                                                                ": Failed to remove backlink of "
3383                                                                "%s when deleting %s",
3384                                                                el->name,
3385                                                                old_dn_str);
3386                                         talloc_free(tmp_ctx);
3387                                         return LDB_ERR_OPERATIONS_ERROR;
3388                                 }
3389                                 /* now we continue, which means we
3390                                    won't remove this backlink
3391                                    directly
3392                                 */
3393                                 continue;
3394                         }
3395                         if (!sa->linkID) {
3396                                 if (ldb_attr_in_list(preserved_attrs, el->name)) {
3397                                         continue;
3398                                 }
3399                                 if (sa->searchFlags & SEARCH_FLAG_PRESERVEONDELETE) {
3400                                         continue;
3401                                 }
3402                         }
3403                         ret = ldb_msg_add_empty(msg, el->name, LDB_FLAG_MOD_DELETE, &el);
3404                         if (ret != LDB_SUCCESS) {
3405                                 talloc_free(tmp_ctx);
3406                                 ldb_module_oom(module);
3407                                 return ret;
3408                         }
3409                 }
3410
3411                 break;
3412
3413         case OBJECT_DELETED:
3414                 /*
3415                  * MS-ADTS 3.1.1.5.5.1.2 Deleted-Object Requirements
3416                  * describes what must be removed from a deleted
3417                  * object
3418                  */
3419
3420                 ret = ldb_msg_add_empty(msg, "objectCategory", LDB_FLAG_MOD_REPLACE, NULL);
3421                 if (ret != LDB_SUCCESS) {
3422                         talloc_free(tmp_ctx);
3423                         ldb_module_oom(module);
3424                         return ret;
3425                 }
3426
3427                 ret = ldb_msg_add_empty(msg, "sAMAccountType", LDB_FLAG_MOD_REPLACE, NULL);
3428                 if (ret != LDB_SUCCESS) {
3429                         talloc_free(tmp_ctx);
3430                         ldb_module_oom(module);
3431                         return ret;
3432                 }
3433
3434                 break;
3435
3436         default:
3437                 break;
3438         }
3439
3440         if (deletion_state == OBJECT_NOT_DELETED) {
3441                 const struct dsdb_attribute *sa;
3442
3443                 /* work out what the new rdn value is, for updating the
3444                    rDN and name fields */
3445                 new_rdn_value = ldb_dn_get_rdn_val(new_dn);
3446                 if (new_rdn_value == NULL) {
3447                         talloc_free(tmp_ctx);
3448                         return ldb_operr(ldb);
3449                 }
3450
3451                 sa = dsdb_attribute_by_lDAPDisplayName(schema, rdn_name);
3452                 if (!sa) {
3453                         talloc_free(tmp_ctx);
3454                         return LDB_ERR_OPERATIONS_ERROR;
3455                 }
3456
3457                 ret = ldb_msg_add_value(msg, sa->lDAPDisplayName, new_rdn_value,
3458                                         &el);
3459                 if (ret != LDB_SUCCESS) {
3460                         talloc_free(tmp_ctx);
3461                         return ret;
3462                 }
3463                 el->flags = LDB_FLAG_MOD_REPLACE;
3464
3465                 el = ldb_msg_find_element(old_msg, "name");
3466                 if (el) {
3467                         ret = ldb_msg_add_value(msg, "name", new_rdn_value, &el);
3468                         if (ret != LDB_SUCCESS) {
3469                                 talloc_free(tmp_ctx);
3470                                 return ret;
3471                         }
3472                         el->flags = LDB_FLAG_MOD_REPLACE;
3473                 }
3474         }
3475
3476         /*
3477          * TODO: Per MS-DRSR 5.160 RemoveObj we should remove links directly, not as an originating update!
3478          *
3479          */
3480
3481         /*
3482          * No matter what has happned with other renames, try again to
3483          * get this to be under the deleted DN.
3484          */
3485         if (strcmp(ldb_dn_get_linearized(old_dn), ldb_dn_get_linearized(new_dn)) != 0) {
3486                 /* now rename onto the new DN */
3487                 ret = dsdb_module_rename(module, old_dn, new_dn, DSDB_FLAG_NEXT_MODULE, req);
3488                 if (ret != LDB_SUCCESS){
3489                         DEBUG(0,(__location__ ": Failed to rename object from '%s' to '%s' - %s\n",
3490                                  ldb_dn_get_linearized(old_dn),
3491                                  ldb_dn_get_linearized(new_dn),
3492                                  ldb_errstring(ldb)));
3493                         talloc_free(tmp_ctx);
3494                         return ret;
3495                 }
3496                 msg->dn = new_dn;
3497         }
3498
3499         ret = dsdb_module_modify(module, msg, DSDB_FLAG_OWN_MODULE, req);
3500         if (ret != LDB_SUCCESS) {
3501                 ldb_asprintf_errstring(ldb, "replmd_delete: Failed to modify object %s in delete - %s",
3502                                        ldb_dn_get_linearized(old_dn), ldb_errstring(ldb));
3503                 talloc_free(tmp_ctx);
3504                 return ret;
3505         }
3506
3507         talloc_free(tmp_ctx);
3508
3509         return ldb_module_done(req, NULL, NULL, LDB_SUCCESS);
3510 }
3511
3512 static int replmd_delete(struct ldb_module *module, struct ldb_request *req)
3513 {
3514         return replmd_delete_internals(module, req, false);
3515 }
3516
3517
3518 static int replmd_replicated_request_error(struct replmd_replicated_request *ar, int ret)
3519 {
3520         return ret;
3521 }
3522
3523 static int replmd_replicated_request_werror(struct replmd_replicated_request *ar, WERROR status)
3524 {
3525         int ret = LDB_ERR_OTHER;
3526         /* TODO: do some error mapping */
3527         return ret;
3528 }
3529
3530
3531 static struct replPropertyMetaData1 *
3532 replmd_replPropertyMetaData1_find_attid(struct replPropertyMetaDataBlob *md_blob,
3533                                         enum drsuapi_DsAttributeId attid)
3534 {
3535         uint32_t i;
3536         struct replPropertyMetaDataCtr1 *rpmd_ctr = &md_blob->ctr.ctr1;
3537
3538         for (i = 0; i < rpmd_ctr->count; i++) {
3539                 if (rpmd_ctr->array[i].attid == attid) {
3540                         return &rpmd_ctr->array[i];
3541                 }
3542         }
3543         return NULL;
3544 }
3545
3546
3547 /*
3548    return true if an update is newer than an existing entry
3549    see section 5.11 of MS-ADTS
3550 */
3551 static bool replmd_update_is_newer(const struct GUID *current_invocation_id,
3552                                    const struct GUID *update_invocation_id,
3553                                    uint32_t current_version,
3554                                    uint32_t update_version,
3555                                    NTTIME current_change_time,
3556                                    NTTIME update_change_time)
3557 {
3558         if (update_version != current_version) {
3559                 return update_version > current_version;
3560         }
3561         if (update_change_time != current_change_time) {
3562                 return update_change_time > current_change_time;
3563         }
3564         return GUID_compare(update_invocation_id, current_invocation_id) > 0;
3565 }
3566
3567 static bool replmd_replPropertyMetaData1_is_newer(struct replPropertyMetaData1 *cur_m,
3568                                                   struct replPropertyMetaData1 *new_m)
3569 {
3570         return replmd_update_is_newer(&cur_m->originating_invocation_id,
3571                                       &new_m->originating_invocation_id,
3572                                       cur_m->version,
3573                                       new_m->version,
3574                                       cur_m->originating_change_time,
3575                                       new_m->originating_change_time);
3576 }
3577
3578
3579 /*
3580   form a conflict DN
3581  */
3582 static struct ldb_dn *replmd_conflict_dn(TALLOC_CTX *mem_ctx, struct ldb_dn *dn, struct GUID *guid)
3583 {
3584         const struct ldb_val *rdn_val;
3585         const char *rdn_name;
3586         struct ldb_dn *new_dn;
3587
3588         rdn_val = ldb_dn_get_rdn_val(dn);
3589         rdn_name = ldb_dn_get_rdn_name(dn);
3590         if (!rdn_val || !rdn_name) {
3591                 return NULL;
3592         }
3593
3594         new_dn = ldb_dn_copy(mem_ctx, dn);
3595         if (!new_dn) {
3596                 return NULL;
3597         }
3598
3599         if (!ldb_dn_remove_child_components(new_dn, 1)) {
3600                 return NULL;
3601         }
3602
3603         if (!ldb_dn_add_child_fmt(new_dn, "%s=%s\\0ACNF:%s",
3604                                   rdn_name,
3605                                   ldb_dn_escape_value(new_dn, *rdn_val),
3606                                   GUID_string(new_dn, guid))) {
3607                 return NULL;
3608         }
3609
3610         return new_dn;
3611 }
3612
3613
3614 /*
3615   perform a modify operation which sets the rDN and name attributes to
3616   their current values. This has the effect of changing these
3617   attributes to have been last updated by the current DC. This is
3618   needed to ensure that renames performed as part of conflict
3619   resolution are propogated to other DCs
3620  */
3621 static int replmd_name_modify(struct replmd_replicated_request *ar,
3622                               struct ldb_request *req, struct ldb_dn *dn)
3623 {
3624         struct ldb_message *msg;
3625         const char *rdn_name;
3626         const struct ldb_val *rdn_val;
3627         const struct dsdb_attribute *rdn_attr;
3628         int ret;
3629
3630         msg = ldb_msg_new(req);
3631         if (msg == NULL) {
3632                 goto failed;
3633         }
3634         msg->dn = dn;
3635
3636         rdn_name = ldb_dn_get_rdn_name(dn);
3637         if (rdn_name == NULL) {
3638                 goto failed;
3639         }
3640
3641         /* normalize the rdn attribute name */
3642         rdn_attr = dsdb_attribute_by_lDAPDisplayName(ar->schema, rdn_name);
3643         if (rdn_attr == NULL) {
3644                 goto failed;
3645         }
3646         rdn_name = rdn_attr->lDAPDisplayName;
3647
3648         rdn_val = ldb_dn_get_rdn_val(dn);
3649         if (rdn_val == NULL) {
3650                 goto failed;
3651         }
3652
3653         if (ldb_msg_add_empty(msg, rdn_name, LDB_FLAG_MOD_REPLACE, NULL) != 0) {
3654                 goto failed;
3655         }
3656         if (ldb_msg_add_value(msg, rdn_name, rdn_val, NULL) != 0) {
3657                 goto failed;
3658         }
3659         if (ldb_msg_add_empty(msg, "name", LDB_FLAG_MOD_REPLACE, NULL) != 0) {
3660                 goto failed;
3661         }
3662         if (ldb_msg_add_value(msg, "name", rdn_val, NULL) != 0) {
3663                 goto failed;
3664         }
3665
3666         ret = dsdb_module_modify(ar->module, msg, DSDB_FLAG_OWN_MODULE, req);
3667         if (ret != LDB_SUCCESS) {
3668                 DEBUG(0,(__location__ ": Failed to modify rDN/name of conflict DN '%s' - %s",
3669                          ldb_dn_get_linearized(dn),
3670                          ldb_errstring(ldb_module_get_ctx(ar->module))));
3671                 return ret;
3672         }
3673
3674         talloc_free(msg);
3675
3676         return LDB_SUCCESS;
3677
3678 failed:
3679         talloc_free(msg);
3680         DEBUG(0,(__location__ ": Failed to setup modify rDN/name of conflict DN '%s'",
3681                  ldb_dn_get_linearized(dn)));
3682         return LDB_ERR_OPERATIONS_ERROR;
3683 }
3684
3685
3686 /*
3687   callback for conflict DN handling where we have renamed the incoming
3688   record. After renaming it, we need to ensure the change of name and
3689   rDN for the incoming record is seen as an originating update by this DC.
3690
3691   This also handles updating lastKnownParent for entries sent to lostAndFound
3692  */
3693 static int replmd_op_name_modify_callback(struct ldb_request *req, struct ldb_reply *ares)
3694 {
3695         struct replmd_replicated_request *ar =
3696                 talloc_get_type_abort(req->context, struct replmd_replicated_request);
3697         struct ldb_dn *conflict_dn = NULL;
3698         int ret;
3699
3700         if (ares->error != LDB_SUCCESS) {
3701                 /* call the normal callback for everything except success */
3702                 return replmd_op_callback(req, ares);
3703         }
3704
3705         switch (req->operation) {
3706         case LDB_ADD:
3707                 conflict_dn = req->op.add.message->dn;
3708                 break;
3709         case LDB_MODIFY:
3710                 conflict_dn = req->op.mod.message->dn;
3711                 break;
3712         default:
3713                 smb_panic("replmd_op_name_modify_callback called in unknown circumstances");
3714         }
3715
3716         /* perform a modify of the rDN and name of the record */
3717         ret = replmd_name_modify(ar, req, conflict_dn);
3718         if (ret != LDB_SUCCESS) {
3719                 ares->error = ret;
3720                 return replmd_op_callback(req, ares);
3721         }
3722
3723         if (ar->objs->objects[ar->index_current].last_known_parent) {
3724                 struct ldb_message *msg = ldb_msg_new(req);
3725                 if (msg == NULL) {
3726                         ldb_module_oom(ar->module);
3727                         return LDB_ERR_OPERATIONS_ERROR;
3728                 }
3729
3730                 msg->dn = req->op.add.message->dn;
3731
3732                 ret = ldb_msg_add_steal_string(msg, "lastKnownParent",
3733                                                ldb_dn_get_extended_linearized(msg, ar->objs->objects[ar->index_current].last_known_parent, 1));
3734                 if (ret != LDB_SUCCESS) {
3735                         DEBUG(0,(__location__ ": Failed to add lastKnownParent string to the msg\n"));
3736                         ldb_module_oom(ar->module);
3737                         return ret;
3738                 }
3739                 msg->elements[0].flags = LDB_FLAG_MOD_REPLACE;
3740
3741                 ret = dsdb_module_modify(ar->module, msg, DSDB_FLAG_OWN_MODULE, req);
3742                 if (ret != LDB_SUCCESS) {
3743                         DEBUG(0,(__location__ ": Failed to modify lastKnownParent of lostAndFound DN '%s' - %s",
3744                                  ldb_dn_get_linearized(msg->dn),
3745                                  ldb_errstring(ldb_module_get_ctx(ar->module))));
3746                         return ret;
3747                 }
3748                 TALLOC_FREE(msg);
3749         }
3750
3751         return replmd_op_callback(req, ares);
3752 }
3753
3754 /*
3755   callback for replmd_replicated_apply_add() and replmd_replicated_handle_rename()
3756   This copes with the creation of conflict records in the case where
3757   the DN exists, but with a different objectGUID
3758  */
3759 static int replmd_op_possible_conflict_callback(struct ldb_request *req, struct ldb_reply *ares, int (*callback)(struct ldb_request *req, struct ldb_reply *ares))
3760 {
3761         struct ldb_dn *conflict_dn;
3762         struct replmd_replicated_request *ar =
3763                 talloc_get_type_abort(req->context, struct replmd_replicated_request);
3764         struct ldb_result *res;
3765         const char *attrs[] = { "replPropertyMetaData", "objectGUID", NULL };
3766         int ret;
3767         const struct ldb_val *omd_value;
3768         struct replPropertyMetaDataBlob omd, *rmd;
3769         enum ndr_err_code ndr_err;
3770         bool rename_incoming_record, rodc;
3771         struct replPropertyMetaData1 *rmd_name, *omd_name;
3772         struct ldb_message *msg;
3773
3774         req->callback = callback;
3775
3776         if (ares->error != LDB_ERR_ENTRY_ALREADY_EXISTS) {
3777                 /* call the normal callback for everything except
3778                    conflicts */
3779                 return ldb_module_done(req, ares->controls, ares->response, ares->error);
3780         }
3781
3782         ret = samdb_rodc(ldb_module_get_ctx(ar->module), &rodc);
3783         if (ret != LDB_SUCCESS) {
3784                 ldb_asprintf_errstring(ldb_module_get_ctx(ar->module), "Failed to determine if we are an RODC when attempting to form conflict DN: %s", ldb_errstring(ldb_module_get_ctx(ar->module)));
3785                 return ldb_module_done(req, ares->controls, ares->response, LDB_ERR_OPERATIONS_ERROR);
3786         }
3787         /*
3788          * we have a conflict, and need to decide if we will keep the
3789          * new record or the old record
3790          */
3791
3792         msg = ar->objs->objects[ar->index_current].msg;
3793
3794         switch (req->operation) {
3795         case LDB_ADD:
3796                 conflict_dn = msg->dn;
3797                 break;
3798         case LDB_RENAME:
3799                 conflict_dn = req->op.rename.newdn;
3800                 break;
3801         default:
3802                 return ldb_module_done(req, ares->controls, ares->response, ldb_module_operr(ar->module));
3803         }
3804
3805         if (rodc) {
3806                 /*
3807                  * We are on an RODC, or were a GC for this
3808                  * partition, so we have to fail this until
3809                  * someone who owns the partition sorts it
3810                  * out 
3811                  */
3812                 ldb_asprintf_errstring(ldb_module_get_ctx(ar->module), 
3813                                        "Conflict adding object '%s' from incoming replication as we are read only for the partition.  \n"
3814                                        " - We must fail the operation until a master for this partition resolves the conflict",
3815                                        ldb_dn_get_linearized(conflict_dn));
3816                 goto failed;
3817         }
3818
3819         /*
3820          * first we need the replPropertyMetaData attribute from the
3821          * old record
3822          */
3823         ret = dsdb_module_search_dn(ar->module, req, &res, conflict_dn,
3824                                     attrs,
3825                                     DSDB_FLAG_NEXT_MODULE |
3826                                     DSDB_SEARCH_SHOW_DELETED |
3827                                     DSDB_SEARCH_SHOW_RECYCLED, req);
3828         if (ret != LDB_SUCCESS) {
3829                 DEBUG(0,(__location__ ": Unable to find object for conflicting record '%s'\n",
3830                          ldb_dn_get_linearized(conflict_dn)));
3831                 goto failed;
3832         }
3833
3834         omd_value = ldb_msg_find_ldb_val(res->msgs[0], "replPropertyMetaData");
3835         if (omd_value == NULL) {
3836                 DEBUG(0,(__location__ ": Unable to find replPropertyMetaData for conflicting record '%s'\n",
3837                          ldb_dn_get_linearized(conflict_dn)));
3838                 goto failed;
3839         }
3840
3841         ndr_err = ndr_pull_struct_blob(omd_value, res->msgs[0], &omd,
3842                                        (ndr_pull_flags_fn_t)ndr_pull_replPropertyMetaDataBlob);
3843         if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
3844                 DEBUG(0,(__location__ ": Failed to parse old replPropertyMetaData for %s\n",
3845                          ldb_dn_get_linearized(conflict_dn)));
3846                 goto failed;
3847         }
3848
3849         rmd = ar->objs->objects[ar->index_current].meta_data;
3850
3851         /* we decide which is newer based on the RPMD on the name
3852            attribute.  See [MS-DRSR] ResolveNameConflict */
3853         rmd_name = replmd_replPropertyMetaData1_find_attid(rmd, DRSUAPI_ATTID_name);
3854         omd_name = replmd_replPropertyMetaData1_find_attid(&omd, DRSUAPI_ATTID_name);
3855         if (!rmd_name || !omd_name) {
3856                 DEBUG(0,(__location__ ": Failed to find name attribute in replPropertyMetaData for %s\n",
3857                          ldb_dn_get_linearized(conflict_dn)));
3858                 goto failed;
3859         }
3860
3861         rename_incoming_record = !(ar->objs->dsdb_repl_flags & DSDB_REPL_FLAG_PRIORITISE_INCOMING) &&
3862                 !replmd_replPropertyMetaData1_is_newer(omd_name, rmd_name);
3863
3864         if (rename_incoming_record) {
3865                 struct GUID guid;
3866                 struct ldb_dn *new_dn;
3867
3868                 /*
3869                  * We want to run the original callback here, which
3870                  * will return LDB_ERR_ENTRY_ALREADY_EXISTS to the
3871                  * caller, which will in turn know to rename the
3872                  * incoming record.  The error string is set in case
3873                  * this isn't handled properly at some point in the
3874                  * future.
3875                  */
3876                 if (req->operation == LDB_RENAME) {
3877                         ldb_asprintf_errstring(ldb_module_get_ctx(ar->module),
3878                                                "Unable to handle incoming renames where this would "
3879                                                "create a conflict. Incoming record is %s (caller to handle)\n",
3880                                                ldb_dn_get_extended_linearized(req, conflict_dn, 1));
3881
3882                         goto failed;
3883                 }
3884
3885                 guid = samdb_result_guid(msg, "objectGUID");
3886                 if (GUID_all_zero(&guid)) {
3887                         DEBUG(0,(__location__ ": Failed to find objectGUID for conflicting incoming record %s\n",
3888                                  ldb_dn_get_linearized(conflict_dn)));
3889                         goto failed;
3890                 }
3891                 new_dn = replmd_conflict_dn(req, conflict_dn, &guid);
3892                 if (new_dn == NULL) {
3893                         DEBUG(0,(__location__ ": Failed to form conflict DN for %s\n",
3894                                  ldb_dn_get_linearized(conflict_dn)));
3895                         goto failed;
3896                 }
3897
3898                 DEBUG(2,(__location__ ": Resolving conflict record via incoming rename '%s' -> '%s'\n",
3899                          ldb_dn_get_linearized(conflict_dn), ldb_dn_get_linearized(new_dn)));
3900
3901                 /* re-submit the request, but with a different
3902                    callback, so we don't loop forever. */
3903                 msg->dn = new_dn;
3904                 req->callback = replmd_op_name_modify_callback;
3905
3906                 return ldb_next_request(ar->module, req);
3907         } else {
3908                 /* we are renaming the existing record */
3909                 struct GUID guid;
3910                 struct ldb_dn *new_dn;
3911
3912                 guid = samdb_result_guid(res->msgs[0], "objectGUID");
3913                 if (GUID_all_zero(&guid)) {
3914                         DEBUG(0,(__location__ ": Failed to find objectGUID for existing conflict record %s\n",
3915                                  ldb_dn_get_linearized(conflict_dn)));
3916                         goto failed;
3917                 }
3918
3919                 new_dn = replmd_conflict_dn(req, conflict_dn, &guid);
3920                 if (new_dn == NULL) {
3921                         DEBUG(0,(__location__ ": Failed to form conflict DN for %s\n",
3922                                  ldb_dn_get_linearized(conflict_dn)));
3923                         goto failed;
3924                 }
3925
3926                 DEBUG(2,(__location__ ": Resolving conflict record via existing-record rename '%s' -> '%s'\n",
3927                          ldb_dn_get_linearized(conflict_dn), ldb_dn_get_linearized(new_dn)));
3928
3929                 ret = dsdb_module_rename(ar->module, conflict_dn, new_dn,
3930                                          DSDB_FLAG_OWN_MODULE, req);
3931                 if (ret != LDB_SUCCESS) {
3932                         DEBUG(0,(__location__ ": Failed to rename conflict dn '%s' to '%s' - %s\n",
3933                                  ldb_dn_get_linearized(conflict_dn),
3934                                  ldb_dn_get_linearized(new_dn),
3935                                  ldb_errstring(ldb_module_get_ctx(ar->module))));
3936                         goto failed;
3937                 }
3938
3939                 /*
3940                  * now we need to ensure that the rename is seen as an
3941                  * originating update. We do that with a modify.
3942                  */
3943                 ret = replmd_name_modify(ar, req, new_dn);
3944                 if (ret != LDB_SUCCESS) {
3945                         goto failed;
3946                 }
3947
3948                 return ldb_next_request(ar->module, req);
3949         }
3950
3951 failed:
3952         /* on failure do the original callback. This means replication
3953          * will stop with an error, but there is not much else we can
3954          * do
3955          */
3956         return ldb_module_done(req, ares->controls, ares->response, ares->error);
3957 }
3958
3959 /*
3960   callback for replmd_replicated_apply_add()
3961   This copes with the creation of conflict records in the case where
3962   the DN exists, but with a different objectGUID
3963  */
3964 static int replmd_op_add_callback(struct ldb_request *req, struct ldb_reply *ares)
3965 {
3966         struct replmd_replicated_request *ar =
3967                 talloc_get_type_abort(req->context, struct replmd_replicated_request);
3968
3969         if (ar->objs->objects[ar->index_current].last_known_parent) {
3970                 /* This is like a conflict DN, where we put the object in LostAndFound
3971                    see MS-DRSR 4.1.10.6.10 FindBestParentObject */
3972                 return replmd_op_possible_conflict_callback(req, ares, replmd_op_name_modify_callback);
3973         }
3974
3975         return replmd_op_possible_conflict_callback(req, ares, replmd_op_callback);
3976 }
3977
3978 /*
3979   callback for replmd_replicated_handle_rename()
3980   This copes with the creation of conflict records in the case where
3981   the DN exists, but with a different objectGUID
3982  */
3983 static int replmd_op_rename_callback(struct ldb_request *req, struct ldb_reply *ares)
3984 {
3985         return replmd_op_possible_conflict_callback(req, ares, ldb_modify_default_callback);
3986 }
3987
3988 /*
3989   this is called when a new object comes in over DRS
3990  */
3991 static int replmd_replicated_apply_add(struct replmd_replicated_request *ar)
3992 {
3993         struct ldb_context *ldb;
3994         struct ldb_request *change_req;
3995         enum ndr_err_code ndr_err;
3996         struct ldb_message *msg;
3997         struct replPropertyMetaDataBlob *md;
3998         struct ldb_val md_value;
3999         unsigned int i;
4000         int ret;
4001         bool remote_isDeleted = false;
4002         const struct dsdb_attribute *rdn_sa;
4003         const char *rdn_name;
4004
4005         ldb = ldb_module_get_ctx(ar->module);
4006         msg = ar->objs->objects[ar->index_current].msg;
4007         md = ar->objs->objects[ar->index_current].meta_data;
4008
4009         ret = ldb_sequence_number(ldb, LDB_SEQ_NEXT, &ar->seq_num);
4010         if (ret != LDB_SUCCESS) {
4011                 return replmd_replicated_request_error(ar, ret);
4012         }
4013
4014         ret = ldb_msg_add_value(msg, "objectGUID", &ar->objs->objects[ar->index_current].guid_value, NULL);
4015         if (ret != LDB_SUCCESS) {
4016                 return replmd_replicated_request_error(ar, ret);
4017         }
4018
4019         ret = ldb_msg_add_string(msg, "whenChanged", ar->objs->objects[ar->index_current].when_changed);
4020         if (ret != LDB_SUCCESS) {
4021                 return replmd_replicated_request_error(ar, ret);
4022         }
4023
4024         ret = samdb_msg_add_uint64(ldb, msg, msg, "uSNCreated", ar->seq_num);
4025         if (ret != LDB_SUCCESS) {
4026                 return replmd_replicated_request_error(ar, ret);
4027         }
4028
4029         ret = samdb_msg_add_uint64(ldb, msg, msg, "uSNChanged", ar->seq_num);
4030         if (ret != LDB_SUCCESS) {
4031                 return replmd_replicated_request_error(ar, ret);
4032         }
4033
4034         /* remove any message elements that have zero values */
4035         for (i=0; i<msg->num_elements; i++) {
4036                 struct ldb_message_element *el = &msg->elements[i];
4037
4038                 if (el->num_values == 0) {
4039                         if (ldb_attr_cmp(msg->elements[i].name, "objectClass") == 0) {
4040                                 ldb_asprintf_errstring(ldb, __location__
4041                                                        ": empty objectClass sent on %s, aborting replication\n",
4042                                                        ldb_dn_get_linearized(msg->dn));
4043                                 return replmd_replicated_request_error(ar, LDB_ERR_OBJECT_CLASS_VIOLATION);
4044                         }
4045
4046                         DEBUG(4,(__location__ ": Removing attribute %s with num_values==0\n",
4047                                  el->name));
4048                         memmove(el, el+1, sizeof(*el)*(msg->num_elements - (i+1)));
4049                         msg->num_elements--;
4050                         i--;
4051                         continue;
4052                 }
4053         }
4054
4055         if (DEBUGLVL(4)) {
4056                 char *s = ldb_ldif_message_string(ldb, ar, LDB_CHANGETYPE_ADD, msg);
4057                 DEBUG(4, ("DRS replication add message:\n%s\n", s));
4058                 talloc_free(s);
4059         }
4060
4061         remote_isDeleted = ldb_msg_find_attr_as_bool(msg,
4062                                                      "isDeleted", false);
4063
4064         /*
4065          * the meta data array is already sorted by the caller
4066          */
4067
4068         rdn_name = ldb_dn_get_rdn_name(msg->dn);
4069         if (rdn_name == NULL) {
4070                 ldb_asprintf_errstring(ldb, __location__ ": No rDN for %s?\n", ldb_dn_get_linearized(msg->dn));
4071                 return replmd_replicated_request_error(ar, LDB_ERR_INVALID_DN_SYNTAX);
4072         }
4073
4074         rdn_sa = dsdb_attribute_by_lDAPDisplayName(ar->schema, rdn_name);
4075         if (rdn_sa == NULL) {
4076                 ldb_asprintf_errstring(ldb, ": No schema attribute found for rDN %s for %s\n",
4077                                        rdn_name, ldb_dn_get_linearized(msg->dn));
4078                 return replmd_replicated_request_error(ar, LDB_ERR_UNDEFINED_ATTRIBUTE_TYPE);
4079         }
4080
4081         ret = replmd_replPropertyMetaDataCtr1_verify(ldb, &md->ctr.ctr1, rdn_sa, msg->dn);
4082         if (ret != LDB_SUCCESS) {
4083                 ldb_asprintf_errstring(ldb, "%s: error during DRS repl ADD: %s", __func__, ldb_errstring(ldb));
4084                 return replmd_replicated_request_error(ar, ret);
4085         }
4086
4087         for (i=0; i < md->ctr.ctr1.count; i++) {
4088                 md->ctr.ctr1.array[i].local_usn = ar->seq_num;
4089         }
4090         ndr_err = ndr_push_struct_blob(&md_value, msg, md,
4091                                        (ndr_push_flags_fn_t)ndr_push_replPropertyMetaDataBlob);
4092         if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
4093                 NTSTATUS nt_status = ndr_map_error2ntstatus(ndr_err);
4094                 return replmd_replicated_request_werror(ar, ntstatus_to_werror(nt_status));
4095         }
4096         ret = ldb_msg_add_value(msg, "replPropertyMetaData", &md_value, NULL);
4097         if (ret != LDB_SUCCESS) {
4098                 return replmd_replicated_request_error(ar, ret);
4099         }
4100
4101         replmd_ldb_message_sort(msg, ar->schema);
4102
4103         if (!remote_isDeleted) {
4104                 ret = dsdb_module_schedule_sd_propagation(ar->module,
4105                                                           ar->objs->partition_dn,
4106                                                           msg->dn, true);
4107                 if (ret != LDB_SUCCESS) {
4108                         return replmd_replicated_request_error(ar, ret);
4109                 }
4110         }
4111
4112         ar->isDeleted = remote_isDeleted;
4113
4114         ret = ldb_build_add_req(&change_req,
4115                                 ldb,
4116                                 ar,
4117                                 msg,
4118                                 ar->controls,
4119                                 ar,
4120                                 replmd_op_add_callback,
4121                                 ar->req);
4122         LDB_REQ_SET_LOCATION(change_req);
4123         if (ret != LDB_SUCCESS) return replmd_replicated_request_error(ar, ret);
4124
4125         /* current partition control needed by "repmd_op_callback" */
4126         ret = ldb_request_add_control(change_req,
4127                                       DSDB_CONTROL_CURRENT_PARTITION_OID,
4128                                       false, NULL);
4129         if (ret != LDB_SUCCESS) return replmd_replicated_request_error(ar, ret);
4130
4131         if (ar->objs->dsdb_repl_flags & DSDB_REPL_FLAG_PARTIAL_REPLICA) {
4132                 /* this tells the partition module to make it a
4133                    partial replica if creating an NC */
4134                 ret = ldb_request_add_control(change_req,
4135                                               DSDB_CONTROL_PARTIAL_REPLICA,
4136                                               false, NULL);
4137                 if (ret != LDB_SUCCESS) return replmd_replicated_request_error(ar, ret);
4138         }
4139
4140         return ldb_next_request(ar->module, change_req);
4141 }
4142
4143 static int replmd_replicated_apply_search_for_parent_callback(struct ldb_request *req,
4144                                                               struct ldb_reply *ares)
4145 {
4146         struct replmd_replicated_request *ar = talloc_get_type(req->context,
4147                                                struct replmd_replicated_request);
4148         int ret;
4149
4150         if (!ares) {
4151                 return ldb_module_done(ar->req, NULL, NULL,
4152                                         LDB_ERR_OPERATIONS_ERROR);
4153         }
4154         if (ares->error != LDB_SUCCESS &&
4155             ares->error != LDB_ERR_NO_SUCH_OBJECT) {
4156                 /*
4157                  * TODO: deal with the above error that the parent object doesn't exist
4158                  */
4159
4160                 return ldb_module_done(ar->req, ares->controls,
4161                                         ares->response, ares->error);
4162         }
4163
4164         switch (ares->type) {
4165         case LDB_REPLY_ENTRY:
4166         {
4167                 struct ldb_message *parent_msg = ares->message;
4168                 struct ldb_message *msg = ar->objs->objects[ar->index_current].msg;
4169                 struct ldb_dn *parent_dn;
4170                 int comp_num;
4171
4172                 if (!ldb_msg_check_string_attribute(msg, "isDeleted", "TRUE")
4173                     && ldb_msg_check_string_attribute(parent_msg, "isDeleted", "TRUE")) {
4174                         /* Per MS-DRSR 4.1.10.6.10
4175                          * FindBestParentObject we need to move this
4176                          * new object under a deleted object to
4177                          * lost-and-found */
4178                         struct ldb_dn *nc_root;
4179
4180                         ret = dsdb_find_nc_root(ldb_module_get_ctx(ar->module), msg, msg->dn, &nc_root);
4181                         if (ret == LDB_ERR_NO_SUCH_OBJECT) {
4182                                 ldb_asprintf_errstring(ldb_module_get_ctx(ar->module),
4183                                                        "No suitable NC root found for %s.  "
4184                                                        "We need to move this object because parent object %s "
4185                                                        "is deleted, but this object is not.",
4186                                                        ldb_dn_get_linearized(msg->dn),
4187                                                        ldb_dn_get_linearized(parent_msg->dn));
4188                                 return ldb_module_done(ar->req, NULL, NULL, LDB_ERR_OPERATIONS_ERROR);
4189                         } else if (ret != LDB_SUCCESS) {
4190                                 ldb_asprintf_errstring(ldb_module_get_ctx(ar->module),
4191                                                        "Unable to find NC root for %s: %s. "
4192                                                        "We need to move this object because parent object %s "
4193                                                        "is deleted, but this object is not.",
4194                                                        ldb_dn_get_linearized(msg->dn),
4195                                                        ldb_errstring(ldb_module_get_ctx(ar->module)),
4196                                                        ldb_dn_get_linearized(parent_msg->dn));
4197                                 return ldb_module_done(ar->req, NULL, NULL, LDB_ERR_OPERATIONS_ERROR);
4198                         }
4199                         
4200                         ret = dsdb_wellknown_dn(ldb_module_get_ctx(ar->module), msg,
4201                                                 nc_root,
4202                                                 DS_GUID_LOSTANDFOUND_CONTAINER,
4203                                                 &parent_dn);
4204                         if (ret != LDB_SUCCESS) {
4205                                 ldb_asprintf_errstring(ldb_module_get_ctx(ar->module),
4206                                                        "Unable to find LostAndFound Container for %s "
4207                                                        "in partition %s: %s. "
4208                                                        "We need to move this object because parent object %s "
4209                                                        "is deleted, but this object is not.",
4210                                                        ldb_dn_get_linearized(msg->dn), ldb_dn_get_linearized(nc_root),
4211                                                        ldb_errstring(ldb_module_get_ctx(ar->module)),
4212                                                        ldb_dn_get_linearized(parent_msg->dn));
4213                                 return ldb_module_done(ar->req, NULL, NULL, LDB_ERR_OPERATIONS_ERROR);
4214                         }
4215                         ar->objs->objects[ar->index_current].last_known_parent
4216                                 = talloc_steal(ar->objs->objects[ar->index_current].msg, parent_msg->dn);
4217                 } else {
4218                         parent_dn = parent_msg->dn;
4219                 }
4220
4221                 comp_num = ldb_dn_get_comp_num(msg->dn);
4222                 if (comp_num > 1) {
4223                         if (!ldb_dn_remove_base_components(msg->dn, comp_num - 1)) {
4224                                 talloc_free(ares);
4225                                 return ldb_module_done(ar->req, NULL, NULL, ldb_module_operr(ar->module));
4226                         }
4227                 }
4228                 if (!ldb_dn_add_base(msg->dn, parent_dn)) {
4229                         talloc_free(ares);
4230                         return ldb_module_done(ar->req, NULL, NULL, ldb_module_operr(ar->module));
4231                 }
4232                 break;
4233         }
4234         case LDB_REPLY_REFERRAL:
4235                 /* we ignore referrals */
4236                 break;
4237
4238         case LDB_REPLY_DONE:
4239                 if (ar->search_msg != NULL) {
4240                         ret = replmd_replicated_apply_merge(ar);
4241                 } else {
4242                         ret = replmd_replicated_apply_add(ar);
4243                 }
4244                 if (ret != LDB_SUCCESS) {
4245                         return ldb_module_done(ar->req, NULL, NULL, ret);
4246                 }
4247         }
4248
4249         talloc_free(ares);
4250         return LDB_SUCCESS;
4251 }
4252
4253 /*
4254  * Look for the parent object, so we put the new object in the right
4255  * place This is akin to NameObject in MS-DRSR - this routine and the
4256  * callbacks find the right parent name, and correct name for this
4257  * object
4258  */
4259
4260 static int replmd_replicated_apply_search_for_parent(struct replmd_replicated_request *ar)
4261 {
4262         struct ldb_context *ldb;
4263         int ret;
4264         char *tmp_str;
4265         char *filter;
4266         struct ldb_request *search_req;
4267         static const char *attrs[] = {"isDeleted", NULL};
4268
4269         ldb = ldb_module_get_ctx(ar->module);
4270
4271         if (!ar->objs->objects[ar->index_current].parent_guid_value.data) {
4272                 if (ar->search_msg != NULL) {
4273                         return replmd_replicated_apply_merge(ar);
4274                 } else {
4275                         return replmd_replicated_apply_add(ar);
4276                 }
4277         }
4278
4279         tmp_str = ldb_binary_encode(ar, ar->objs->objects[ar->index_current].parent_guid_value);
4280         if (!tmp_str) return replmd_replicated_request_werror(ar, WERR_NOMEM);
4281
4282         filter = talloc_asprintf(ar, "(objectGUID=%s)", tmp_str);
4283         if (!filter) return replmd_replicated_request_werror(ar, WERR_NOMEM);
4284         talloc_free(tmp_str);
4285
4286         ret = ldb_build_search_req(&search_req,
4287                                    ldb,
4288                                    ar,
4289                                    ar->objs->partition_dn,
4290                                    LDB_SCOPE_SUBTREE,
4291                                    filter,
4292                                    attrs,
4293                                    NULL,
4294                                    ar,
4295                                    replmd_replicated_apply_search_for_parent_callback,
4296                                    ar->req);
4297         LDB_REQ_SET_LOCATION(search_req);
4298
4299         ret = dsdb_request_add_controls(search_req, 
4300                                         DSDB_SEARCH_SHOW_RECYCLED|
4301                                         DSDB_SEARCH_SHOW_DELETED|
4302                                         DSDB_SEARCH_SHOW_EXTENDED_DN);
4303         if (ret != LDB_SUCCESS) {
4304                 return ret;
4305         }
4306
4307         return ldb_next_request(ar->module, search_req);
4308 }
4309
4310 /*
4311   handle renames that come in over DRS replication
4312  */
4313 static int replmd_replicated_handle_rename(struct replmd_replicated_request *ar,
4314                                            struct ldb_message *msg,
4315                                            struct ldb_request *parent)
4316 {
4317         struct ldb_request *req;
4318         int ret;
4319         TALLOC_CTX *tmp_ctx = talloc_new(msg);
4320         struct ldb_result *res;
4321
4322         DEBUG(4,("replmd_replicated_request rename %s => %s\n",
4323                  ldb_dn_get_linearized(ar->search_msg->dn),
4324                  ldb_dn_get_linearized(msg->dn)));
4325
4326
4327         res = talloc_zero(tmp_ctx, struct ldb_result);
4328         if (!res) {
4329                 talloc_free(tmp_ctx);
4330                 return ldb_oom(ldb_module_get_ctx(ar->module));
4331         }
4332
4333         /* pass rename to the next module
4334          * so it doesn't appear as an originating update */
4335         ret = ldb_build_rename_req(&req, ldb_module_get_ctx(ar->module), tmp_ctx,
4336                                    ar->search_msg->dn, msg->dn,
4337                                    NULL,
4338                                    ar,
4339                                    replmd_op_rename_callback,
4340                                    parent);
4341         LDB_REQ_SET_LOCATION(req);
4342         if (ret != LDB_SUCCESS) {
4343                 talloc_free(tmp_ctx);
4344                 return ret;
4345         }
4346
4347         ret = dsdb_request_add_controls(req, DSDB_MODIFY_RELAX);
4348         if (ret != LDB_SUCCESS) {
4349                 talloc_free(tmp_ctx);
4350                 return ret;
4351         }
4352
4353         ret = ldb_next_request(ar->module, req);
4354
4355         if (ret == LDB_SUCCESS) {
4356                 ret = ldb_wait(req->handle, LDB_WAIT_ALL);
4357         }
4358
4359         talloc_free(tmp_ctx);
4360         return ret;
4361 }
4362
4363
4364 static int replmd_replicated_apply_merge(struct replmd_replicated_request *ar)
4365 {
4366         struct ldb_context *ldb;
4367         struct ldb_request *change_req;
4368         enum ndr_err_code ndr_err;
4369         struct ldb_message *msg;
4370         struct replPropertyMetaDataBlob *rmd;
4371         struct replPropertyMetaDataBlob omd;
4372         const struct ldb_val *omd_value;
4373         struct replPropertyMetaDataBlob nmd;
4374         struct ldb_val nmd_value;
4375         unsigned int i;
4376         uint32_t j,ni=0;
4377         unsigned int removed_attrs = 0;
4378         int ret;
4379         int (*callback)(struct ldb_request *req, struct ldb_reply *ares) = replmd_op_callback;
4380         bool isDeleted = false;
4381         bool local_isDeleted = false;
4382         bool remote_isDeleted = false;
4383         bool take_remote_isDeleted = false;
4384         bool sd_updated = false;
4385         bool renamed = false;
4386
4387         ldb = ldb_module_get_ctx(ar->module);
4388         msg = ar->objs->objects[ar->index_current].msg;
4389
4390         rmd = ar->objs->objects[ar->index_current].meta_data;
4391         ZERO_STRUCT(omd);
4392         omd.version = 1;
4393
4394         /* find existing meta data */
4395         omd_value = ldb_msg_find_ldb_val(ar->search_msg, "replPropertyMetaData");
4396         if (omd_value) {
4397                 ndr_err = ndr_pull_struct_blob(omd_value, ar, &omd,
4398                                                (ndr_pull_flags_fn_t)ndr_pull_replPropertyMetaDataBlob);
4399                 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
4400                         NTSTATUS nt_status = ndr_map_error2ntstatus(ndr_err);
4401                         return replmd_replicated_request_werror(ar, ntstatus_to_werror(nt_status));
4402                 }
4403
4404                 if (omd.version != 1) {
4405                         return replmd_replicated_request_werror(ar, WERR_DS_DRA_INTERNAL_ERROR);
4406                 }
4407         }
4408
4409         local_isDeleted = ldb_msg_find_attr_as_bool(ar->search_msg,
4410                                                     "isDeleted", false);
4411         remote_isDeleted = ldb_msg_find_attr_as_bool(msg,
4412                                                      "isDeleted", false);
4413
4414         if (strcmp(ldb_dn_get_linearized(msg->dn), ldb_dn_get_linearized(ar->search_msg->dn)) == 0) {
4415                 ret = LDB_SUCCESS;
4416         } else {
4417                 /*
4418                  * handle renames, even just by case that come in over
4419                  * DRS.  Changes in the parent DN don't hit us here,
4420                  * because the search for a parent will clean up those
4421                  * components.
4422                  *
4423                  * We also have already filtered out the case where
4424                  * the peer has an older name to what we have (see
4425                  * replmd_replicated_apply_search_callback())
4426                  */
4427                 renamed = true;
4428                 ret = replmd_replicated_handle_rename(ar, msg, ar->req);
4429         }
4430
4431         /*
4432          * This particular error code means that we already tried the
4433          * conflict algrorithm, and the existing record name was newer, so we
4434          * need to rename the incoming record
4435          */
4436         if (ret == LDB_ERR_ENTRY_ALREADY_EXISTS) {
4437                 struct GUID guid;
4438                 NTSTATUS status;
4439                 struct ldb_dn *new_dn;
4440                 status = GUID_from_ndr_blob(&ar->objs->objects[ar->index_current].guid_value, &guid);
4441                 /* This really, really can't fail */
4442                 SMB_ASSERT(NT_STATUS_IS_OK(status));
4443
4444                 new_dn = replmd_conflict_dn(msg, msg->dn, &guid);
4445                 if (new_dn == NULL) {
4446                         ldb_asprintf_errstring(ldb_module_get_ctx(ar->module),
4447                                                                   "Failed to form conflict DN for %s\n",
4448                                                                   ldb_dn_get_linearized(msg->dn));
4449
4450                         return replmd_replicated_request_werror(ar, WERR_NOMEM);
4451                 }
4452
4453                 ret = dsdb_module_rename(ar->module, ar->search_msg->dn, new_dn,
4454                                          DSDB_FLAG_NEXT_MODULE, ar->req);
4455                 if (ret != LDB_SUCCESS) {
4456                         ldb_asprintf_errstring(ldb_module_get_ctx(ar->module),
4457                                                "Failed to rename incoming conflicting dn '%s' (was '%s') to '%s' - %s\n",
4458                                                ldb_dn_get_linearized(msg->dn),
4459                                                ldb_dn_get_linearized(ar->search_msg->dn),
4460                                                ldb_dn_get_linearized(new_dn),
4461                                                ldb_errstring(ldb_module_get_ctx(ar->module)));
4462                         return replmd_replicated_request_werror(ar, WERR_DS_DRA_DB_ERROR);
4463                 }
4464
4465                 /* Set the callback to one that will fix up the name to be a conflict DN */
4466                 callback = replmd_op_name_modify_callback;
4467                 msg->dn = new_dn;
4468                 renamed = true;
4469         } else if (ret != LDB_SUCCESS) {
4470                 ldb_debug(ldb, LDB_DEBUG_FATAL,
4471                           "replmd_replicated_request rename %s => %s failed - %s\n",
4472                           ldb_dn_get_linearized(ar->search_msg->dn),
4473                           ldb_dn_get_linearized(msg->dn),
4474                           ldb_errstring(ldb));
4475                 return replmd_replicated_request_werror(ar, WERR_DS_DRA_DB_ERROR);
4476         }
4477
4478         ZERO_STRUCT(nmd);
4479         nmd.version = 1;
4480         nmd.ctr.ctr1.count = omd.ctr.ctr1.count + rmd->ctr.ctr1.count;
4481         nmd.ctr.ctr1.array = talloc_array(ar,
4482                                           struct replPropertyMetaData1,
4483                                           nmd.ctr.ctr1.count);
4484         if (!nmd.ctr.ctr1.array) return replmd_replicated_request_werror(ar, WERR_NOMEM);
4485
4486         /* first copy the old meta data */
4487         for (i=0; i < omd.ctr.ctr1.count; i++) {
4488                 nmd.ctr.ctr1.array[ni]  = omd.ctr.ctr1.array[i];
4489                 ni++;
4490         }
4491
4492         ar->seq_num = 0;
4493         /* now merge in the new meta data */
4494         for (i=0; i < rmd->ctr.ctr1.count; i++) {
4495                 bool found = false;
4496
4497                 for (j=0; j < ni; j++) {
4498                         bool cmp;
4499
4500                         if (rmd->ctr.ctr1.array[i].attid != nmd.ctr.ctr1.array[j].attid) {
4501                                 continue;
4502                         }
4503
4504                         if (ar->objs->dsdb_repl_flags & DSDB_REPL_FLAG_PRIORITISE_INCOMING) {
4505                                 /*
4506                                  * if we compare equal then do an
4507                                  * update. This is used when a client
4508                                  * asks for a FULL_SYNC, and can be
4509                                  * used to recover a corrupt
4510                                  * replica.
4511                                  *
4512                                  * This call is a bit tricky, what we
4513                                  * are doing it turning the 'is_newer'
4514                                  * call into a 'not is older' by
4515                                  * swapping i and j, and negating the
4516                                  * outcome.
4517                                 */
4518                                 cmp = !replmd_replPropertyMetaData1_is_newer(&rmd->ctr.ctr1.array[i],
4519                                                                              &nmd.ctr.ctr1.array[j]);
4520                         } else {
4521                                 cmp = replmd_replPropertyMetaData1_is_newer(&nmd.ctr.ctr1.array[j],
4522                                                                             &rmd->ctr.ctr1.array[i]);
4523                         }
4524                         if (cmp) {
4525                                 /* replace the entry */
4526                                 nmd.ctr.ctr1.array[j] = rmd->ctr.ctr1.array[i];
4527                                 if (ar->seq_num == 0) {
4528                                         ret = ldb_sequence_number(ldb, LDB_SEQ_NEXT, &ar->seq_num);
4529                                         if (ret != LDB_SUCCESS) {
4530                                                 return replmd_replicated_request_error(ar, ret);
4531                                         }
4532                                 }
4533                                 nmd.ctr.ctr1.array[j].local_usn = ar->seq_num;
4534                                 switch (nmd.ctr.ctr1.array[j].attid) {
4535                                 case DRSUAPI_ATTID_ntSecurityDescriptor:
4536                                         sd_updated = true;
4537                                         break;
4538                                 case DRSUAPI_ATTID_isDeleted:
4539                                         take_remote_isDeleted = true;
4540                                         break;
4541                                 default:
4542                                         break;
4543                                 }
4544                                 found = true;
4545                                 break;
4546                         }
4547
4548                         if (rmd->ctr.ctr1.array[i].attid != DRSUAPI_ATTID_instanceType) {
4549                                 DEBUG(3,("Discarding older DRS attribute update to %s on %s from %s\n",
4550                                          msg->elements[i-removed_attrs].name,
4551                                          ldb_dn_get_linearized(msg->dn),
4552                                          GUID_string(ar, &rmd->ctr.ctr1.array[i].originating_invocation_id)));
4553                         }
4554
4555                         /* we don't want to apply this change so remove the attribute */
4556                         ldb_msg_remove_element(msg, &msg->elements[i-removed_attrs]);
4557                         removed_attrs++;
4558
4559                         found = true;
4560                         break;
4561                 }
4562
4563                 if (found) continue;
4564
4565                 nmd.ctr.ctr1.array[ni] = rmd->ctr.ctr1.array[i];
4566                 if (ar->seq_num == 0) {
4567                         ret = ldb_sequence_number(ldb, LDB_SEQ_NEXT, &ar->seq_num);
4568                         if (ret != LDB_SUCCESS) {
4569                                 return replmd_replicated_request_error(ar, ret);
4570                         }
4571                 }
4572                 nmd.ctr.ctr1.array[ni].local_usn = ar->seq_num;
4573                 switch (nmd.ctr.ctr1.array[ni].attid) {
4574                 case DRSUAPI_ATTID_ntSecurityDescriptor:
4575                         sd_updated = true;
4576                         break;
4577                 case DRSUAPI_ATTID_isDeleted:
4578                         take_remote_isDeleted = true;
4579                         break;
4580                 default:
4581                         break;
4582                 }
4583                 ni++;
4584         }
4585
4586         /*
4587          * finally correct the size of the meta_data array
4588          */
4589         nmd.ctr.ctr1.count = ni;
4590
4591         /*
4592          * the rdn attribute (the alias for the name attribute),
4593          * 'cn' for most objects is the last entry in the meta data array
4594          * we have stored
4595          *
4596          * sort the new meta data array
4597          */
4598         ret = replmd_replPropertyMetaDataCtr1_sort_and_verify(ldb, &nmd.ctr.ctr1, ar->schema, msg->dn);
4599         if (ret != LDB_SUCCESS) {
4600                 ldb_asprintf_errstring(ldb, "%s: error during DRS repl merge: %s", __func__, ldb_errstring(ldb));
4601                 return ret;
4602         }
4603
4604         /*
4605          * Work out if this object is deleted, so we can prune any extra attributes.  See MS-DRSR 4.1.10.6.9
4606          * UpdateObject.
4607          *
4608          * This also controls SD propagation below
4609          */
4610         if (take_remote_isDeleted) {
4611                 isDeleted = remote_isDeleted;
4612         } else {
4613                 isDeleted = local_isDeleted;
4614         }
4615
4616         ar->isDeleted = isDeleted;
4617
4618         /*
4619          * check if some replicated attributes left, otherwise skip the ldb_modify() call
4620          */
4621         if (msg->num_elements == 0) {
4622                 ldb_debug(ldb, LDB_DEBUG_TRACE, "replmd_replicated_apply_merge[%u]: skip replace\n",
4623                           ar->index_current);
4624
4625                 return replmd_replicated_apply_isDeleted(ar);
4626         }
4627
4628         ldb_debug(ldb, LDB_DEBUG_TRACE, "replmd_replicated_apply_merge[%u]: replace %u attributes\n",
4629                   ar->index_current, msg->num_elements);
4630
4631         if (renamed) {
4632                 sd_updated = true;
4633         }
4634
4635         if (sd_updated && !isDeleted) {
4636                 ret = dsdb_module_schedule_sd_propagation(ar->module,
4637                                                           ar->objs->partition_dn,
4638                                                           msg->dn, true);
4639                 if (ret != LDB_SUCCESS) {
4640                         return ldb_operr(ldb);
4641                 }
4642         }
4643
4644         /* create the meta data value */
4645         ndr_err = ndr_push_struct_blob(&nmd_value, msg, &nmd,
4646                                        (ndr_push_flags_fn_t)ndr_push_replPropertyMetaDataBlob);
4647         if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
4648                 NTSTATUS nt_status = ndr_map_error2ntstatus(ndr_err);
4649                 return replmd_replicated_request_werror(ar, ntstatus_to_werror(nt_status));
4650         }
4651
4652         /*
4653          * when we know that we'll modify the record, add the whenChanged, uSNChanged
4654          * and replPopertyMetaData attributes
4655          */
4656         ret = ldb_msg_add_string(msg, "whenChanged", ar->objs->objects[ar->index_current].when_changed);
4657         if (ret != LDB_SUCCESS) {
4658                 return replmd_replicated_request_error(ar, ret);
4659         }
4660         ret = samdb_msg_add_uint64(ldb, msg, msg, "uSNChanged", ar->seq_num);
4661         if (ret != LDB_SUCCESS) {
4662                 return replmd_replicated_request_error(ar, ret);
4663         }
4664         ret = ldb_msg_add_value(msg, "replPropertyMetaData", &nmd_value, NULL);
4665         if (ret != LDB_SUCCESS) {
4666                 return replmd_replicated_request_error(ar, ret);
4667         }
4668
4669         replmd_ldb_message_sort(msg, ar->schema);
4670
4671         /* we want to replace the old values */
4672         for (i=0; i < msg->num_elements; i++) {
4673                 msg->elements[i].flags = LDB_FLAG_MOD_REPLACE;
4674                 if (ldb_attr_cmp(msg->elements[i].name, "objectClass") == 0) {
4675                         if (msg->elements[i].num_values == 0) {
4676                                 ldb_asprintf_errstring(ldb, __location__
4677                                                        ": objectClass removed on %s, aborting replication\n",
4678                                                        ldb_dn_get_linearized(msg->dn));
4679                                 return replmd_replicated_request_error(ar, LDB_ERR_OBJECT_CLASS_VIOLATION);
4680                         }
4681                 }
4682         }
4683
4684         if (DEBUGLVL(4)) {
4685                 char *s = ldb_ldif_message_string(ldb, ar, LDB_CHANGETYPE_MODIFY, msg);
4686                 DEBUG(4, ("DRS replication modify message:\n%s\n", s));
4687                 talloc_free(s);
4688         }
4689
4690         ret = ldb_build_mod_req(&change_req,
4691                                 ldb,
4692                                 ar,
4693                                 msg,
4694                                 ar->controls,
4695                                 ar,
4696                                 callback,
4697                                 ar->req);
4698         LDB_REQ_SET_LOCATION(change_req);
4699         if (ret != LDB_SUCCESS) return replmd_replicated_request_error(ar, ret);
4700
4701         /* current partition control needed by "repmd_op_callback" */
4702         ret = ldb_request_add_control(change_req,
4703                                       DSDB_CONTROL_CURRENT_PARTITION_OID,
4704                                       false, NULL);
4705         if (ret != LDB_SUCCESS) return replmd_replicated_request_error(ar, ret);
4706
4707         return ldb_next_request(ar->module, change_req);
4708 }
4709
4710 static int replmd_replicated_apply_search_callback(struct ldb_request *req,
4711                                                    struct ldb_reply *ares)
4712 {
4713         struct replmd_replicated_request *ar = talloc_get_type(req->context,
4714                                                struct replmd_replicated_request);
4715         int ret;
4716
4717         if (!ares) {
4718                 return ldb_module_done(ar->req, NULL, NULL,
4719                                         LDB_ERR_OPERATIONS_ERROR);
4720         }
4721         if (ares->error != LDB_SUCCESS &&
4722             ares->error != LDB_ERR_NO_SUCH_OBJECT) {
4723                 return ldb_module_done(ar->req, ares->controls,
4724                                         ares->response, ares->error);
4725         }
4726
4727         switch (ares->type) {
4728         case LDB_REPLY_ENTRY:
4729                 ar->search_msg = talloc_steal(ar, ares->message);
4730                 break;
4731
4732         case LDB_REPLY_REFERRAL:
4733                 /* we ignore referrals */
4734                 break;
4735
4736         case LDB_REPLY_DONE:
4737         {
4738                 struct replPropertyMetaData1 *md_remote;
4739                 struct replPropertyMetaData1 *md_local;
4740
4741                 struct replPropertyMetaDataBlob omd;
4742                 const struct ldb_val *omd_value;
4743                 struct replPropertyMetaDataBlob *rmd;
4744                 struct ldb_message *msg;
4745
4746                 ar->objs->objects[ar->index_current].last_known_parent = NULL;
4747
4748                 /*
4749                  * This is the ADD case, find the appropriate parent,
4750                  * as this object doesn't exist locally:
4751                  */
4752                 if (ar->search_msg == NULL) {
4753                         ret = replmd_replicated_apply_search_for_parent(ar);
4754                         if (ret != LDB_SUCCESS) {
4755                                 return ldb_module_done(ar->req, NULL, NULL, ret);
4756                         }
4757                         talloc_free(ares);
4758                         return LDB_SUCCESS;
4759                 }
4760
4761                 /*
4762                  * Otherwise, in the MERGE case, work out if we are
4763                  * attempting a rename, and if so find the parent the
4764                  * newly renamed object wants to belong under (which
4765                  * may not be the parent in it's attached string DN
4766                  */
4767                 rmd = ar->objs->objects[ar->index_current].meta_data;
4768                 ZERO_STRUCT(omd);
4769                 omd.version = 1;
4770
4771                 /* find existing meta data */
4772                 omd_value = ldb_msg_find_ldb_val(ar->search_msg, "replPropertyMetaData");
4773                 if (omd_value) {
4774                         enum ndr_err_code ndr_err;
4775                         ndr_err = ndr_pull_struct_blob(omd_value, ar, &omd,
4776                                                        (ndr_pull_flags_fn_t)ndr_pull_replPropertyMetaDataBlob);
4777                         if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
4778                                 NTSTATUS nt_status = ndr_map_error2ntstatus(ndr_err);
4779                                 return replmd_replicated_request_werror(ar, ntstatus_to_werror(nt_status));
4780                         }
4781
4782                         if (omd.version != 1) {
4783                                 return replmd_replicated_request_werror(ar, WERR_DS_DRA_INTERNAL_ERROR);
4784                         }
4785                 }
4786
4787                 /*
4788                  * now we need to check for double renames. We could have a
4789                  * local rename pending which our replication partner hasn't
4790                  * received yet. We choose which one wins by looking at the
4791                  * attribute stamps on the two objects, the newer one wins
4792                  */
4793                 md_remote = replmd_replPropertyMetaData1_find_attid(rmd, DRSUAPI_ATTID_name);
4794                 md_local  = replmd_replPropertyMetaData1_find_attid(&omd, DRSUAPI_ATTID_name);
4795                 /* if there is no name attribute then we have to assume the
4796                    object we've received is in fact newer */
4797                 if (ar->objs->dsdb_repl_flags & DSDB_REPL_FLAG_PRIORITISE_INCOMING ||
4798                     !md_remote || !md_local ||
4799                     replmd_replPropertyMetaData1_is_newer(md_local, md_remote)) {
4800                         ret = replmd_replicated_apply_search_for_parent(ar);
4801                 } else {
4802                         msg = ar->objs->objects[ar->index_current].msg;
4803
4804                         /* Otherwise, just merge on the existing object, force no rename */
4805                         DEBUG(4,(__location__ ": Keeping object %s and rejecting older rename to %s\n",
4806                                  ldb_dn_get_linearized(ar->search_msg->dn),
4807                                  ldb_dn_get_linearized(msg->dn)));
4808
4809                         /*
4810                          * This assignment ensures that the strcmp()
4811                          * in replmd_replicated_apply_merge() avoids
4812                          * the rename call
4813                          */
4814                         msg->dn = ar->search_msg->dn;
4815                         ret = replmd_replicated_apply_merge(ar);
4816                 }
4817                 if (ret != LDB_SUCCESS) {
4818                         return ldb_module_done(ar->req, NULL, NULL, ret);
4819                 }
4820         }
4821         }
4822
4823         talloc_free(ares);
4824         return LDB_SUCCESS;
4825 }
4826
4827 static int replmd_replicated_uptodate_vector(struct replmd_replicated_request *ar);
4828
4829 static int replmd_replicated_apply_next(struct replmd_replicated_request *ar)
4830 {
4831         struct ldb_context *ldb;
4832         int ret;
4833         char *tmp_str;
4834         char *filter;
4835         struct ldb_request *search_req;
4836
4837         if (ar->index_current >= ar->objs->num_objects) {
4838                 /* done with it, go to next stage */
4839                 return replmd_replicated_uptodate_vector(ar);
4840         }
4841
4842         ldb = ldb_module_get_ctx(ar->module);
4843         ar->search_msg = NULL;
4844         ar->isDeleted = false;
4845
4846         tmp_str = ldb_binary_encode(ar, ar->objs->objects[ar->index_current].guid_value);
4847         if (!tmp_str) return replmd_replicated_request_werror(ar, WERR_NOMEM);
4848
4849         filter = talloc_asprintf(ar, "(objectGUID=%s)", tmp_str);
4850         if (!filter) return replmd_replicated_request_werror(ar, WERR_NOMEM);
4851         talloc_free(tmp_str);
4852
4853         ret = ldb_build_search_req(&search_req,
4854                                    ldb,
4855                                    ar,
4856                                    ar->objs->partition_dn,
4857                                    LDB_SCOPE_SUBTREE,
4858                                    filter,
4859                                    NULL,
4860                                    NULL,
4861                                    ar,
4862                                    replmd_replicated_apply_search_callback,
4863                                    ar->req);
4864         LDB_REQ_SET_LOCATION(search_req);
4865
4866         ret = dsdb_request_add_controls(search_req, DSDB_SEARCH_SHOW_RECYCLED);
4867
4868         if (ret != LDB_SUCCESS) {
4869                 return ret;
4870         }
4871
4872         return ldb_next_request(ar->module, search_req);
4873 }
4874
4875 /*
4876  * This is essentially a wrapper for replmd_replicated_apply_next()
4877  *
4878  * This is needed to ensure that both codepaths call this handler.
4879  */
4880 static int replmd_replicated_apply_isDeleted(struct replmd_replicated_request *ar)
4881 {
4882         struct ldb_dn *deleted_objects_dn;
4883         struct ldb_message *msg = ar->objs->objects[ar->index_current].msg;
4884         int ret = dsdb_get_deleted_objects_dn(ldb_module_get_ctx(ar->module), msg, msg->dn,
4885                                               &deleted_objects_dn);
4886         if (ar->isDeleted && (ret != LDB_SUCCESS || ldb_dn_compare(msg->dn, deleted_objects_dn) != 0)) {
4887                 /*
4888                  * Do a delete here again, so that if there is
4889                  * anything local that conflicts with this
4890                  * object being deleted, it is removed.  This
4891                  * includes links.  See MS-DRSR 4.1.10.6.9
4892                  * UpdateObject.
4893                  *
4894                  * If the object is already deleted, and there
4895                  * is no more work required, it doesn't do
4896                  * anything.
4897                  */
4898
4899                 /* This has been updated to point to the DN we eventually did the modify on */
4900
4901                 struct ldb_request *del_req;
4902                 struct ldb_result *res;
4903
4904                 TALLOC_CTX *tmp_ctx = talloc_new(ar);
4905                 if (!tmp_ctx) {
4906                         ret = ldb_oom(ldb_module_get_ctx(ar->module));
4907                         return ret;
4908                 }
4909
4910                 res = talloc_zero(tmp_ctx, struct ldb_result);
4911                 if (!res) {
4912                         ret = ldb_oom(ldb_module_get_ctx(ar->module));
4913                         talloc_free(tmp_ctx);
4914                         return ret;
4915                 }
4916
4917                 /* Build a delete request, which hopefully will artually turn into nothing */
4918                 ret = ldb_build_del_req(&del_req, ldb_module_get_ctx(ar->module), tmp_ctx,
4919                                         msg->dn,
4920                                         NULL,
4921                                         res,
4922                                         ldb_modify_default_callback,
4923                                         ar->req);
4924                 LDB_REQ_SET_LOCATION(del_req);
4925                 if (ret != LDB_SUCCESS) {
4926                         talloc_free(tmp_ctx);
4927                         return ret;
4928                 }
4929
4930                 /*
4931                  * This is the guts of the call, call back
4932                  * into our delete code, but setting the
4933                  * re_delete flag so we delete anything that
4934                  * shouldn't be there on a deleted or recycled
4935                  * object
4936                  */
4937                 ret = replmd_delete_internals(ar->module, del_req, true);
4938                 if (ret == LDB_SUCCESS) {
4939                         ret = ldb_wait(del_req->handle, LDB_WAIT_ALL);
4940                 }
4941
4942                 talloc_free(tmp_ctx);
4943                 if (ret != LDB_SUCCESS) {
4944                         return ret;
4945                 }
4946         }
4947
4948         ar->index_current++;
4949         return replmd_replicated_apply_next(ar);
4950 }
4951
4952 static int replmd_replicated_uptodate_modify_callback(struct ldb_request *req,
4953                                                       struct ldb_reply *ares)
4954 {
4955         struct ldb_context *ldb;
4956         struct replmd_replicated_request *ar = talloc_get_type(req->context,
4957                                                struct replmd_replicated_request);
4958         ldb = ldb_module_get_ctx(ar->module);
4959
4960         if (!ares) {
4961                 return ldb_module_done(ar->req, NULL, NULL,
4962                                         LDB_ERR_OPERATIONS_ERROR);
4963         }
4964         if (ares->error != LDB_SUCCESS) {
4965                 return ldb_module_done(ar->req, ares->controls,
4966                                         ares->response, ares->error);
4967         }
4968
4969         if (ares->type != LDB_REPLY_DONE) {
4970                 ldb_asprintf_errstring(ldb, "Invalid LDB reply type %d", ares->type);
4971                 return ldb_module_done(ar->req, NULL, NULL,
4972                                         LDB_ERR_OPERATIONS_ERROR);
4973         }
4974
4975         talloc_free(ares);
4976
4977         return ldb_module_done(ar->req, NULL, NULL, LDB_SUCCESS);
4978 }
4979
4980 static int replmd_replicated_uptodate_modify(struct replmd_replicated_request *ar)
4981 {
4982         struct ldb_context *ldb;
4983         struct ldb_request *change_req;
4984         enum ndr_err_code ndr_err;
4985         struct ldb_message *msg;
4986         struct replUpToDateVectorBlob ouv;
4987         const struct ldb_val *ouv_value;
4988         const struct drsuapi_DsReplicaCursor2CtrEx *ruv;
4989         struct replUpToDateVectorBlob nuv;
4990         struct ldb_val nuv_value;
4991         struct ldb_message_element *nuv_el = NULL;
4992         const struct GUID *our_invocation_id;
4993         struct ldb_message_element *orf_el = NULL;
4994         struct repsFromToBlob nrf;
4995         struct ldb_val *nrf_value = NULL;
4996         struct ldb_message_element *nrf_el = NULL;
4997         unsigned int i;
4998         uint32_t j,ni=0;
4999         bool found = false;
5000         time_t t = time(NULL);
5001         NTTIME now;
5002         int ret;
5003         uint32_t instanceType;
5004
5005         ldb = ldb_module_get_ctx(ar->module);
5006         ruv = ar->objs->uptodateness_vector;
5007         ZERO_STRUCT(ouv);
5008         ouv.version = 2;
5009         ZERO_STRUCT(nuv);
5010         nuv.version = 2;
5011
5012         unix_to_nt_time(&now, t);
5013
5014         if (ar->search_msg == NULL) {
5015                 /* this happens for a REPL_OBJ call where we are
5016                    creating the target object by replicating it. The
5017                    subdomain join code does this for the partition DN
5018                 */
5019                 DEBUG(4,(__location__ ": Skipping UDV and repsFrom update as no target DN\n"));
5020                 return ldb_module_done(ar->req, NULL, NULL, LDB_SUCCESS);
5021         }
5022
5023         instanceType = ldb_msg_find_attr_as_uint(ar->search_msg, "instanceType", 0);
5024         if (! (instanceType & INSTANCE_TYPE_IS_NC_HEAD)) {
5025                 DEBUG(4,(__location__ ": Skipping UDV and repsFrom update as not NC root: %s\n",
5026                          ldb_dn_get_linearized(ar->search_msg->dn)));
5027                 return ldb_module_done(ar->req, NULL, NULL, LDB_SUCCESS);
5028         }
5029
5030         /*
5031          * first create the new replUpToDateVector
5032          */
5033         ouv_value = ldb_msg_find_ldb_val(ar->search_msg, "replUpToDateVector");
5034         if (ouv_value) {
5035                 ndr_err = ndr_pull_struct_blob(ouv_value, ar, &ouv,
5036                                                (ndr_pull_flags_fn_t)ndr_pull_replUpToDateVectorBlob);
5037                 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
5038                         NTSTATUS nt_status = ndr_map_error2ntstatus(ndr_err);
5039                         return replmd_replicated_request_werror(ar, ntstatus_to_werror(nt_status));
5040                 }
5041
5042                 if (ouv.version != 2) {
5043                         return replmd_replicated_request_werror(ar, WERR_DS_DRA_INTERNAL_ERROR);
5044                 }
5045         }
5046
5047         /*
5048          * the new uptodateness vector will at least
5049          * contain 1 entry, one for the source_dsa
5050          *
5051          * plus optional values from our old vector and the one from the source_dsa
5052          */
5053         nuv.ctr.ctr2.count = ouv.ctr.ctr2.count;
5054         if (ruv) nuv.ctr.ctr2.count += ruv->count;
5055         nuv.ctr.ctr2.cursors = talloc_array(ar,
5056                                             struct drsuapi_DsReplicaCursor2,
5057                                             nuv.ctr.ctr2.count);
5058         if (!nuv.ctr.ctr2.cursors) return replmd_replicated_request_werror(ar, WERR_NOMEM);
5059
5060         /* first copy the old vector */
5061         for (i=0; i < ouv.ctr.ctr2.count; i++) {
5062                 nuv.ctr.ctr2.cursors[ni] = ouv.ctr.ctr2.cursors[i];
5063                 ni++;
5064         }
5065
5066         /* get our invocation_id if we have one already attached to the ldb */
5067         our_invocation_id = samdb_ntds_invocation_id(ldb);
5068         if (our_invocation_id == NULL) {
5069                 DEBUG(0, ("repl_meta_data: Could not find our own server's invocationID!\n"));
5070                 return replmd_replicated_request_werror(ar, WERR_DS_DRA_INTERNAL_ERROR);                
5071         }
5072
5073         /* merge in the source_dsa vector is available */
5074         for (i=0; (ruv && i < ruv->count); i++) {
5075                 found = false;
5076
5077                 if (our_invocation_id &&
5078                     GUID_equal(&ruv->cursors[i].source_dsa_invocation_id,
5079                                our_invocation_id)) {
5080                         continue;
5081                 }
5082
5083                 for (j=0; j < ni; j++) {
5084                         if (!GUID_equal(&ruv->cursors[i].source_dsa_invocation_id,
5085                                         &nuv.ctr.ctr2.cursors[j].source_dsa_invocation_id)) {
5086                                 continue;
5087                         }
5088
5089                         found = true;
5090
5091                         if (ruv->cursors[i].highest_usn > nuv.ctr.ctr2.cursors[j].highest_usn) {
5092                                 nuv.ctr.ctr2.cursors[j] = ruv->cursors[i];
5093                         }
5094                         break;
5095                 }
5096
5097                 if (found) continue;
5098
5099                 /* if it's not there yet, add it */
5100                 nuv.ctr.ctr2.cursors[ni] = ruv->cursors[i];
5101                 ni++;
5102         }
5103
5104         /*
5105          * finally correct the size of the cursors array
5106          */
5107         nuv.ctr.ctr2.count = ni;
5108
5109         /*
5110          * sort the cursors
5111          */
5112         TYPESAFE_QSORT(nuv.ctr.ctr2.cursors, nuv.ctr.ctr2.count, drsuapi_DsReplicaCursor2_compare);
5113
5114         /*
5115          * create the change ldb_message
5116          */
5117         msg = ldb_msg_new(ar);
5118         if (!msg) return replmd_replicated_request_werror(ar, WERR_NOMEM);
5119         msg->dn = ar->search_msg->dn;
5120
5121         ndr_err = ndr_push_struct_blob(&nuv_value, msg, &nuv,
5122                                        (ndr_push_flags_fn_t)ndr_push_replUpToDateVectorBlob);
5123         if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
5124                 NTSTATUS nt_status = ndr_map_error2ntstatus(ndr_err);
5125                 return replmd_replicated_request_werror(ar, ntstatus_to_werror(nt_status));
5126         }
5127         ret = ldb_msg_add_value(msg, "replUpToDateVector", &nuv_value, &nuv_el);
5128         if (ret != LDB_SUCCESS) {
5129                 return replmd_replicated_request_error(ar, ret);
5130         }
5131         nuv_el->flags = LDB_FLAG_MOD_REPLACE;
5132
5133         /*
5134          * now create the new repsFrom value from the given repsFromTo1 structure
5135          */
5136         ZERO_STRUCT(nrf);
5137         nrf.version                                     = 1;
5138         nrf.ctr.ctr1                                    = *ar->objs->source_dsa;
5139         nrf.ctr.ctr1.last_attempt                       = now;
5140         nrf.ctr.ctr1.last_success                       = now;
5141         nrf.ctr.ctr1.result_last_attempt                = WERR_OK;
5142
5143         /*
5144          * first see if we already have a repsFrom value for the current source dsa
5145          * if so we'll later replace this value
5146          */
5147         orf_el = ldb_msg_find_element(ar->search_msg, "repsFrom");
5148         if (orf_el) {
5149                 for (i=0; i < orf_el->num_values; i++) {
5150                         struct repsFromToBlob *trf;
5151
5152                         trf = talloc(ar, struct repsFromToBlob);
5153                         if (!trf) return replmd_replicated_request_werror(ar, WERR_NOMEM);
5154
5155                         ndr_err = ndr_pull_struct_blob(&orf_el->values[i], trf, trf,
5156                                                        (ndr_pull_flags_fn_t)ndr_pull_repsFromToBlob);
5157                         if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
5158                                 NTSTATUS nt_status = ndr_map_error2ntstatus(ndr_err);
5159                                 return replmd_replicated_request_werror(ar, ntstatus_to_werror(nt_status));
5160                         }
5161
5162                         if (trf->version != 1) {
5163                                 return replmd_replicated_request_werror(ar, WERR_DS_DRA_INTERNAL_ERROR);
5164                         }
5165
5166                         /*
5167                          * we compare the source dsa objectGUID not the invocation_id
5168                          * because we want only one repsFrom value per source dsa
5169                          * and when the invocation_id of the source dsa has changed we don't need
5170                          * the old repsFrom with the old invocation_id
5171                          */
5172                         if (!GUID_equal(&trf->ctr.ctr1.source_dsa_obj_guid,
5173                                         &ar->objs->source_dsa->source_dsa_obj_guid)) {
5174                                 talloc_free(trf);
5175                                 continue;
5176                         }
5177
5178                         talloc_free(trf);
5179                         nrf_value = &orf_el->values[i];
5180                         break;
5181                 }
5182
5183                 /*
5184                  * copy over all old values to the new ldb_message
5185                  */
5186                 ret = ldb_msg_add_empty(msg, "repsFrom", 0, &nrf_el);
5187                 if (ret != LDB_SUCCESS) return replmd_replicated_request_error(ar, ret);
5188                 *nrf_el = *orf_el;
5189         }
5190
5191         /*
5192          * if we haven't found an old repsFrom value for the current source dsa
5193          * we'll add a new value
5194          */
5195         if (!nrf_value) {
5196                 struct ldb_val zero_value;
5197                 ZERO_STRUCT(zero_value);
5198                 ret = ldb_msg_add_value(msg, "repsFrom", &zero_value, &nrf_el);
5199                 if (ret != LDB_SUCCESS) return replmd_replicated_request_error(ar, ret);
5200
5201                 nrf_value = &nrf_el->values[nrf_el->num_values - 1];
5202         }
5203
5204         /* we now fill the value which is already attached to ldb_message */
5205         ndr_err = ndr_push_struct_blob(nrf_value, msg,
5206                                        &nrf,
5207                                        (ndr_push_flags_fn_t)ndr_push_repsFromToBlob);
5208         if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
5209                 NTSTATUS nt_status = ndr_map_error2ntstatus(ndr_err);
5210                 return replmd_replicated_request_werror(ar, ntstatus_to_werror(nt_status));
5211         }
5212
5213         /*
5214          * the ldb_message_element for the attribute, has all the old values and the new one
5215          * so we'll replace the whole attribute with all values
5216          */
5217         nrf_el->flags = LDB_FLAG_MOD_REPLACE;
5218
5219         if (CHECK_DEBUGLVL(4)) {
5220                 char *s = ldb_ldif_message_string(ldb, ar, LDB_CHANGETYPE_MODIFY, msg);
5221                 DEBUG(4, ("DRS replication uptodate modify message:\n%s\n", s));
5222                 talloc_free(s);
5223         }
5224
5225         /* prepare the ldb_modify() request */
5226         ret = ldb_build_mod_req(&change_req,
5227                                 ldb,
5228                                 ar,
5229                                 msg,
5230                                 ar->controls,
5231                                 ar,
5232                                 replmd_replicated_uptodate_modify_callback,
5233                                 ar->req);
5234         LDB_REQ_SET_LOCATION(change_req);
5235         if (ret != LDB_SUCCESS) return replmd_replicated_request_error(ar, ret);
5236
5237         return ldb_next_request(ar->module, change_req);
5238 }
5239
5240 static int replmd_replicated_uptodate_search_callback(struct ldb_request *req,
5241                                                       struct ldb_reply *ares)
5242 {
5243         struct replmd_replicated_request *ar = talloc_get_type(req->context,
5244                                                struct replmd_replicated_request);
5245         int ret;
5246
5247         if (!ares) {
5248                 return ldb_module_done(ar->req, NULL, NULL,
5249                                         LDB_ERR_OPERATIONS_ERROR);
5250         }
5251         if (ares->error != LDB_SUCCESS &&
5252             ares->error != LDB_ERR_NO_SUCH_OBJECT) {
5253                 return ldb_module_done(ar->req, ares->controls,
5254                                         ares->response, ares->error);
5255         }
5256
5257         switch (ares->type) {
5258         case LDB_REPLY_ENTRY:
5259                 ar->search_msg = talloc_steal(ar, ares->message);
5260                 break;
5261
5262         case LDB_REPLY_REFERRAL:
5263                 /* we ignore referrals */
5264                 break;
5265
5266         case LDB_REPLY_DONE:
5267                 ret = replmd_replicated_uptodate_modify(ar);
5268                 if (ret != LDB_SUCCESS) {
5269                         return ldb_module_done(ar->req, NULL, NULL, ret);
5270                 }
5271         }
5272
5273         talloc_free(ares);
5274         return LDB_SUCCESS;
5275 }
5276
5277
5278 static int replmd_replicated_uptodate_vector(struct replmd_replicated_request *ar)
5279 {
5280         struct ldb_context *ldb;
5281         int ret;
5282         static const char *attrs[] = {
5283                 "replUpToDateVector",
5284                 "repsFrom",
5285                 "instanceType",
5286                 NULL
5287         };
5288         struct ldb_request *search_req;
5289
5290         ldb = ldb_module_get_ctx(ar->module);
5291         ar->search_msg = NULL;
5292
5293         ret = ldb_build_search_req(&search_req,
5294                                    ldb,
5295                                    ar,
5296                                    ar->objs->partition_dn,
5297                                    LDB_SCOPE_BASE,
5298                                    "(objectClass=*)",
5299                                    attrs,
5300                                    NULL,
5301                                    ar,
5302                                    replmd_replicated_uptodate_search_callback,
5303                                    ar->req);
5304         LDB_REQ_SET_LOCATION(search_req);
5305         if (ret != LDB_SUCCESS) return replmd_replicated_request_error(ar, ret);
5306
5307         return ldb_next_request(ar->module, search_req);
5308 }
5309
5310
5311
5312 static int replmd_extended_replicated_objects(struct ldb_module *module, struct ldb_request *req)
5313 {
5314         struct ldb_context *ldb;
5315         struct dsdb_extended_replicated_objects *objs;
5316         struct replmd_replicated_request *ar;
5317         struct ldb_control **ctrls;
5318         int ret;
5319         uint32_t i;
5320         struct replmd_private *replmd_private =
5321                 talloc_get_type(ldb_module_get_private(module), struct replmd_private);
5322         struct dsdb_control_replicated_update *rep_update;
5323
5324         ldb = ldb_module_get_ctx(module);
5325
5326         ldb_debug(ldb, LDB_DEBUG_TRACE, "replmd_extended_replicated_objects\n");
5327
5328         objs = talloc_get_type(req->op.extended.data, struct dsdb_extended_replicated_objects);
5329         if (!objs) {
5330                 ldb_debug(ldb, LDB_DEBUG_FATAL, "replmd_extended_replicated_objects: invalid extended data\n");
5331                 return LDB_ERR_PROTOCOL_ERROR;
5332         }
5333
5334         if (objs->version != DSDB_EXTENDED_REPLICATED_OBJECTS_VERSION) {
5335                 ldb_debug(ldb, LDB_DEBUG_FATAL, "replmd_extended_replicated_objects: extended data invalid version [%u != %u]\n",
5336                           objs->version, DSDB_EXTENDED_REPLICATED_OBJECTS_VERSION);
5337                 return LDB_ERR_PROTOCOL_ERROR;
5338         }
5339
5340         ar = replmd_ctx_init(module, req);
5341         if (!ar)
5342                 return LDB_ERR_OPERATIONS_ERROR;
5343
5344         /* Set the flags to have the replmd_op_callback run over the full set of objects */
5345         ar->apply_mode = true;
5346         ar->objs = objs;
5347         ar->schema = dsdb_get_schema(ldb, ar);
5348         if (!ar->schema) {
5349                 ldb_debug_set(ldb, LDB_DEBUG_FATAL, "replmd_ctx_init: no loaded schema found\n");
5350                 talloc_free(ar);
5351                 DEBUG(0,(__location__ ": %s\n", ldb_errstring(ldb)));
5352                 return LDB_ERR_CONSTRAINT_VIOLATION;
5353         }
5354
5355         ctrls = req->controls;
5356
5357         if (req->controls) {
5358                 req->controls = talloc_memdup(ar, req->controls,
5359                                               talloc_get_size(req->controls));
5360                 if (!req->controls) return replmd_replicated_request_werror(ar, WERR_NOMEM);
5361         }
5362
5363         /* This allows layers further down to know if a change came in
5364            over replication and what the replication flags were */
5365         rep_update = talloc_zero(ar, struct dsdb_control_replicated_update);
5366         if (rep_update == NULL) {
5367                 return ldb_module_oom(module);
5368         }
5369         rep_update->dsdb_repl_flags = objs->dsdb_repl_flags;
5370
5371         ret = ldb_request_add_control(req, DSDB_CONTROL_REPLICATED_UPDATE_OID, false, rep_update);
5372         if (ret != LDB_SUCCESS) {
5373                 return ret;
5374         }
5375
5376         /* If this change contained linked attributes in the body
5377          * (rather than in the links section) we need to update
5378          * backlinks in linked_attributes */
5379         ret = ldb_request_add_control(req, DSDB_CONTROL_APPLY_LINKS, false, NULL);
5380         if (ret != LDB_SUCCESS) {
5381                 return ret;
5382         }
5383
5384         ar->controls = req->controls;
5385         req->controls = ctrls;
5386
5387         DEBUG(4,("linked_attributes_count=%u\n", objs->linked_attributes_count));
5388
5389         /* save away the linked attributes for the end of the
5390            transaction */
5391         for (i=0; i<ar->objs->linked_attributes_count; i++) {
5392                 struct la_entry *la_entry;
5393
5394                 if (replmd_private->la_ctx == NULL) {
5395                         replmd_private->la_ctx = talloc_new(replmd_private);
5396                 }
5397                 la_entry = talloc(replmd_private->la_ctx, struct la_entry);
5398                 if (la_entry == NULL) {
5399                         ldb_oom(ldb);
5400                         return LDB_ERR_OPERATIONS_ERROR;
5401                 }
5402                 la_entry->la = talloc(la_entry, struct drsuapi_DsReplicaLinkedAttribute);
5403                 if (la_entry->la == NULL) {
5404                         talloc_free(la_entry);
5405                         ldb_oom(ldb);
5406                         return LDB_ERR_OPERATIONS_ERROR;
5407                 }
5408                 *la_entry->la = ar->objs->linked_attributes[i];
5409
5410                 /* we need to steal the non-scalars so they stay
5411                    around until the end of the transaction */
5412                 talloc_steal(la_entry->la, la_entry->la->identifier);
5413                 talloc_steal(la_entry->la, la_entry->la->value.blob);
5414
5415                 DLIST_ADD(replmd_private->la_list, la_entry);
5416         }
5417
5418         return replmd_replicated_apply_next(ar);
5419 }
5420
5421 /*
5422   process one linked attribute structure
5423  */
5424 static int replmd_process_linked_attribute(struct ldb_module *module,
5425                                            struct la_entry *la_entry,
5426                                            struct ldb_request *parent)
5427 {
5428         struct drsuapi_DsReplicaLinkedAttribute *la = la_entry->la;
5429         struct ldb_context *ldb = ldb_module_get_ctx(module);
5430         struct ldb_message *msg;
5431         struct ldb_message *target_msg = NULL;
5432         TALLOC_CTX *tmp_ctx = talloc_new(la_entry);
5433         const struct dsdb_schema *schema = dsdb_get_schema(ldb, tmp_ctx);
5434         int ret;
5435         const struct dsdb_attribute *attr;
5436         struct dsdb_dn *dsdb_dn;
5437         uint64_t seq_num = 0;
5438         struct ldb_message_element *old_el;
5439         WERROR status;
5440         time_t t = time(NULL);
5441         struct ldb_result *res;
5442         struct ldb_result *target_res;
5443         const char *attrs[4];
5444         const char *attrs2[] = { "isDeleted", "isRecycled", NULL };
5445         struct parsed_dn *pdn_list, *pdn;
5446         struct GUID guid = GUID_zero();
5447         NTSTATUS ntstatus;
5448         bool active = (la->flags & DRSUAPI_DS_LINKED_ATTRIBUTE_FLAG_ACTIVE)?true:false;
5449         const struct GUID *our_invocation_id;
5450
5451         enum deletion_state deletion_state = OBJECT_NOT_DELETED;
5452         enum deletion_state target_deletion_state = OBJECT_NOT_DELETED;
5453
5454 /*
5455 linked_attributes[0]:
5456      &objs->linked_attributes[i]: struct drsuapi_DsReplicaLinkedAttribute
5457         identifier               : *
5458             identifier: struct drsuapi_DsReplicaObjectIdentifier
5459                 __ndr_size               : 0x0000003a (58)
5460                 __ndr_size_sid           : 0x00000000 (0)
5461                 guid                     : 8e95b6a9-13dd-4158-89db-3220a5be5cc7
5462                 sid                      : S-0-0
5463                 __ndr_size_dn            : 0x00000000 (0)
5464                 dn                       : ''
5465         attid                    : DRSUAPI_ATTID_member (0x1F)
5466         value: struct drsuapi_DsAttributeValue
5467             __ndr_size               : 0x0000007e (126)
5468             blob                     : *
5469                 blob                     : DATA_BLOB length=126
5470         flags                    : 0x00000001 (1)
5471                1: DRSUAPI_DS_LINKED_ATTRIBUTE_FLAG_ACTIVE
5472         originating_add_time     : Wed Sep  2 22:20:01 2009 EST
5473         meta_data: struct drsuapi_DsReplicaMetaData
5474             version                  : 0x00000015 (21)
5475             originating_change_time  : Wed Sep  2 23:39:07 2009 EST
5476             originating_invocation_id: 794640f3-18cf-40ee-a211-a93992b67a64
5477             originating_usn          : 0x000000000001e19c (123292)
5478
5479 (for cases where the link is to a normal DN)
5480      &target: struct drsuapi_DsReplicaObjectIdentifier3
5481         __ndr_size               : 0x0000007e (126)
5482         __ndr_size_sid           : 0x0000001c (28)
5483         guid                     : 7639e594-db75-4086-b0d4-67890ae46031
5484         sid                      : S-1-5-21-2848215498-2472035911-1947525656-19924
5485         __ndr_size_dn            : 0x00000022 (34)
5486         dn                       : 'CN=UOne,OU=TestOU,DC=vsofs8,DC=com'
5487  */
5488
5489         /* find the attribute being modified */
5490         attr = dsdb_attribute_by_attributeID_id(schema, la->attid);
5491         if (attr == NULL) {
5492                 DEBUG(0, (__location__ ": Unable to find attributeID 0x%x\n", la->attid));
5493                 talloc_free(tmp_ctx);
5494                 return LDB_ERR_OPERATIONS_ERROR;
5495         }
5496
5497         attrs[0] = attr->lDAPDisplayName;
5498         attrs[1] = "isDeleted";
5499         attrs[2] = "isRecycled";
5500         attrs[3] = NULL;
5501
5502         /* get the existing message from the db for the object with
5503            this GUID, returning attribute being modified. We will then
5504            use this msg as the basis for a modify call */
5505         ret = dsdb_module_search(module, tmp_ctx, &res, NULL, LDB_SCOPE_SUBTREE, attrs,
5506                                  DSDB_FLAG_NEXT_MODULE |
5507                                  DSDB_SEARCH_SEARCH_ALL_PARTITIONS |
5508                                  DSDB_SEARCH_SHOW_RECYCLED |
5509                                  DSDB_SEARCH_SHOW_DN_IN_STORAGE_FORMAT |
5510                                  DSDB_SEARCH_REVEAL_INTERNALS,
5511                                  parent,
5512                                  "objectGUID=%s", GUID_string(tmp_ctx, &la->identifier->guid));
5513         if (ret != LDB_SUCCESS) {
5514                 talloc_free(tmp_ctx);
5515                 return ret;
5516         }
5517         if (res->count != 1) {
5518                 ldb_asprintf_errstring(ldb, "DRS linked attribute for GUID %s - DN not found",
5519                                        GUID_string(tmp_ctx, &la->identifier->guid));
5520                 talloc_free(tmp_ctx);
5521                 return LDB_ERR_NO_SUCH_OBJECT;
5522         }
5523         msg = res->msgs[0];
5524
5525         /*
5526          * Check for deleted objects per MS-DRSR 4.1.10.6.13
5527          * ProcessLinkValue, because link updates are not applied to
5528          * recycled and tombstone objects.  We don't have to delete
5529          * any existing link, that should have happened when the
5530          * object deletion was replicated or initiated.
5531          */
5532
5533         replmd_deletion_state(module, msg, &deletion_state, NULL);
5534
5535         if (deletion_state >= OBJECT_RECYCLED) {
5536                 talloc_free(tmp_ctx);
5537                 return LDB_SUCCESS;
5538         }
5539
5540         old_el = ldb_msg_find_element(msg, attr->lDAPDisplayName);
5541         if (old_el == NULL) {
5542                 ret = ldb_msg_add_empty(msg, attr->lDAPDisplayName, LDB_FLAG_MOD_REPLACE, &old_el);
5543                 if (ret != LDB_SUCCESS) {
5544                         ldb_module_oom(module);
5545                         talloc_free(tmp_ctx);
5546                         return LDB_ERR_OPERATIONS_ERROR;
5547                 }
5548         } else {
5549                 old_el->flags = LDB_FLAG_MOD_REPLACE;
5550         }
5551
5552         /* parse the existing links */
5553         ret = get_parsed_dns(module, tmp_ctx, old_el, &pdn_list, attr->syntax->ldap_oid, parent);
5554         if (ret != LDB_SUCCESS) {
5555                 talloc_free(tmp_ctx);
5556                 return ret;
5557         }
5558
5559         /* get our invocationId */
5560         our_invocation_id = samdb_ntds_invocation_id(ldb);
5561         if (!our_invocation_id) {
5562                 ldb_debug_set(ldb, LDB_DEBUG_ERROR, __location__ ": unable to find invocationId\n");
5563                 talloc_free(tmp_ctx);
5564                 return LDB_ERR_OPERATIONS_ERROR;
5565         }
5566
5567         ret = replmd_check_upgrade_links(pdn_list, old_el->num_values, old_el, our_invocation_id);
5568         if (ret != LDB_SUCCESS) {
5569                 talloc_free(tmp_ctx);
5570                 return ret;
5571         }
5572
5573         status = dsdb_dn_la_from_blob(ldb, attr, schema, tmp_ctx, la->value.blob, &dsdb_dn);
5574         if (!W_ERROR_IS_OK(status)) {
5575                 ldb_asprintf_errstring(ldb, "Failed to parsed linked attribute blob for %s on %s - %s\n",
5576                                        old_el->name, ldb_dn_get_linearized(msg->dn), win_errstr(status));
5577                 talloc_free(tmp_ctx);
5578                 return LDB_ERR_OPERATIONS_ERROR;
5579         }
5580
5581         ntstatus = dsdb_get_extended_dn_guid(dsdb_dn->dn, &guid, "GUID");
5582         if (!NT_STATUS_IS_OK(ntstatus) && !active) {
5583                 /*
5584                  * This strange behaviour (allowing a NULL/missing
5585                  * GUID) originally comes from:
5586                  *
5587                  * commit e3054ce0fe0f8f62d2f5b2a77893e7a1479128bd
5588                  * Author: Andrew Tridgell <tridge@samba.org>
5589                  * Date:   Mon Dec 21 21:21:55 2009 +1100
5590                  *
5591                  *  s4-drs: cope better with NULL GUIDS from DRS
5592                  *
5593                  *  It is valid to get a NULL GUID over DRS for a deleted forward link. We
5594                  *  need to match by DN if possible when seeing if we should update an
5595                  *  existing link.
5596                  *
5597                  *  Pair-Programmed-With: Andrew Bartlett <abartlet@samba.org>
5598                  */
5599
5600                 ret = dsdb_module_search_dn(module, tmp_ctx, &target_res,
5601                                             dsdb_dn->dn, attrs2,
5602                                             DSDB_FLAG_NEXT_MODULE |
5603                                             DSDB_SEARCH_SHOW_RECYCLED |
5604                                             DSDB_SEARCH_SEARCH_ALL_PARTITIONS |
5605                                             DSDB_SEARCH_SHOW_DN_IN_STORAGE_FORMAT,
5606                                             parent);
5607         } else if (!NT_STATUS_IS_OK(ntstatus)) {
5608                 ldb_asprintf_errstring(ldb, "Failed to find GUID in linked attribute blob for %s on %s from %s",
5609                                        old_el->name,
5610                                        ldb_dn_get_linearized(dsdb_dn->dn),
5611                                        ldb_dn_get_linearized(msg->dn));
5612                 talloc_free(tmp_ctx);
5613                 return LDB_ERR_OPERATIONS_ERROR;
5614         } else {
5615                 ret = dsdb_module_search(module, tmp_ctx, &target_res,
5616                                          NULL, LDB_SCOPE_SUBTREE,
5617                                          attrs2,
5618                                          DSDB_FLAG_NEXT_MODULE |
5619                                          DSDB_SEARCH_SHOW_RECYCLED |
5620                                          DSDB_SEARCH_SEARCH_ALL_PARTITIONS |
5621                                          DSDB_SEARCH_SHOW_DN_IN_STORAGE_FORMAT,
5622                                          parent,
5623                                          "objectGUID=%s",
5624                                          GUID_string(tmp_ctx, &guid));
5625         }
5626
5627         if (ret != LDB_SUCCESS) {
5628                 ldb_asprintf_errstring(ldb_module_get_ctx(module), "Failed to re-resolve GUID %s: %s\n",
5629                                        GUID_string(tmp_ctx, &guid),
5630                                        ldb_errstring(ldb_module_get_ctx(module)));
5631                 talloc_free(tmp_ctx);
5632                 return ret;
5633         }
5634
5635         if (target_res->count == 0) {
5636                 DEBUG(2,(__location__ ": WARNING: Failed to re-resolve GUID %s - using %s\n",
5637                          GUID_string(tmp_ctx, &guid),
5638                          ldb_dn_get_linearized(dsdb_dn->dn)));
5639         } else if (target_res->count != 1) {
5640                 ldb_asprintf_errstring(ldb_module_get_ctx(module), "More than one object found matching objectGUID %s\n",
5641                                        GUID_string(tmp_ctx, &guid));
5642                 talloc_free(tmp_ctx);
5643                 return LDB_ERR_OPERATIONS_ERROR;
5644         } else {
5645                 target_msg = target_res->msgs[0];
5646                 dsdb_dn->dn = talloc_steal(dsdb_dn, target_msg->dn);
5647         }
5648
5649         /*
5650          * Check for deleted objects per MS-DRSR 4.1.10.6.13
5651          * ProcessLinkValue, because link updates are not applied to
5652          * recycled and tombstone objects.  We don't have to delete
5653          * any existing link, that should have happened when the
5654          * object deletion was replicated or initiated.
5655          */
5656         replmd_deletion_state(module, target_msg,
5657                               &target_deletion_state, NULL);
5658
5659         if (target_deletion_state >= OBJECT_RECYCLED) {
5660                 talloc_free(tmp_ctx);
5661                 return LDB_SUCCESS;
5662         }
5663
5664         /* see if this link already exists */
5665         pdn = parsed_dn_find(pdn_list, old_el->num_values, &guid, dsdb_dn->dn);
5666         if (pdn != NULL) {
5667                 /* see if this update is newer than what we have already */
5668                 struct GUID invocation_id = GUID_zero();
5669                 uint32_t version = 0;
5670                 uint32_t originating_usn = 0;
5671                 NTTIME change_time = 0;
5672                 uint32_t rmd_flags = dsdb_dn_rmd_flags(pdn->dsdb_dn->dn);
5673
5674                 dsdb_get_extended_dn_guid(pdn->dsdb_dn->dn, &invocation_id, "RMD_INVOCID");
5675                 dsdb_get_extended_dn_uint32(pdn->dsdb_dn->dn, &version, "RMD_VERSION");
5676                 dsdb_get_extended_dn_uint32(pdn->dsdb_dn->dn, &originating_usn, "RMD_ORIGINATING_USN");
5677                 dsdb_get_extended_dn_nttime(pdn->dsdb_dn->dn, &change_time, "RMD_CHANGETIME");
5678
5679                 if (!replmd_update_is_newer(&invocation_id,
5680                                             &la->meta_data.originating_invocation_id,
5681                                             version,
5682                                             la->meta_data.version,
5683                                             change_time,
5684                                             la->meta_data.originating_change_time)) {
5685                         DEBUG(3,("Discarding older DRS linked attribute update to %s on %s from %s\n",
5686                                  old_el->name, ldb_dn_get_linearized(msg->dn),
5687                                  GUID_string(tmp_ctx, &la->meta_data.originating_invocation_id)));
5688                         talloc_free(tmp_ctx);
5689                         return LDB_SUCCESS;
5690                 }
5691
5692                 /* get a seq_num for this change */
5693                 ret = ldb_sequence_number(ldb, LDB_SEQ_NEXT, &seq_num);
5694                 if (ret != LDB_SUCCESS) {
5695                         talloc_free(tmp_ctx);
5696                         return ret;
5697                 }
5698
5699                 if (!(rmd_flags & DSDB_RMD_FLAG_DELETED)) {
5700                         /* remove the existing backlink */
5701                         ret = replmd_add_backlink(module, schema, &la->identifier->guid, &guid, false, attr, false);
5702                         if (ret != LDB_SUCCESS) {
5703                                 talloc_free(tmp_ctx);
5704                                 return ret;
5705                         }
5706                 }
5707
5708                 ret = replmd_update_la_val(tmp_ctx, pdn->v, dsdb_dn, pdn->dsdb_dn,
5709                                            &la->meta_data.originating_invocation_id,
5710                                            la->meta_data.originating_usn, seq_num,
5711                                            la->meta_data.originating_change_time,
5712                                            la->meta_data.version,
5713                                            !active);
5714                 if (ret != LDB_SUCCESS) {
5715                         talloc_free(tmp_ctx);
5716                         return ret;
5717                 }
5718
5719                 if (active) {
5720                         /* add the new backlink */
5721                         ret = replmd_add_backlink(module, schema, &la->identifier->guid, &guid, true, attr, false);
5722                         if (ret != LDB_SUCCESS) {
5723                                 talloc_free(tmp_ctx);
5724                                 return ret;
5725                         }
5726                 }
5727         } else {
5728                 /* get a seq_num for this change */
5729                 ret = ldb_sequence_number(ldb, LDB_SEQ_NEXT, &seq_num);
5730                 if (ret != LDB_SUCCESS) {
5731                         talloc_free(tmp_ctx);
5732                         return ret;
5733                 }
5734
5735                 old_el->values = talloc_realloc(msg->elements, old_el->values,
5736                                                 struct ldb_val, old_el->num_values+1);
5737                 if (!old_el->values) {
5738                         ldb_module_oom(module);
5739                         return LDB_ERR_OPERATIONS_ERROR;
5740                 }
5741                 old_el->num_values++;
5742
5743                 ret = replmd_build_la_val(tmp_ctx, &old_el->values[old_el->num_values-1], dsdb_dn,
5744                                           &la->meta_data.originating_invocation_id,
5745                                           la->meta_data.originating_usn, seq_num,
5746                                           la->meta_data.originating_change_time,
5747                                           la->meta_data.version,
5748                                           (la->flags & DRSUAPI_DS_LINKED_ATTRIBUTE_FLAG_ACTIVE)?false:true);
5749                 if (ret != LDB_SUCCESS) {
5750                         talloc_free(tmp_ctx);
5751                         return ret;
5752                 }
5753
5754                 if (active) {
5755                         ret = replmd_add_backlink(module, schema, &la->identifier->guid, &guid,
5756                                                   true, attr, false);
5757                         if (ret != LDB_SUCCESS) {
5758                                 talloc_free(tmp_ctx);
5759                                 return ret;
5760                         }
5761                 }
5762         }
5763
5764         /* we only change whenChanged and uSNChanged if the seq_num
5765            has changed */
5766         ret = add_time_element(msg, "whenChanged", t);
5767         if (ret != LDB_SUCCESS) {
5768                 talloc_free(tmp_ctx);
5769                 ldb_operr(ldb);
5770                 return ret;
5771         }
5772
5773         ret = add_uint64_element(ldb, msg, "uSNChanged", seq_num);
5774         if (ret != LDB_SUCCESS) {
5775                 talloc_free(tmp_ctx);
5776                 ldb_operr(ldb);
5777                 return ret;
5778         }
5779
5780         old_el = ldb_msg_find_element(msg, attr->lDAPDisplayName);
5781         if (old_el == NULL) {
5782                 talloc_free(tmp_ctx);
5783                 return ldb_operr(ldb);
5784         }
5785
5786         ret = dsdb_check_single_valued_link(attr, old_el);
5787         if (ret != LDB_SUCCESS) {
5788                 talloc_free(tmp_ctx);
5789                 return ret;
5790         }
5791
5792         old_el->flags |= LDB_FLAG_INTERNAL_DISABLE_SINGLE_VALUE_CHECK;
5793
5794         ret = dsdb_module_modify(module, msg, DSDB_FLAG_NEXT_MODULE, parent);
5795         if (ret != LDB_SUCCESS) {
5796                 ldb_debug(ldb, LDB_DEBUG_WARNING, "Failed to apply linked attribute change '%s'\n%s\n",
5797                           ldb_errstring(ldb),
5798                           ldb_ldif_message_string(ldb, tmp_ctx, LDB_CHANGETYPE_MODIFY, msg));
5799                 talloc_free(tmp_ctx);
5800                 return ret;
5801         }
5802
5803         talloc_free(tmp_ctx);
5804
5805         return ret;
5806 }
5807
5808 static int replmd_extended(struct ldb_module *module, struct ldb_request *req)
5809 {
5810         if (strcmp(req->op.extended.oid, DSDB_EXTENDED_REPLICATED_OBJECTS_OID) == 0) {
5811                 return replmd_extended_replicated_objects(module, req);
5812         }
5813
5814         return ldb_next_request(module, req);
5815 }
5816
5817
5818 /*
5819   we hook into the transaction operations to allow us to
5820   perform the linked attribute updates at the end of the whole
5821   transaction. This allows a forward linked attribute to be created
5822   before the object is created. During a vampire, w2k8 sends us linked
5823   attributes before the objects they are part of.
5824  */
5825 static int replmd_start_transaction(struct ldb_module *module)
5826 {
5827         /* create our private structure for this transaction */
5828         struct replmd_private *replmd_private = talloc_get_type(ldb_module_get_private(module),
5829                                                                 struct replmd_private);
5830         replmd_txn_cleanup(replmd_private);
5831
5832         /* free any leftover mod_usn records from cancelled
5833            transactions */
5834         while (replmd_private->ncs) {
5835                 struct nc_entry *e = replmd_private->ncs;
5836                 DLIST_REMOVE(replmd_private->ncs, e);
5837                 talloc_free(e);
5838         }
5839
5840         return ldb_next_start_trans(module);
5841 }
5842
5843 /*
5844   on prepare commit we loop over our queued la_context structures and
5845   apply each of them
5846  */
5847 static int replmd_prepare_commit(struct ldb_module *module)
5848 {
5849         struct replmd_private *replmd_private =
5850                 talloc_get_type(ldb_module_get_private(module), struct replmd_private);
5851         struct la_entry *la, *prev;
5852         struct la_backlink *bl;
5853         int ret;
5854
5855         /* walk the list backwards, to do the first entry first, as we
5856          * added the entries with DLIST_ADD() which puts them at the
5857          * start of the list */
5858         for (la = DLIST_TAIL(replmd_private->la_list); la; la=prev) {
5859                 prev = DLIST_PREV(la);
5860                 DLIST_REMOVE(replmd_private->la_list, la);
5861                 ret = replmd_process_linked_attribute(module, la, NULL);
5862                 if (ret != LDB_SUCCESS) {
5863                         replmd_txn_cleanup(replmd_private);
5864                         return ret;
5865                 }
5866         }
5867
5868         /* process our backlink list, creating and deleting backlinks
5869            as necessary */
5870         for (bl=replmd_private->la_backlinks; bl; bl=bl->next) {
5871                 ret = replmd_process_backlink(module, bl, NULL);
5872                 if (ret != LDB_SUCCESS) {
5873                         replmd_txn_cleanup(replmd_private);
5874                         return ret;
5875                 }
5876         }
5877
5878         replmd_txn_cleanup(replmd_private);
5879
5880         /* possibly change @REPLCHANGED */
5881         ret = replmd_notify_store(module, NULL);
5882         if (ret != LDB_SUCCESS) {
5883                 return ret;
5884         }
5885
5886         return ldb_next_prepare_commit(module);
5887 }
5888
5889 static int replmd_del_transaction(struct ldb_module *module)
5890 {
5891         struct replmd_private *replmd_private =
5892                 talloc_get_type(ldb_module_get_private(module), struct replmd_private);
5893         replmd_txn_cleanup(replmd_private);
5894
5895         return ldb_next_del_trans(module);
5896 }
5897
5898
5899 static const struct ldb_module_ops ldb_repl_meta_data_module_ops = {
5900         .name          = "repl_meta_data",
5901         .init_context      = replmd_init,
5902         .add               = replmd_add,
5903         .modify            = replmd_modify,
5904         .rename            = replmd_rename,
5905         .del               = replmd_delete,
5906         .extended          = replmd_extended,
5907         .start_transaction = replmd_start_transaction,
5908         .prepare_commit    = replmd_prepare_commit,
5909         .del_transaction   = replmd_del_transaction,
5910 };
5911
5912 int ldb_repl_meta_data_module_init(const char *version)
5913 {
5914         LDB_MODULE_CHECK_VERSION(version);
5915         return ldb_register_module(&ldb_repl_meta_data_module_ops);
5916 }