dsdb: Ensure to sort replPropertyMetaData as UNSIGNED, not SIGNED quantities
[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 };
71
72 struct la_entry {
73         struct la_entry *next, *prev;
74         struct drsuapi_DsReplicaLinkedAttribute *la;
75 };
76
77 struct replmd_replicated_request {
78         struct ldb_module *module;
79         struct ldb_request *req;
80
81         const struct dsdb_schema *schema;
82
83         /* the controls we pass down */
84         struct ldb_control **controls;
85
86         /* details for the mode where we apply a bunch of inbound replication meessages */
87         bool apply_mode;
88         uint32_t index_current;
89         struct dsdb_extended_replicated_objects *objs;
90
91         struct ldb_message *search_msg;
92
93         uint64_t seq_num;
94         bool is_urgent;
95
96         bool isDeleted;
97 };
98
99 static int replmd_replicated_apply_merge(struct replmd_replicated_request *ar);
100 static int replmd_delete_internals(struct ldb_module *module, struct ldb_request *req, bool re_delete);
101
102 enum urgent_situation {
103         REPL_URGENT_ON_CREATE = 1,
104         REPL_URGENT_ON_UPDATE = 2,
105         REPL_URGENT_ON_DELETE = 4
106 };
107
108 enum deletion_state {
109         OBJECT_NOT_DELETED=1,
110         OBJECT_DELETED=2,
111         OBJECT_RECYCLED=3,
112         OBJECT_TOMBSTONE=4,
113         OBJECT_REMOVED=5
114 };
115
116 static void replmd_deletion_state(struct ldb_module *module,
117                                   const struct ldb_message *msg,
118                                   enum deletion_state *current_state,
119                                   enum deletion_state *next_state)
120 {
121         int ret;
122         bool enabled = false;
123
124         if (msg == NULL) {
125                 *current_state = OBJECT_REMOVED;
126                 if (next_state != NULL) {
127                         *next_state = OBJECT_REMOVED;
128                 }
129                 return;
130         }
131
132         ret = dsdb_recyclebin_enabled(module, &enabled);
133         if (ret != LDB_SUCCESS) {
134                 enabled = false;
135         }
136
137         if (ldb_msg_check_string_attribute(msg, "isDeleted", "TRUE")) {
138                 if (!enabled) {
139                         *current_state = OBJECT_TOMBSTONE;
140                         if (next_state != NULL) {
141                                 *next_state = OBJECT_REMOVED;
142                         }
143                         return;
144                 }
145
146                 if (ldb_msg_check_string_attribute(msg, "isRecycled", "TRUE")) {
147                         *current_state = OBJECT_RECYCLED;
148                         if (next_state != NULL) {
149                                 *next_state = OBJECT_REMOVED;
150                         }
151                         return;
152                 }
153
154                 *current_state = OBJECT_DELETED;
155                 if (next_state != NULL) {
156                         *next_state = OBJECT_RECYCLED;
157                 }
158                 return;
159         }
160
161         *current_state = OBJECT_NOT_DELETED;
162         if (next_state == NULL) {
163                 return;
164         }
165
166         if (enabled) {
167                 *next_state = OBJECT_DELETED;
168         } else {
169                 *next_state = OBJECT_TOMBSTONE;
170         }
171 }
172
173 static const struct {
174         const char *update_name;
175         enum urgent_situation repl_situation;
176 } urgent_objects[] = {
177                 {"nTDSDSA", (REPL_URGENT_ON_CREATE | REPL_URGENT_ON_DELETE)},
178                 {"crossRef", (REPL_URGENT_ON_CREATE | REPL_URGENT_ON_DELETE)},
179                 {"attributeSchema", (REPL_URGENT_ON_CREATE | REPL_URGENT_ON_UPDATE)},
180                 {"classSchema", (REPL_URGENT_ON_CREATE | REPL_URGENT_ON_UPDATE)},
181                 {"secret", (REPL_URGENT_ON_CREATE | REPL_URGENT_ON_UPDATE)},
182                 {"rIDManager", (REPL_URGENT_ON_CREATE | REPL_URGENT_ON_UPDATE)},
183                 {NULL, 0}
184 };
185
186 /* Attributes looked for when updating or deleting, to check for a urgent replication needed */
187 static const char *urgent_attrs[] = {
188                 "lockoutTime",
189                 "pwdLastSet",
190                 "userAccountControl",
191                 NULL
192 };
193
194
195 static bool replmd_check_urgent_objectclass(const struct ldb_message_element *objectclass_el,
196                                         enum urgent_situation situation)
197 {
198         unsigned int i, j;
199         for (i=0; urgent_objects[i].update_name; i++) {
200
201                 if ((situation & urgent_objects[i].repl_situation) == 0) {
202                         continue;
203                 }
204
205                 for (j=0; j<objectclass_el->num_values; j++) {
206                         const struct ldb_val *v = &objectclass_el->values[j];
207                         if (ldb_attr_cmp((const char *)v->data, urgent_objects[i].update_name) == 0) {
208                                 return true;
209                         }
210                 }
211         }
212         return false;
213 }
214
215 static bool replmd_check_urgent_attribute(const struct ldb_message_element *el)
216 {
217         if (ldb_attr_in_list(urgent_attrs, el->name)) {
218                 return true;
219         }
220         return false;
221 }
222
223
224 static int replmd_replicated_apply_isDeleted(struct replmd_replicated_request *ar);
225
226 /*
227   initialise the module
228   allocate the private structure and build the list
229   of partition DNs for use by replmd_notify()
230  */
231 static int replmd_init(struct ldb_module *module)
232 {
233         struct replmd_private *replmd_private;
234         struct ldb_context *ldb = ldb_module_get_ctx(module);
235
236         replmd_private = talloc_zero(module, struct replmd_private);
237         if (replmd_private == NULL) {
238                 ldb_oom(ldb);
239                 return LDB_ERR_OPERATIONS_ERROR;
240         }
241         ldb_module_set_private(module, replmd_private);
242
243         return ldb_next_init(module);
244 }
245
246 /*
247   cleanup our per-transaction contexts
248  */
249 static void replmd_txn_cleanup(struct replmd_private *replmd_private)
250 {
251         talloc_free(replmd_private->la_ctx);
252         replmd_private->la_list = NULL;
253         replmd_private->la_ctx = NULL;
254
255         talloc_free(replmd_private->bl_ctx);
256         replmd_private->la_backlinks = NULL;
257         replmd_private->bl_ctx = NULL;
258 }
259
260
261 struct la_backlink {
262         struct la_backlink *next, *prev;
263         const char *attr_name;
264         struct GUID forward_guid, target_guid;
265         bool active;
266 };
267
268 /*
269   process a backlinks we accumulated during a transaction, adding and
270   deleting the backlinks from the target objects
271  */
272 static int replmd_process_backlink(struct ldb_module *module, struct la_backlink *bl, struct ldb_request *parent)
273 {
274         struct ldb_dn *target_dn, *source_dn;
275         int ret;
276         struct ldb_context *ldb = ldb_module_get_ctx(module);
277         struct ldb_message *msg;
278         TALLOC_CTX *tmp_ctx = talloc_new(bl);
279         char *dn_string;
280
281         /*
282           - find DN of target
283           - find DN of source
284           - construct ldb_message
285               - either an add or a delete
286          */
287         ret = dsdb_module_dn_by_guid(module, tmp_ctx, &bl->target_guid, &target_dn, parent);
288         if (ret != LDB_SUCCESS) {
289                 DEBUG(2,(__location__ ": WARNING: Failed to find target DN for linked attribute with GUID %s\n",
290                          GUID_string(bl, &bl->target_guid)));
291                 return LDB_SUCCESS;
292         }
293
294         ret = dsdb_module_dn_by_guid(module, tmp_ctx, &bl->forward_guid, &source_dn, parent);
295         if (ret != LDB_SUCCESS) {
296                 ldb_asprintf_errstring(ldb, "Failed to find source DN for linked attribute with GUID %s\n",
297                                        GUID_string(bl, &bl->forward_guid));
298                 talloc_free(tmp_ctx);
299                 return ret;
300         }
301
302         msg = ldb_msg_new(tmp_ctx);
303         if (msg == NULL) {
304                 ldb_module_oom(module);
305                 talloc_free(tmp_ctx);
306                 return LDB_ERR_OPERATIONS_ERROR;
307         }
308
309         /* construct a ldb_message for adding/deleting the backlink */
310         msg->dn = target_dn;
311         dn_string = ldb_dn_get_extended_linearized(tmp_ctx, source_dn, 1);
312         if (!dn_string) {
313                 ldb_module_oom(module);
314                 talloc_free(tmp_ctx);
315                 return LDB_ERR_OPERATIONS_ERROR;
316         }
317         ret = ldb_msg_add_steal_string(msg, bl->attr_name, dn_string);
318         if (ret != LDB_SUCCESS) {
319                 talloc_free(tmp_ctx);
320                 return ret;
321         }
322         msg->elements[0].flags = bl->active?LDB_FLAG_MOD_ADD:LDB_FLAG_MOD_DELETE;
323
324         /* a backlink should never be single valued. Unfortunately the
325            exchange schema has a attribute
326            msExchBridgeheadedLocalConnectorsDNBL which is single
327            valued and a backlink. We need to cope with that by
328            ignoring the single value flag */
329         msg->elements[0].flags |= LDB_FLAG_INTERNAL_DISABLE_SINGLE_VALUE_CHECK;
330
331         ret = dsdb_module_modify(module, msg, DSDB_FLAG_NEXT_MODULE, parent);
332         if (ret == LDB_ERR_NO_SUCH_ATTRIBUTE && !bl->active) {
333                 /* we allow LDB_ERR_NO_SUCH_ATTRIBUTE as success to
334                    cope with possible corruption where the backlink has
335                    already been removed */
336                 DEBUG(3,("WARNING: backlink from %s already removed from %s - %s\n",
337                          ldb_dn_get_linearized(target_dn),
338                          ldb_dn_get_linearized(source_dn),
339                          ldb_errstring(ldb)));
340                 ret = LDB_SUCCESS;
341         } else if (ret != LDB_SUCCESS) {
342                 ldb_asprintf_errstring(ldb, "Failed to %s backlink from %s to %s - %s",
343                                        bl->active?"add":"remove",
344                                        ldb_dn_get_linearized(source_dn),
345                                        ldb_dn_get_linearized(target_dn),
346                                        ldb_errstring(ldb));
347                 talloc_free(tmp_ctx);
348                 return ret;
349         }
350         talloc_free(tmp_ctx);
351         return ret;
352 }
353
354 /*
355   add a backlink to the list of backlinks to add/delete in the prepare
356   commit
357  */
358 static int replmd_add_backlink(struct ldb_module *module, const struct dsdb_schema *schema,
359                                struct GUID *forward_guid, struct GUID *target_guid,
360                                bool active, const struct dsdb_attribute *schema_attr, bool immediate)
361 {
362         const struct dsdb_attribute *target_attr;
363         struct la_backlink *bl;
364         struct replmd_private *replmd_private =
365                 talloc_get_type_abort(ldb_module_get_private(module), struct replmd_private);
366
367         target_attr = dsdb_attribute_by_linkID(schema, schema_attr->linkID ^ 1);
368         if (!target_attr) {
369                 /*
370                  * windows 2003 has a broken schema where the
371                  * definition of msDS-IsDomainFor is missing (which is
372                  * supposed to be the backlink of the
373                  * msDS-HasDomainNCs attribute
374                  */
375                 return LDB_SUCCESS;
376         }
377
378         /* see if its already in the list */
379         for (bl=replmd_private->la_backlinks; bl; bl=bl->next) {
380                 if (GUID_equal(forward_guid, &bl->forward_guid) &&
381                     GUID_equal(target_guid, &bl->target_guid) &&
382                     (target_attr->lDAPDisplayName == bl->attr_name ||
383                      strcmp(target_attr->lDAPDisplayName, bl->attr_name) == 0)) {
384                         break;
385                 }
386         }
387
388         if (bl) {
389                 /* we found an existing one */
390                 if (bl->active == active) {
391                         return LDB_SUCCESS;
392                 }
393                 DLIST_REMOVE(replmd_private->la_backlinks, bl);
394                 talloc_free(bl);
395                 return LDB_SUCCESS;
396         }
397
398         if (replmd_private->bl_ctx == NULL) {
399                 replmd_private->bl_ctx = talloc_new(replmd_private);
400                 if (replmd_private->bl_ctx == NULL) {
401                         ldb_module_oom(module);
402                         return LDB_ERR_OPERATIONS_ERROR;
403                 }
404         }
405
406         /* its a new one */
407         bl = talloc(replmd_private->bl_ctx, struct la_backlink);
408         if (bl == NULL) {
409                 ldb_module_oom(module);
410                 return LDB_ERR_OPERATIONS_ERROR;
411         }
412
413         /* Ensure the schema does not go away before the bl->attr_name is used */
414         if (!talloc_reference(bl, schema)) {
415                 talloc_free(bl);
416                 ldb_module_oom(module);
417                 return LDB_ERR_OPERATIONS_ERROR;
418         }
419
420         bl->attr_name = target_attr->lDAPDisplayName;
421         bl->forward_guid = *forward_guid;
422         bl->target_guid = *target_guid;
423         bl->active = active;
424
425         /* the caller may ask for this backlink to be processed
426            immediately */
427         if (immediate) {
428                 int ret = replmd_process_backlink(module, bl, NULL);
429                 talloc_free(bl);
430                 return ret;
431         }
432
433         DLIST_ADD(replmd_private->la_backlinks, bl);
434
435         return LDB_SUCCESS;
436 }
437
438
439 /*
440  * Callback for most write operations in this module:
441  *
442  * notify the repl task that a object has changed. The notifies are
443  * gathered up in the replmd_private structure then written to the
444  * @REPLCHANGED object in each partition during the prepare_commit
445  */
446 static int replmd_op_callback(struct ldb_request *req, struct ldb_reply *ares)
447 {
448         int ret;
449         struct replmd_replicated_request *ac =
450                 talloc_get_type_abort(req->context, struct replmd_replicated_request);
451         struct replmd_private *replmd_private =
452                 talloc_get_type_abort(ldb_module_get_private(ac->module), struct replmd_private);
453         struct nc_entry *modified_partition;
454         struct ldb_control *partition_ctrl;
455         const struct dsdb_control_current_partition *partition;
456
457         struct ldb_control **controls;
458
459         partition_ctrl = ldb_reply_get_control(ares, DSDB_CONTROL_CURRENT_PARTITION_OID);
460
461         controls = ares->controls;
462         if (ldb_request_get_control(ac->req,
463                                     DSDB_CONTROL_CURRENT_PARTITION_OID) == NULL) {
464                 /*
465                  * Remove the current partition control from what we pass up
466                  * the chain if it hasn't been requested manually.
467                  */
468                 controls = ldb_controls_except_specified(ares->controls, ares,
469                                                          partition_ctrl);
470         }
471
472         if (ares->error != LDB_SUCCESS) {
473                 DEBUG(5,("%s failure. Error is: %s\n", __FUNCTION__, ldb_strerror(ares->error)));
474                 return ldb_module_done(ac->req, controls,
475                                         ares->response, ares->error);
476         }
477
478         if (ares->type != LDB_REPLY_DONE) {
479                 ldb_set_errstring(ldb_module_get_ctx(ac->module), "Invalid reply type for notify\n!");
480                 return ldb_module_done(ac->req, NULL,
481                                        NULL, LDB_ERR_OPERATIONS_ERROR);
482         }
483
484         if (!partition_ctrl) {
485                 ldb_set_errstring(ldb_module_get_ctx(ac->module),"No partition control on reply");
486                 return ldb_module_done(ac->req, NULL,
487                                        NULL, LDB_ERR_OPERATIONS_ERROR);
488         }
489
490         partition = talloc_get_type_abort(partition_ctrl->data,
491                                     struct dsdb_control_current_partition);
492
493         if (ac->seq_num > 0) {
494                 for (modified_partition = replmd_private->ncs; modified_partition;
495                      modified_partition = modified_partition->next) {
496                         if (ldb_dn_compare(modified_partition->dn, partition->dn) == 0) {
497                                 break;
498                         }
499                 }
500
501                 if (modified_partition == NULL) {
502                         modified_partition = talloc_zero(replmd_private, struct nc_entry);
503                         if (!modified_partition) {
504                                 ldb_oom(ldb_module_get_ctx(ac->module));
505                                 return ldb_module_done(ac->req, NULL,
506                                                        NULL, LDB_ERR_OPERATIONS_ERROR);
507                         }
508                         modified_partition->dn = ldb_dn_copy(modified_partition, partition->dn);
509                         if (!modified_partition->dn) {
510                                 ldb_oom(ldb_module_get_ctx(ac->module));
511                                 return ldb_module_done(ac->req, NULL,
512                                                        NULL, LDB_ERR_OPERATIONS_ERROR);
513                         }
514                         DLIST_ADD(replmd_private->ncs, modified_partition);
515                 }
516
517                 if (ac->seq_num > modified_partition->mod_usn) {
518                         modified_partition->mod_usn = ac->seq_num;
519                         if (ac->is_urgent) {
520                                 modified_partition->mod_usn_urgent = ac->seq_num;
521                         }
522                 }
523         }
524
525         if (ac->apply_mode) {
526                 ret = replmd_replicated_apply_isDeleted(ac);
527                 if (ret != LDB_SUCCESS) {
528                         return ldb_module_done(ac->req, NULL, NULL, ret);
529                 }
530                 return ret;
531         } else {
532                 /* free the partition control container here, for the
533                  * common path.  Other cases will have it cleaned up
534                  * eventually with the ares */
535                 talloc_free(partition_ctrl);
536                 return ldb_module_done(ac->req, controls,
537                                        ares->response, LDB_SUCCESS);
538         }
539 }
540
541
542 /*
543  * update a @REPLCHANGED record in each partition if there have been
544  * any writes of replicated data in the partition
545  */
546 static int replmd_notify_store(struct ldb_module *module, struct ldb_request *parent)
547 {
548         struct replmd_private *replmd_private =
549                 talloc_get_type(ldb_module_get_private(module), struct replmd_private);
550
551         while (replmd_private->ncs) {
552                 int ret;
553                 struct nc_entry *modified_partition = replmd_private->ncs;
554
555                 ret = dsdb_module_save_partition_usn(module, modified_partition->dn,
556                                                      modified_partition->mod_usn,
557                                                      modified_partition->mod_usn_urgent, parent);
558                 if (ret != LDB_SUCCESS) {
559                         DEBUG(0,(__location__ ": Failed to save partition uSN for %s\n",
560                                  ldb_dn_get_linearized(modified_partition->dn)));
561                         return ret;
562                 }
563                 DLIST_REMOVE(replmd_private->ncs, modified_partition);
564                 talloc_free(modified_partition);
565         }
566
567         return LDB_SUCCESS;
568 }
569
570
571 /*
572   created a replmd_replicated_request context
573  */
574 static struct replmd_replicated_request *replmd_ctx_init(struct ldb_module *module,
575                                                          struct ldb_request *req)
576 {
577         struct ldb_context *ldb;
578         struct replmd_replicated_request *ac;
579
580         ldb = ldb_module_get_ctx(module);
581
582         ac = talloc_zero(req, struct replmd_replicated_request);
583         if (ac == NULL) {
584                 ldb_oom(ldb);
585                 return NULL;
586         }
587
588         ac->module = module;
589         ac->req = req;
590
591         ac->schema = dsdb_get_schema(ldb, ac);
592         if (!ac->schema) {
593                 ldb_debug_set(ldb, LDB_DEBUG_FATAL,
594                               "replmd_modify: no dsdb_schema loaded");
595                 DEBUG(0,(__location__ ": %s\n", ldb_errstring(ldb)));
596                 return NULL;
597         }
598
599         return ac;
600 }
601
602 /*
603   add a time element to a record
604 */
605 static int add_time_element(struct ldb_message *msg, const char *attr, time_t t)
606 {
607         struct ldb_message_element *el;
608         char *s;
609         int ret;
610
611         if (ldb_msg_find_element(msg, attr) != NULL) {
612                 return LDB_SUCCESS;
613         }
614
615         s = ldb_timestring(msg, t);
616         if (s == NULL) {
617                 return LDB_ERR_OPERATIONS_ERROR;
618         }
619
620         ret = ldb_msg_add_string(msg, attr, s);
621         if (ret != LDB_SUCCESS) {
622                 return ret;
623         }
624
625         el = ldb_msg_find_element(msg, attr);
626         /* always set as replace. This works because on add ops, the flag
627            is ignored */
628         el->flags = LDB_FLAG_MOD_REPLACE;
629
630         return LDB_SUCCESS;
631 }
632
633 /*
634   add a uint64_t element to a record
635 */
636 static int add_uint64_element(struct ldb_context *ldb, struct ldb_message *msg,
637                               const char *attr, uint64_t v)
638 {
639         struct ldb_message_element *el;
640         int ret;
641
642         if (ldb_msg_find_element(msg, attr) != NULL) {
643                 return LDB_SUCCESS;
644         }
645
646         ret = samdb_msg_add_uint64(ldb, msg, msg, attr, v);
647         if (ret != LDB_SUCCESS) {
648                 return ret;
649         }
650
651         el = ldb_msg_find_element(msg, attr);
652         /* always set as replace. This works because on add ops, the flag
653            is ignored */
654         el->flags = LDB_FLAG_MOD_REPLACE;
655
656         return LDB_SUCCESS;
657 }
658
659 static int replmd_replPropertyMetaData1_attid_sort(const struct replPropertyMetaData1 *m1,
660                                                    const struct replPropertyMetaData1 *m2,
661                                                    const uint32_t *rdn_attid)
662 {
663         /*
664          * This assignment seems inoccous, but it is critical for the
665          * system, as we need to do the comparisons as a unsigned
666          * quantity, not signed (enums are signed integers)
667          */
668         uint32_t attid_1 = m1->attid;
669         uint32_t attid_2 = m2->attid;
670
671         if (attid_1 == attid_2) {
672                 return 0;
673         }
674
675         /*
676          * the rdn attribute should be at the end!
677          * so we need to return a value greater than zero
678          * which means m1 is greater than m2
679          */
680         if (attid_1 == *rdn_attid) {
681                 return 1;
682         }
683
684         /*
685          * the rdn attribute should be at the end!
686          * so we need to return a value less than zero
687          * which means m2 is greater than m1
688          */
689         if (attid_2 == *rdn_attid) {
690                 return -1;
691         }
692
693         /*
694          * See above regarding this being an unsigned comparison.
695          * Otherwise when the high bit is set on non-standard
696          * attributes, they would end up first, before objectClass
697          * (0).
698          */
699         return attid_1 > attid_2 ? 1 : -1;
700 }
701
702 static int replmd_replPropertyMetaDataCtr1_sort(struct replPropertyMetaDataCtr1 *ctr1,
703                                                 const struct dsdb_schema *schema,
704                                                 struct ldb_dn *dn)
705 {
706         const char *rdn_name;
707         const struct dsdb_attribute *rdn_sa;
708
709         rdn_name = ldb_dn_get_rdn_name(dn);
710         if (!rdn_name) {
711                 DEBUG(0,(__location__ ": No rDN for %s?\n", ldb_dn_get_linearized(dn)));
712                 return LDB_ERR_OPERATIONS_ERROR;
713         }
714
715         rdn_sa = dsdb_attribute_by_lDAPDisplayName(schema, rdn_name);
716         if (rdn_sa == NULL) {
717                 DEBUG(0,(__location__ ": No sa found for rDN %s for %s\n", rdn_name, ldb_dn_get_linearized(dn)));
718                 return LDB_ERR_OPERATIONS_ERROR;
719         }
720
721         DEBUG(6,("Sorting rpmd with attid exception %u rDN=%s DN=%s\n",
722                  rdn_sa->attributeID_id, rdn_name, ldb_dn_get_linearized(dn)));
723
724         LDB_TYPESAFE_QSORT(ctr1->array, ctr1->count, &rdn_sa->attributeID_id, replmd_replPropertyMetaData1_attid_sort);
725
726         return LDB_SUCCESS;
727 }
728
729 static int replmd_ldb_message_element_attid_sort(const struct ldb_message_element *e1,
730                                                  const struct ldb_message_element *e2,
731                                                  const struct dsdb_schema *schema)
732 {
733         const struct dsdb_attribute *a1;
734         const struct dsdb_attribute *a2;
735
736         /*
737          * TODO: make this faster by caching the dsdb_attribute pointer
738          *       on the ldb_messag_element
739          */
740
741         a1 = dsdb_attribute_by_lDAPDisplayName(schema, e1->name);
742         a2 = dsdb_attribute_by_lDAPDisplayName(schema, e2->name);
743
744         /*
745          * TODO: remove this check, we should rely on e1 and e2 having valid attribute names
746          *       in the schema
747          */
748         if (!a1 || !a2) {
749                 return strcasecmp(e1->name, e2->name);
750         }
751         if (a1->attributeID_id == a2->attributeID_id) {
752                 return 0;
753         }
754         return a1->attributeID_id > a2->attributeID_id ? 1 : -1;
755 }
756
757 static void replmd_ldb_message_sort(struct ldb_message *msg,
758                                     const struct dsdb_schema *schema)
759 {
760         LDB_TYPESAFE_QSORT(msg->elements, msg->num_elements, schema, replmd_ldb_message_element_attid_sort);
761 }
762
763 static int replmd_build_la_val(TALLOC_CTX *mem_ctx, struct ldb_val *v, struct dsdb_dn *dsdb_dn,
764                                const struct GUID *invocation_id, uint64_t seq_num,
765                                uint64_t local_usn, NTTIME nttime, uint32_t version, bool deleted);
766
767
768 /*
769   fix up linked attributes in replmd_add.
770   This involves setting up the right meta-data in extended DN
771   components, and creating backlinks to the object
772  */
773 static int replmd_add_fix_la(struct ldb_module *module, struct ldb_message_element *el,
774                              uint64_t seq_num, const struct GUID *invocationId, time_t t,
775                              struct GUID *guid, const struct dsdb_attribute *sa, struct ldb_request *parent)
776 {
777         unsigned int i;
778         TALLOC_CTX *tmp_ctx = talloc_new(el->values);
779         struct ldb_context *ldb = ldb_module_get_ctx(module);
780
781         /* We will take a reference to the schema in replmd_add_backlink */
782         const struct dsdb_schema *schema = dsdb_get_schema(ldb, NULL);
783         NTTIME now;
784
785         unix_to_nt_time(&now, t);
786
787         for (i=0; i<el->num_values; i++) {
788                 struct ldb_val *v = &el->values[i];
789                 struct dsdb_dn *dsdb_dn = dsdb_dn_parse(tmp_ctx, ldb, v, sa->syntax->ldap_oid);
790                 struct GUID target_guid;
791                 NTSTATUS status;
792                 int ret;
793
794                 /* note that the DN already has the extended
795                    components from the extended_dn_store module */
796                 status = dsdb_get_extended_dn_guid(dsdb_dn->dn, &target_guid, "GUID");
797                 if (!NT_STATUS_IS_OK(status) || GUID_all_zero(&target_guid)) {
798                         ret = dsdb_module_guid_by_dn(module, dsdb_dn->dn, &target_guid, parent);
799                         if (ret != LDB_SUCCESS) {
800                                 talloc_free(tmp_ctx);
801                                 return ret;
802                         }
803                         ret = dsdb_set_extended_dn_guid(dsdb_dn->dn, &target_guid, "GUID");
804                         if (ret != LDB_SUCCESS) {
805                                 talloc_free(tmp_ctx);
806                                 return ret;
807                         }
808                 }
809
810                 ret = replmd_build_la_val(el->values, v, dsdb_dn, invocationId,
811                                           seq_num, seq_num, now, 0, false);
812                 if (ret != LDB_SUCCESS) {
813                         talloc_free(tmp_ctx);
814                         return ret;
815                 }
816
817                 ret = replmd_add_backlink(module, schema, guid, &target_guid, true, sa, false);
818                 if (ret != LDB_SUCCESS) {
819                         talloc_free(tmp_ctx);
820                         return ret;
821                 }
822         }
823
824         talloc_free(tmp_ctx);
825         return LDB_SUCCESS;
826 }
827
828
829 /*
830   intercept add requests
831  */
832 static int replmd_add(struct ldb_module *module, struct ldb_request *req)
833 {
834         struct samldb_msds_intid_persistant *msds_intid_struct;
835         struct ldb_context *ldb;
836         struct ldb_control *control;
837         struct replmd_replicated_request *ac;
838         enum ndr_err_code ndr_err;
839         struct ldb_request *down_req;
840         struct ldb_message *msg;
841         const DATA_BLOB *guid_blob;
842         struct GUID guid;
843         struct replPropertyMetaDataBlob nmd;
844         struct ldb_val nmd_value;
845         const struct GUID *our_invocation_id;
846         time_t t = time(NULL);
847         NTTIME now;
848         char *time_str;
849         int ret;
850         unsigned int i;
851         unsigned int functional_level;
852         uint32_t ni=0;
853         bool allow_add_guid = false;
854         bool remove_current_guid = false;
855         bool is_urgent = false;
856         struct ldb_message_element *objectclass_el;
857
858         /* check if there's a show relax control (used by provision to say 'I know what I'm doing') */
859         control = ldb_request_get_control(req, LDB_CONTROL_RELAX_OID);
860         if (control) {
861                 allow_add_guid = true;
862         }
863
864         /* do not manipulate our control entries */
865         if (ldb_dn_is_special(req->op.add.message->dn)) {
866                 return ldb_next_request(module, req);
867         }
868
869         ldb = ldb_module_get_ctx(module);
870
871         ldb_debug(ldb, LDB_DEBUG_TRACE, "replmd_add\n");
872
873         guid_blob = ldb_msg_find_ldb_val(req->op.add.message, "objectGUID");
874         if (guid_blob != NULL) {
875                 if (!allow_add_guid) {
876                         ldb_set_errstring(ldb,
877                                           "replmd_add: it's not allowed to add an object with objectGUID!");
878                         return LDB_ERR_UNWILLING_TO_PERFORM;
879                 } else {
880                         NTSTATUS status = GUID_from_data_blob(guid_blob,&guid);
881                         if (!NT_STATUS_IS_OK(status)) {
882                                 ldb_set_errstring(ldb,
883                                                   "replmd_add: Unable to parse the 'objectGUID' as a GUID!");
884                                 return LDB_ERR_UNWILLING_TO_PERFORM;
885                         }
886                         /* we remove this attribute as it can be a string and
887                          * will not be treated correctly and then we will re-add
888                          * it later on in the good format */
889                         remove_current_guid = true;
890                 }
891         } else {
892                 /* a new GUID */
893                 guid = GUID_random();
894         }
895
896         ac = replmd_ctx_init(module, req);
897         if (ac == NULL) {
898                 return ldb_module_oom(module);
899         }
900
901         functional_level = dsdb_functional_level(ldb);
902
903         /* Get a sequence number from the backend */
904         ret = ldb_sequence_number(ldb, LDB_SEQ_NEXT, &ac->seq_num);
905         if (ret != LDB_SUCCESS) {
906                 talloc_free(ac);
907                 return ret;
908         }
909
910         /* get our invocationId */
911         our_invocation_id = samdb_ntds_invocation_id(ldb);
912         if (!our_invocation_id) {
913                 ldb_debug_set(ldb, LDB_DEBUG_ERROR,
914                               "replmd_add: unable to find invocationId\n");
915                 talloc_free(ac);
916                 return LDB_ERR_OPERATIONS_ERROR;
917         }
918
919         /* we have to copy the message as the caller might have it as a const */
920         msg = ldb_msg_copy_shallow(ac, req->op.add.message);
921         if (msg == NULL) {
922                 ldb_oom(ldb);
923                 talloc_free(ac);
924                 return LDB_ERR_OPERATIONS_ERROR;
925         }
926
927         /* generated times */
928         unix_to_nt_time(&now, t);
929         time_str = ldb_timestring(msg, t);
930         if (!time_str) {
931                 ldb_oom(ldb);
932                 talloc_free(ac);
933                 return LDB_ERR_OPERATIONS_ERROR;
934         }
935         if (remove_current_guid) {
936                 ldb_msg_remove_attr(msg,"objectGUID");
937         }
938
939         /*
940          * remove autogenerated attributes
941          */
942         ldb_msg_remove_attr(msg, "whenCreated");
943         ldb_msg_remove_attr(msg, "whenChanged");
944         ldb_msg_remove_attr(msg, "uSNCreated");
945         ldb_msg_remove_attr(msg, "uSNChanged");
946         ldb_msg_remove_attr(msg, "replPropertyMetaData");
947
948         /*
949          * readd replicated attributes
950          */
951         ret = ldb_msg_add_string(msg, "whenCreated", time_str);
952         if (ret != LDB_SUCCESS) {
953                 ldb_oom(ldb);
954                 talloc_free(ac);
955                 return ret;
956         }
957
958         /* build the replication meta_data */
959         ZERO_STRUCT(nmd);
960         nmd.version             = 1;
961         nmd.ctr.ctr1.count      = msg->num_elements;
962         nmd.ctr.ctr1.array      = talloc_array(msg,
963                                                struct replPropertyMetaData1,
964                                                nmd.ctr.ctr1.count);
965         if (!nmd.ctr.ctr1.array) {
966                 ldb_oom(ldb);
967                 talloc_free(ac);
968                 return LDB_ERR_OPERATIONS_ERROR;
969         }
970
971         for (i=0; i < msg->num_elements; i++) {
972                 struct ldb_message_element *e = &msg->elements[i];
973                 struct replPropertyMetaData1 *m = &nmd.ctr.ctr1.array[ni];
974                 const struct dsdb_attribute *sa;
975
976                 if (e->name[0] == '@') continue;
977
978                 sa = dsdb_attribute_by_lDAPDisplayName(ac->schema, e->name);
979                 if (!sa) {
980                         ldb_debug_set(ldb, LDB_DEBUG_ERROR,
981                                       "replmd_add: attribute '%s' not defined in schema\n",
982                                       e->name);
983                         talloc_free(ac);
984                         return LDB_ERR_NO_SUCH_ATTRIBUTE;
985                 }
986
987                 if ((sa->systemFlags & DS_FLAG_ATTR_NOT_REPLICATED) || (sa->systemFlags & DS_FLAG_ATTR_IS_CONSTRUCTED)) {
988                         /* if the attribute is not replicated (0x00000001)
989                          * or constructed (0x00000004) it has no metadata
990                          */
991                         continue;
992                 }
993
994                 if (sa->linkID != 0 && functional_level > DS_DOMAIN_FUNCTION_2000) {
995                         ret = replmd_add_fix_la(module, e, ac->seq_num, our_invocation_id, t, &guid, sa, req);
996                         if (ret != LDB_SUCCESS) {
997                                 talloc_free(ac);
998                                 return ret;
999                         }
1000                         /* linked attributes are not stored in
1001                            replPropertyMetaData in FL above w2k */
1002                         continue;
1003                 }
1004
1005                 m->attid                        = sa->attributeID_id;
1006                 m->version                      = 1;
1007                 if (m->attid == 0x20030) {
1008                         const struct ldb_val *rdn_val = ldb_dn_get_rdn_val(msg->dn);
1009                         const char* rdn;
1010
1011                         if (rdn_val == NULL) {
1012                                 ldb_oom(ldb);
1013                                 talloc_free(ac);
1014                                 return LDB_ERR_OPERATIONS_ERROR;
1015                         }
1016
1017                         rdn = (const char*)rdn_val->data;
1018                         if (strcmp(rdn, "Deleted Objects") == 0) {
1019                                 /*
1020                                  * Set the originating_change_time to 29/12/9999 at 23:59:59
1021                                  * as specified in MS-ADTS 7.1.1.4.2 Deleted Objects Container
1022                                  */
1023                                 m->originating_change_time      = DELETED_OBJECT_CONTAINER_CHANGE_TIME;
1024                         } else {
1025                                 m->originating_change_time      = now;
1026                         }
1027                 } else {
1028                         m->originating_change_time      = now;
1029                 }
1030                 m->originating_invocation_id    = *our_invocation_id;
1031                 m->originating_usn              = ac->seq_num;
1032                 m->local_usn                    = ac->seq_num;
1033                 ni++;
1034         }
1035
1036         /* fix meta data count */
1037         nmd.ctr.ctr1.count = ni;
1038
1039         /*
1040          * sort meta data array, and move the rdn attribute entry to the end
1041          */
1042         ret = replmd_replPropertyMetaDataCtr1_sort(&nmd.ctr.ctr1, ac->schema, msg->dn);
1043         if (ret != LDB_SUCCESS) {
1044                 talloc_free(ac);
1045                 return ret;
1046         }
1047
1048         /* generated NDR encoded values */
1049         ndr_err = ndr_push_struct_blob(&nmd_value, msg,
1050                                        &nmd,
1051                                        (ndr_push_flags_fn_t)ndr_push_replPropertyMetaDataBlob);
1052         if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
1053                 ldb_oom(ldb);
1054                 talloc_free(ac);
1055                 return LDB_ERR_OPERATIONS_ERROR;
1056         }
1057
1058         /*
1059          * add the autogenerated values
1060          */
1061         ret = dsdb_msg_add_guid(msg, &guid, "objectGUID");
1062         if (ret != LDB_SUCCESS) {
1063                 ldb_oom(ldb);
1064                 talloc_free(ac);
1065                 return ret;
1066         }
1067         ret = ldb_msg_add_string(msg, "whenChanged", time_str);
1068         if (ret != LDB_SUCCESS) {
1069                 ldb_oom(ldb);
1070                 talloc_free(ac);
1071                 return ret;
1072         }
1073         ret = samdb_msg_add_uint64(ldb, msg, msg, "uSNCreated", ac->seq_num);
1074         if (ret != LDB_SUCCESS) {
1075                 ldb_oom(ldb);
1076                 talloc_free(ac);
1077                 return ret;
1078         }
1079         ret = samdb_msg_add_uint64(ldb, msg, msg, "uSNChanged", ac->seq_num);
1080         if (ret != LDB_SUCCESS) {
1081                 ldb_oom(ldb);
1082                 talloc_free(ac);
1083                 return ret;
1084         }
1085         ret = ldb_msg_add_value(msg, "replPropertyMetaData", &nmd_value, NULL);
1086         if (ret != LDB_SUCCESS) {
1087                 ldb_oom(ldb);
1088                 talloc_free(ac);
1089                 return ret;
1090         }
1091
1092         /*
1093          * sort the attributes by attid before storing the object
1094          */
1095         replmd_ldb_message_sort(msg, ac->schema);
1096
1097         objectclass_el = ldb_msg_find_element(msg, "objectClass");
1098         is_urgent = replmd_check_urgent_objectclass(objectclass_el,
1099                                                         REPL_URGENT_ON_CREATE);
1100
1101         ac->is_urgent = is_urgent;
1102         ret = ldb_build_add_req(&down_req, ldb, ac,
1103                                 msg,
1104                                 req->controls,
1105                                 ac, replmd_op_callback,
1106                                 req);
1107
1108         LDB_REQ_SET_LOCATION(down_req);
1109         if (ret != LDB_SUCCESS) {
1110                 talloc_free(ac);
1111                 return ret;
1112         }
1113
1114         /* current partition control is needed by "replmd_op_callback" */
1115         if (ldb_request_get_control(req, DSDB_CONTROL_CURRENT_PARTITION_OID) == NULL) {
1116                 ret = ldb_request_add_control(down_req,
1117                                               DSDB_CONTROL_CURRENT_PARTITION_OID,
1118                                               false, NULL);
1119                 if (ret != LDB_SUCCESS) {
1120                         talloc_free(ac);
1121                         return ret;
1122                 }
1123         }
1124
1125         if (functional_level == DS_DOMAIN_FUNCTION_2000) {
1126                 ret = ldb_request_add_control(down_req, DSDB_CONTROL_APPLY_LINKS, false, NULL);
1127                 if (ret != LDB_SUCCESS) {
1128                         talloc_free(ac);
1129                         return ret;
1130                 }
1131         }
1132
1133         /* mark the control done */
1134         if (control) {
1135                 control->critical = 0;
1136         }
1137         if (ldb_dn_compare_base(ac->schema->base_dn, req->op.add.message->dn) != 0) {
1138
1139                 /* Update the usn in the SAMLDB_MSDS_INTID_OPAQUE opaque */
1140                 msds_intid_struct = (struct samldb_msds_intid_persistant *) ldb_get_opaque(ldb, SAMLDB_MSDS_INTID_OPAQUE);
1141                 if (msds_intid_struct) {
1142                         msds_intid_struct->usn = ac->seq_num;
1143                 }
1144         }
1145         /* go on with the call chain */
1146         return ldb_next_request(module, down_req);
1147 }
1148
1149
1150 /*
1151  * update the replPropertyMetaData for one element
1152  */
1153 static int replmd_update_rpmd_element(struct ldb_context *ldb,
1154                                       struct ldb_message *msg,
1155                                       struct ldb_message_element *el,
1156                                       struct ldb_message_element *old_el,
1157                                       struct replPropertyMetaDataBlob *omd,
1158                                       const struct dsdb_schema *schema,
1159                                       uint64_t *seq_num,
1160                                       const struct GUID *our_invocation_id,
1161                                       NTTIME now,
1162                                       struct ldb_request *req)
1163 {
1164         uint32_t i;
1165         const struct dsdb_attribute *a;
1166         struct replPropertyMetaData1 *md1;
1167         bool may_skip = false;
1168
1169         a = dsdb_attribute_by_lDAPDisplayName(schema, el->name);
1170         if (a == NULL) {
1171                 if (ldb_request_get_control(req, LDB_CONTROL_RELAX_OID)) {
1172                         /* allow this to make it possible for dbcheck
1173                            to remove bad attributes */
1174                         return LDB_SUCCESS;
1175                 }
1176
1177                 DEBUG(0,(__location__ ": Unable to find attribute %s in schema\n",
1178                          el->name));
1179                 return LDB_ERR_OPERATIONS_ERROR;
1180         }
1181
1182         if ((a->systemFlags & DS_FLAG_ATTR_NOT_REPLICATED) || (a->systemFlags & DS_FLAG_ATTR_IS_CONSTRUCTED)) {
1183                 return LDB_SUCCESS;
1184         }
1185
1186         /*
1187          * if the attribute's value haven't changed, and this isn't
1188          * just a delete of everything then return LDB_SUCCESS Unless
1189          * we have the provision control or if the attribute is
1190          * interSiteTopologyGenerator as this page explain:
1191          * http://support.microsoft.com/kb/224815 this attribute is
1192          * periodicaly written by the DC responsible for the intersite
1193          * generation in a given site
1194          *
1195          * Unchanged could be deleting or replacing an already-gone
1196          * thing with an unconstrained delete/empty replace or a
1197          * replace with the same value, but not an add with the same
1198          * value because that could be about adding a duplicate (which
1199          * is for someone else to error out on).
1200          */
1201         if (old_el != NULL && ldb_msg_element_equal_ordered(el, old_el)) {
1202                 if (LDB_FLAG_MOD_TYPE(el->flags) == LDB_FLAG_MOD_REPLACE) {
1203                         may_skip = true;
1204                 }
1205         } else if (old_el == NULL && el->num_values == 0) {
1206                 if (LDB_FLAG_MOD_TYPE(el->flags) == LDB_FLAG_MOD_REPLACE) {
1207                         may_skip = true;
1208                 } else if (LDB_FLAG_MOD_TYPE(el->flags) == LDB_FLAG_MOD_DELETE) {
1209                         may_skip = true;
1210                 }
1211         }
1212
1213         if (may_skip) {
1214                 if (strcmp(el->name, "interSiteTopologyGenerator") != 0 &&
1215                     !ldb_request_get_control(req, LDB_CONTROL_PROVISION_OID)) {
1216                         /*
1217                          * allow this to make it possible for dbcheck
1218                          * to rebuild broken metadata
1219                          */
1220                         return LDB_SUCCESS;
1221                 }
1222         }
1223
1224         for (i=0; i<omd->ctr.ctr1.count; i++) {
1225                 if (a->attributeID_id == omd->ctr.ctr1.array[i].attid) break;
1226         }
1227
1228         if (a->linkID != 0 && dsdb_functional_level(ldb) > DS_DOMAIN_FUNCTION_2000) {
1229                 /* linked attributes are not stored in
1230                    replPropertyMetaData in FL above w2k, but we do
1231                    raise the seqnum for the object  */
1232                 if (*seq_num == 0 &&
1233                     ldb_sequence_number(ldb, LDB_SEQ_NEXT, seq_num) != LDB_SUCCESS) {
1234                         return LDB_ERR_OPERATIONS_ERROR;
1235                 }
1236                 return LDB_SUCCESS;
1237         }
1238
1239         if (i == omd->ctr.ctr1.count) {
1240                 /* we need to add a new one */
1241                 omd->ctr.ctr1.array = talloc_realloc(msg, omd->ctr.ctr1.array,
1242                                                      struct replPropertyMetaData1, omd->ctr.ctr1.count+1);
1243                 if (omd->ctr.ctr1.array == NULL) {
1244                         ldb_oom(ldb);
1245                         return LDB_ERR_OPERATIONS_ERROR;
1246                 }
1247                 omd->ctr.ctr1.count++;
1248                 ZERO_STRUCT(omd->ctr.ctr1.array[i]);
1249         }
1250
1251         /* Get a new sequence number from the backend. We only do this
1252          * if we have a change that requires a new
1253          * replPropertyMetaData element
1254          */
1255         if (*seq_num == 0) {
1256                 int ret = ldb_sequence_number(ldb, LDB_SEQ_NEXT, seq_num);
1257                 if (ret != LDB_SUCCESS) {
1258                         return LDB_ERR_OPERATIONS_ERROR;
1259                 }
1260         }
1261
1262         md1 = &omd->ctr.ctr1.array[i];
1263         md1->version++;
1264         md1->attid                     = a->attributeID_id;
1265         if (md1->attid == 0x20030) {
1266                 const struct ldb_val *rdn_val = ldb_dn_get_rdn_val(msg->dn);
1267                 const char* rdn;
1268
1269                 if (rdn_val == NULL) {
1270                         ldb_oom(ldb);
1271                         return LDB_ERR_OPERATIONS_ERROR;
1272                 }
1273
1274                 rdn = (const char*)rdn_val->data;
1275                 if (strcmp(rdn, "Deleted Objects") == 0) {
1276                         /*
1277                          * Set the originating_change_time to 29/12/9999 at 23:59:59
1278                          * as specified in MS-ADTS 7.1.1.4.2 Deleted Objects Container
1279                          */
1280                         md1->originating_change_time    = DELETED_OBJECT_CONTAINER_CHANGE_TIME;
1281                 } else {
1282                         md1->originating_change_time    = now;
1283                 }
1284         } else {
1285                 md1->originating_change_time    = now;
1286         }
1287         md1->originating_invocation_id = *our_invocation_id;
1288         md1->originating_usn           = *seq_num;
1289         md1->local_usn                 = *seq_num;
1290
1291         return LDB_SUCCESS;
1292 }
1293
1294 static uint64_t find_max_local_usn(struct replPropertyMetaDataBlob omd)
1295 {
1296         uint32_t count = omd.ctr.ctr1.count;
1297         uint64_t max = 0;
1298         uint32_t i;
1299         for (i=0; i < count; i++) {
1300                 struct replPropertyMetaData1 m = omd.ctr.ctr1.array[i];
1301                 if (max < m.local_usn) {
1302                         max = m.local_usn;
1303                 }
1304         }
1305         return max;
1306 }
1307
1308 /*
1309  * update the replPropertyMetaData object each time we modify an
1310  * object. This is needed for DRS replication, as the merge on the
1311  * client is based on this object
1312  */
1313 static int replmd_update_rpmd(struct ldb_module *module,
1314                               const struct dsdb_schema *schema,
1315                               struct ldb_request *req,
1316                               const char * const *rename_attrs,
1317                               struct ldb_message *msg, uint64_t *seq_num,
1318                               time_t t,
1319                               bool *is_urgent, bool *rodc)
1320 {
1321         const struct ldb_val *omd_value;
1322         enum ndr_err_code ndr_err;
1323         struct replPropertyMetaDataBlob omd;
1324         unsigned int i;
1325         NTTIME now;
1326         const struct GUID *our_invocation_id;
1327         int ret;
1328         const char * const *attrs = NULL;
1329         const char * const attrs1[] = { "replPropertyMetaData", "*", NULL };
1330         const char * const attrs2[] = { "uSNChanged", "objectClass", "instanceType", NULL };
1331         struct ldb_result *res;
1332         struct ldb_context *ldb;
1333         struct ldb_message_element *objectclass_el;
1334         enum urgent_situation situation;
1335         bool rmd_is_provided;
1336
1337         if (rename_attrs) {
1338                 attrs = rename_attrs;
1339         } else {
1340                 attrs = attrs1;
1341         }
1342
1343         ldb = ldb_module_get_ctx(module);
1344
1345         our_invocation_id = samdb_ntds_invocation_id(ldb);
1346         if (!our_invocation_id) {
1347                 /* this happens during an initial vampire while
1348                    updating the schema */
1349                 DEBUG(5,("No invocationID - skipping replPropertyMetaData update\n"));
1350                 return LDB_SUCCESS;
1351         }
1352
1353         unix_to_nt_time(&now, t);
1354
1355         if (ldb_request_get_control(req, DSDB_CONTROL_CHANGEREPLMETADATA_OID)) {
1356                 rmd_is_provided = true;
1357         } else {
1358                 rmd_is_provided = false;
1359         }
1360
1361         /* if isDeleted is present and is TRUE, then we consider we are deleting,
1362          * otherwise we consider we are updating */
1363         if (ldb_msg_check_string_attribute(msg, "isDeleted", "TRUE")) {
1364                 situation = REPL_URGENT_ON_DELETE;
1365         } else if (rename_attrs) {
1366                 situation = REPL_URGENT_ON_CREATE | REPL_URGENT_ON_DELETE;
1367         } else {
1368                 situation = REPL_URGENT_ON_UPDATE;
1369         }
1370
1371         if (rmd_is_provided) {
1372                 /* In this case the change_replmetadata control was supplied */
1373                 /* We check that it's the only attribute that is provided
1374                  * (it's a rare case so it's better to keep the code simplier)
1375                  * We also check that the highest local_usn is bigger than
1376                  * uSNChanged. */
1377                 uint64_t db_seq;
1378                 if( msg->num_elements != 1 ||
1379                         strncmp(msg->elements[0].name,
1380                                 "replPropertyMetaData", 20) ) {
1381                         DEBUG(0,(__location__ ": changereplmetada control called without "\
1382                                 "a specified replPropertyMetaData attribute or with others\n"));
1383                         return LDB_ERR_OPERATIONS_ERROR;
1384                 }
1385                 if (situation != REPL_URGENT_ON_UPDATE) {
1386                         DEBUG(0,(__location__ ": changereplmetada control can't be called when deleting an object\n"));
1387                         return LDB_ERR_OPERATIONS_ERROR;
1388                 }
1389                 omd_value = ldb_msg_find_ldb_val(msg, "replPropertyMetaData");
1390                 if (!omd_value) {
1391                         DEBUG(0,(__location__ ": replPropertyMetaData was not specified for Object %s\n",
1392                                  ldb_dn_get_linearized(msg->dn)));
1393                         return LDB_ERR_OPERATIONS_ERROR;
1394                 }
1395                 ndr_err = ndr_pull_struct_blob(omd_value, msg, &omd,
1396                                                (ndr_pull_flags_fn_t)ndr_pull_replPropertyMetaDataBlob);
1397                 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
1398                         DEBUG(0,(__location__ ": Failed to parse replPropertyMetaData for %s\n",
1399                                  ldb_dn_get_linearized(msg->dn)));
1400                         return LDB_ERR_OPERATIONS_ERROR;
1401                 }
1402                 *seq_num = find_max_local_usn(omd);
1403
1404                 ret = dsdb_module_search_dn(module, msg, &res, msg->dn, attrs2,
1405                                             DSDB_FLAG_NEXT_MODULE |
1406                                             DSDB_SEARCH_SHOW_RECYCLED |
1407                                             DSDB_SEARCH_SHOW_EXTENDED_DN |
1408                                             DSDB_SEARCH_SHOW_DN_IN_STORAGE_FORMAT |
1409                                             DSDB_SEARCH_REVEAL_INTERNALS, req);
1410
1411                 if (ret != LDB_SUCCESS) {
1412                         return ret;
1413                 }
1414
1415                 objectclass_el = ldb_msg_find_element(res->msgs[0], "objectClass");
1416                 if (is_urgent && replmd_check_urgent_objectclass(objectclass_el,
1417                                                                 situation)) {
1418                         *is_urgent = true;
1419                 }
1420
1421                 db_seq = ldb_msg_find_attr_as_uint64(res->msgs[0], "uSNChanged", 0);
1422                 if (*seq_num <= db_seq) {
1423                         DEBUG(0,(__location__ ": changereplmetada control provided but max(local_usn)"\
1424                                               " is less or equal to uSNChanged (max = %lld uSNChanged = %lld)\n",
1425                                  (long long)*seq_num, (long long)db_seq));
1426                         return LDB_ERR_OPERATIONS_ERROR;
1427                 }
1428
1429         } else {
1430                 /* search for the existing replPropertyMetaDataBlob. We need
1431                  * to use REVEAL and ask for DNs in storage format to support
1432                  * the check for values being the same in
1433                  * replmd_update_rpmd_element()
1434                  */
1435                 ret = dsdb_module_search_dn(module, msg, &res, msg->dn, attrs,
1436                                             DSDB_FLAG_NEXT_MODULE |
1437                                             DSDB_SEARCH_SHOW_RECYCLED |
1438                                             DSDB_SEARCH_SHOW_EXTENDED_DN |
1439                                             DSDB_SEARCH_SHOW_DN_IN_STORAGE_FORMAT |
1440                                             DSDB_SEARCH_REVEAL_INTERNALS, req);
1441                 if (ret != LDB_SUCCESS) {
1442                         return ret;
1443                 }
1444
1445                 objectclass_el = ldb_msg_find_element(res->msgs[0], "objectClass");
1446                 if (is_urgent && replmd_check_urgent_objectclass(objectclass_el,
1447                                                                 situation)) {
1448                         *is_urgent = true;
1449                 }
1450
1451                 omd_value = ldb_msg_find_ldb_val(res->msgs[0], "replPropertyMetaData");
1452                 if (!omd_value) {
1453                         DEBUG(0,(__location__ ": Object %s does not have a replPropertyMetaData attribute\n",
1454                                  ldb_dn_get_linearized(msg->dn)));
1455                         return LDB_ERR_OPERATIONS_ERROR;
1456                 }
1457
1458                 ndr_err = ndr_pull_struct_blob(omd_value, msg, &omd,
1459                                                (ndr_pull_flags_fn_t)ndr_pull_replPropertyMetaDataBlob);
1460                 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
1461                         DEBUG(0,(__location__ ": Failed to parse replPropertyMetaData for %s\n",
1462                                  ldb_dn_get_linearized(msg->dn)));
1463                         return LDB_ERR_OPERATIONS_ERROR;
1464                 }
1465
1466                 if (omd.version != 1) {
1467                         DEBUG(0,(__location__ ": bad version %u in replPropertyMetaData for %s\n",
1468                                  omd.version, ldb_dn_get_linearized(msg->dn)));
1469                         return LDB_ERR_OPERATIONS_ERROR;
1470                 }
1471
1472                 for (i=0; i<msg->num_elements; i++) {
1473                         struct ldb_message_element *old_el;
1474                         old_el = ldb_msg_find_element(res->msgs[0], msg->elements[i].name);
1475                         ret = replmd_update_rpmd_element(ldb, msg, &msg->elements[i], old_el, &omd, schema, seq_num,
1476                                                          our_invocation_id, now, req);
1477                         if (ret != LDB_SUCCESS) {
1478                                 return ret;
1479                         }
1480
1481                         if (is_urgent && !*is_urgent && (situation == REPL_URGENT_ON_UPDATE)) {
1482                                 *is_urgent = replmd_check_urgent_attribute(&msg->elements[i]);
1483                         }
1484
1485                 }
1486         }
1487         /*
1488          * replmd_update_rpmd_element has done an update if the
1489          * seq_num is set
1490          */
1491         if (*seq_num != 0) {
1492                 struct ldb_val *md_value;
1493                 struct ldb_message_element *el;
1494
1495                 /*if we are RODC and this is a DRSR update then its ok*/
1496                 if (!ldb_request_get_control(req, DSDB_CONTROL_REPLICATED_UPDATE_OID)
1497                     && !ldb_request_get_control(req, DSDB_CONTROL_DBCHECK_MODIFY_RO_REPLICA)) {
1498                         unsigned instanceType;
1499
1500                         ret = samdb_rodc(ldb, rodc);
1501                         if (ret != LDB_SUCCESS) {
1502                                 DEBUG(4, (__location__ ": unable to tell if we are an RODC\n"));
1503                         } else if (*rodc) {
1504                                 ldb_set_errstring(ldb, "RODC modify is forbidden!");
1505                                 return LDB_ERR_REFERRAL;
1506                         }
1507
1508                         instanceType = ldb_msg_find_attr_as_uint(res->msgs[0], "instanceType", INSTANCE_TYPE_WRITE);
1509                         if (!(instanceType & INSTANCE_TYPE_WRITE)) {
1510                                 return ldb_error(ldb, LDB_ERR_UNWILLING_TO_PERFORM,
1511                                                  "cannot change replicated attribute on partial replica");
1512                         }
1513                 }
1514
1515                 md_value = talloc(msg, struct ldb_val);
1516                 if (md_value == NULL) {
1517                         ldb_oom(ldb);
1518                         return LDB_ERR_OPERATIONS_ERROR;
1519                 }
1520
1521                 ret = replmd_replPropertyMetaDataCtr1_sort(&omd.ctr.ctr1, schema, msg->dn);
1522                 if (ret != LDB_SUCCESS) {
1523                         return ret;
1524                 }
1525
1526                 ndr_err = ndr_push_struct_blob(md_value, msg, &omd,
1527                                                (ndr_push_flags_fn_t)ndr_push_replPropertyMetaDataBlob);
1528                 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
1529                         DEBUG(0,(__location__ ": Failed to marshall replPropertyMetaData for %s\n",
1530                                  ldb_dn_get_linearized(msg->dn)));
1531                         return LDB_ERR_OPERATIONS_ERROR;
1532                 }
1533
1534                 ret = ldb_msg_add_empty(msg, "replPropertyMetaData", LDB_FLAG_MOD_REPLACE, &el);
1535                 if (ret != LDB_SUCCESS) {
1536                         DEBUG(0,(__location__ ": Failed to add updated replPropertyMetaData %s\n",
1537                                  ldb_dn_get_linearized(msg->dn)));
1538                         return ret;
1539                 }
1540
1541                 el->num_values = 1;
1542                 el->values = md_value;
1543         }
1544
1545         return LDB_SUCCESS;
1546 }
1547
1548 struct parsed_dn {
1549         struct dsdb_dn *dsdb_dn;
1550         struct GUID *guid;
1551         struct ldb_val *v;
1552 };
1553
1554 static int parsed_dn_compare(struct parsed_dn *pdn1, struct parsed_dn *pdn2)
1555 {
1556         return GUID_compare(pdn1->guid, pdn2->guid);
1557 }
1558
1559 static struct parsed_dn *parsed_dn_find(struct parsed_dn *pdn,
1560                                         unsigned int count, struct GUID *guid,
1561                                         struct ldb_dn *dn)
1562 {
1563         struct parsed_dn *ret;
1564         unsigned int i;
1565         if (dn && GUID_all_zero(guid)) {
1566                 /* when updating a link using DRS, we sometimes get a
1567                    NULL GUID. We then need to try and match by DN */
1568                 for (i=0; i<count; i++) {
1569                         if (ldb_dn_compare(pdn[i].dsdb_dn->dn, dn) == 0) {
1570                                 dsdb_get_extended_dn_guid(pdn[i].dsdb_dn->dn, guid, "GUID");
1571                                 return &pdn[i];
1572                         }
1573                 }
1574                 return NULL;
1575         }
1576         BINARY_ARRAY_SEARCH(pdn, count, guid, guid, GUID_compare, ret);
1577         return ret;
1578 }
1579
1580 /*
1581   get a series of message element values as an array of DNs and GUIDs
1582   the result is sorted by GUID
1583  */
1584 static int get_parsed_dns(struct ldb_module *module, TALLOC_CTX *mem_ctx,
1585                           struct ldb_message_element *el, struct parsed_dn **pdn,
1586                           const char *ldap_oid, struct ldb_request *parent)
1587 {
1588         unsigned int i;
1589         struct ldb_context *ldb = ldb_module_get_ctx(module);
1590
1591         if (el == NULL) {
1592                 *pdn = NULL;
1593                 return LDB_SUCCESS;
1594         }
1595
1596         (*pdn) = talloc_array(mem_ctx, struct parsed_dn, el->num_values);
1597         if (!*pdn) {
1598                 ldb_module_oom(module);
1599                 return LDB_ERR_OPERATIONS_ERROR;
1600         }
1601
1602         for (i=0; i<el->num_values; i++) {
1603                 struct ldb_val *v = &el->values[i];
1604                 NTSTATUS status;
1605                 struct ldb_dn *dn;
1606                 struct parsed_dn *p;
1607
1608                 p = &(*pdn)[i];
1609
1610                 p->dsdb_dn = dsdb_dn_parse(*pdn, ldb, v, ldap_oid);
1611                 if (p->dsdb_dn == NULL) {
1612                         return LDB_ERR_INVALID_DN_SYNTAX;
1613                 }
1614
1615                 dn = p->dsdb_dn->dn;
1616
1617                 p->guid = talloc(*pdn, struct GUID);
1618                 if (p->guid == NULL) {
1619                         ldb_module_oom(module);
1620                         return LDB_ERR_OPERATIONS_ERROR;
1621                 }
1622
1623                 status = dsdb_get_extended_dn_guid(dn, p->guid, "GUID");
1624                 if (NT_STATUS_EQUAL(status, NT_STATUS_OBJECT_NAME_NOT_FOUND)) {
1625                         /* we got a DN without a GUID - go find the GUID */
1626                         int ret = dsdb_module_guid_by_dn(module, dn, p->guid, parent);
1627                         if (ret != LDB_SUCCESS) {
1628                                 ldb_asprintf_errstring(ldb, "Unable to find GUID for DN %s\n",
1629                                                        ldb_dn_get_linearized(dn));
1630                                 if (ret == LDB_ERR_NO_SUCH_OBJECT &&
1631                                     LDB_FLAG_MOD_TYPE(el->flags) == LDB_FLAG_MOD_DELETE &&
1632                                     ldb_attr_cmp(el->name, "member") == 0) {
1633                                         return LDB_ERR_UNWILLING_TO_PERFORM;
1634                                 }
1635                                 return ret;
1636                         }
1637                         ret = dsdb_set_extended_dn_guid(dn, p->guid, "GUID");
1638                         if (ret != LDB_SUCCESS) {
1639                                 return ret;
1640                         }
1641                 } else if (!NT_STATUS_IS_OK(status)) {
1642                         return LDB_ERR_OPERATIONS_ERROR;
1643                 }
1644
1645                 /* keep a pointer to the original ldb_val */
1646                 p->v = v;
1647         }
1648
1649         TYPESAFE_QSORT(*pdn, el->num_values, parsed_dn_compare);
1650
1651         return LDB_SUCCESS;
1652 }
1653
1654 /*
1655   build a new extended DN, including all meta data fields
1656
1657   RMD_FLAGS           = DSDB_RMD_FLAG_* bits
1658   RMD_ADDTIME         = originating_add_time
1659   RMD_INVOCID         = originating_invocation_id
1660   RMD_CHANGETIME      = originating_change_time
1661   RMD_ORIGINATING_USN = originating_usn
1662   RMD_LOCAL_USN       = local_usn
1663   RMD_VERSION         = version
1664  */
1665 static int replmd_build_la_val(TALLOC_CTX *mem_ctx, struct ldb_val *v, struct dsdb_dn *dsdb_dn,
1666                                const struct GUID *invocation_id, uint64_t seq_num,
1667                                uint64_t local_usn, NTTIME nttime, uint32_t version, bool deleted)
1668 {
1669         struct ldb_dn *dn = dsdb_dn->dn;
1670         const char *tstring, *usn_string, *flags_string;
1671         struct ldb_val tval;
1672         struct ldb_val iid;
1673         struct ldb_val usnv, local_usnv;
1674         struct ldb_val vers, flagsv;
1675         NTSTATUS status;
1676         int ret;
1677         const char *dnstring;
1678         char *vstring;
1679         uint32_t rmd_flags = deleted?DSDB_RMD_FLAG_DELETED:0;
1680
1681         tstring = talloc_asprintf(mem_ctx, "%llu", (unsigned long long)nttime);
1682         if (!tstring) {
1683                 return LDB_ERR_OPERATIONS_ERROR;
1684         }
1685         tval = data_blob_string_const(tstring);
1686
1687         usn_string = talloc_asprintf(mem_ctx, "%llu", (unsigned long long)seq_num);
1688         if (!usn_string) {
1689                 return LDB_ERR_OPERATIONS_ERROR;
1690         }
1691         usnv = data_blob_string_const(usn_string);
1692
1693         usn_string = talloc_asprintf(mem_ctx, "%llu", (unsigned long long)local_usn);
1694         if (!usn_string) {
1695                 return LDB_ERR_OPERATIONS_ERROR;
1696         }
1697         local_usnv = data_blob_string_const(usn_string);
1698
1699         vstring = talloc_asprintf(mem_ctx, "%lu", (unsigned long)version);
1700         if (!vstring) {
1701                 return LDB_ERR_OPERATIONS_ERROR;
1702         }
1703         vers = data_blob_string_const(vstring);
1704
1705         status = GUID_to_ndr_blob(invocation_id, dn, &iid);
1706         if (!NT_STATUS_IS_OK(status)) {
1707                 return LDB_ERR_OPERATIONS_ERROR;
1708         }
1709
1710         flags_string = talloc_asprintf(mem_ctx, "%u", rmd_flags);
1711         if (!flags_string) {
1712                 return LDB_ERR_OPERATIONS_ERROR;
1713         }
1714         flagsv = data_blob_string_const(flags_string);
1715
1716         ret = ldb_dn_set_extended_component(dn, "RMD_FLAGS", &flagsv);
1717         if (ret != LDB_SUCCESS) return ret;
1718         ret = ldb_dn_set_extended_component(dn, "RMD_ADDTIME", &tval);
1719         if (ret != LDB_SUCCESS) return ret;
1720         ret = ldb_dn_set_extended_component(dn, "RMD_INVOCID", &iid);
1721         if (ret != LDB_SUCCESS) return ret;
1722         ret = ldb_dn_set_extended_component(dn, "RMD_CHANGETIME", &tval);
1723         if (ret != LDB_SUCCESS) return ret;
1724         ret = ldb_dn_set_extended_component(dn, "RMD_LOCAL_USN", &local_usnv);
1725         if (ret != LDB_SUCCESS) return ret;
1726         ret = ldb_dn_set_extended_component(dn, "RMD_ORIGINATING_USN", &usnv);
1727         if (ret != LDB_SUCCESS) return ret;
1728         ret = ldb_dn_set_extended_component(dn, "RMD_VERSION", &vers);
1729         if (ret != LDB_SUCCESS) return ret;
1730
1731         dnstring = dsdb_dn_get_extended_linearized(mem_ctx, dsdb_dn, 1);
1732         if (dnstring == NULL) {
1733                 return LDB_ERR_OPERATIONS_ERROR;
1734         }
1735         *v = data_blob_string_const(dnstring);
1736
1737         return LDB_SUCCESS;
1738 }
1739
1740 static int replmd_update_la_val(TALLOC_CTX *mem_ctx, struct ldb_val *v, struct dsdb_dn *dsdb_dn,
1741                                 struct dsdb_dn *old_dsdb_dn, const struct GUID *invocation_id,
1742                                 uint64_t seq_num, uint64_t local_usn, NTTIME nttime,
1743                                 uint32_t version, bool deleted);
1744
1745 /*
1746   check if any links need upgrading from w2k format
1747
1748   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.
1749  */
1750 static int replmd_check_upgrade_links(struct parsed_dn *dns, uint32_t count, struct ldb_message_element *parent_ctx, const struct GUID *invocation_id)
1751 {
1752         uint32_t i;
1753         for (i=0; i<count; i++) {
1754                 NTSTATUS status;
1755                 uint32_t version;
1756                 int ret;
1757
1758                 status = dsdb_get_extended_dn_uint32(dns[i].dsdb_dn->dn, &version, "RMD_VERSION");
1759                 if (!NT_STATUS_EQUAL(status, NT_STATUS_OBJECT_NAME_NOT_FOUND)) {
1760                         continue;
1761                 }
1762
1763                 /* it's an old one that needs upgrading */
1764                 ret = replmd_update_la_val(parent_ctx->values, dns[i].v, dns[i].dsdb_dn, dns[i].dsdb_dn, invocation_id,
1765                                            1, 1, 0, 0, false);
1766                 if (ret != LDB_SUCCESS) {
1767                         return ret;
1768                 }
1769         }
1770         return LDB_SUCCESS;
1771 }
1772
1773 /*
1774   update an extended DN, including all meta data fields
1775
1776   see replmd_build_la_val for value names
1777  */
1778 static int replmd_update_la_val(TALLOC_CTX *mem_ctx, struct ldb_val *v, struct dsdb_dn *dsdb_dn,
1779                                 struct dsdb_dn *old_dsdb_dn, const struct GUID *invocation_id,
1780                                 uint64_t seq_num, uint64_t local_usn, NTTIME nttime,
1781                                 uint32_t version, bool deleted)
1782 {
1783         struct ldb_dn *dn = dsdb_dn->dn;
1784         const char *tstring, *usn_string, *flags_string;
1785         struct ldb_val tval;
1786         struct ldb_val iid;
1787         struct ldb_val usnv, local_usnv;
1788         struct ldb_val vers, flagsv;
1789         const struct ldb_val *old_addtime;
1790         uint32_t old_version;
1791         NTSTATUS status;
1792         int ret;
1793         const char *dnstring;
1794         char *vstring;
1795         uint32_t rmd_flags = deleted?DSDB_RMD_FLAG_DELETED:0;
1796
1797         tstring = talloc_asprintf(mem_ctx, "%llu", (unsigned long long)nttime);
1798         if (!tstring) {
1799                 return LDB_ERR_OPERATIONS_ERROR;
1800         }
1801         tval = data_blob_string_const(tstring);
1802
1803         usn_string = talloc_asprintf(mem_ctx, "%llu", (unsigned long long)seq_num);
1804         if (!usn_string) {
1805                 return LDB_ERR_OPERATIONS_ERROR;
1806         }
1807         usnv = data_blob_string_const(usn_string);
1808
1809         usn_string = talloc_asprintf(mem_ctx, "%llu", (unsigned long long)local_usn);
1810         if (!usn_string) {
1811                 return LDB_ERR_OPERATIONS_ERROR;
1812         }
1813         local_usnv = data_blob_string_const(usn_string);
1814
1815         status = GUID_to_ndr_blob(invocation_id, dn, &iid);
1816         if (!NT_STATUS_IS_OK(status)) {
1817                 return LDB_ERR_OPERATIONS_ERROR;
1818         }
1819
1820         flags_string = talloc_asprintf(mem_ctx, "%u", rmd_flags);
1821         if (!flags_string) {
1822                 return LDB_ERR_OPERATIONS_ERROR;
1823         }
1824         flagsv = data_blob_string_const(flags_string);
1825
1826         ret = ldb_dn_set_extended_component(dn, "RMD_FLAGS", &flagsv);
1827         if (ret != LDB_SUCCESS) return ret;
1828
1829         /* get the ADDTIME from the original */
1830         old_addtime = ldb_dn_get_extended_component(old_dsdb_dn->dn, "RMD_ADDTIME");
1831         if (old_addtime == NULL) {
1832                 old_addtime = &tval;
1833         }
1834         if (dsdb_dn != old_dsdb_dn ||
1835             ldb_dn_get_extended_component(dn, "RMD_ADDTIME") == NULL) {
1836                 ret = ldb_dn_set_extended_component(dn, "RMD_ADDTIME", old_addtime);
1837                 if (ret != LDB_SUCCESS) return ret;
1838         }
1839
1840         /* use our invocation id */
1841         ret = ldb_dn_set_extended_component(dn, "RMD_INVOCID", &iid);
1842         if (ret != LDB_SUCCESS) return ret;
1843
1844         /* changetime is the current time */
1845         ret = ldb_dn_set_extended_component(dn, "RMD_CHANGETIME", &tval);
1846         if (ret != LDB_SUCCESS) return ret;
1847
1848         /* update the USN */
1849         ret = ldb_dn_set_extended_component(dn, "RMD_ORIGINATING_USN", &usnv);
1850         if (ret != LDB_SUCCESS) return ret;
1851
1852         ret = ldb_dn_set_extended_component(dn, "RMD_LOCAL_USN", &local_usnv);
1853         if (ret != LDB_SUCCESS) return ret;
1854
1855         /* increase the version by 1 */
1856         status = dsdb_get_extended_dn_uint32(old_dsdb_dn->dn, &old_version, "RMD_VERSION");
1857         if (NT_STATUS_IS_OK(status) && old_version >= version) {
1858                 version = old_version+1;
1859         }
1860         vstring = talloc_asprintf(dn, "%lu", (unsigned long)version);
1861         vers = data_blob_string_const(vstring);
1862         ret = ldb_dn_set_extended_component(dn, "RMD_VERSION", &vers);
1863         if (ret != LDB_SUCCESS) return ret;
1864
1865         dnstring = dsdb_dn_get_extended_linearized(mem_ctx, dsdb_dn, 1);
1866         if (dnstring == NULL) {
1867                 return LDB_ERR_OPERATIONS_ERROR;
1868         }
1869         *v = data_blob_string_const(dnstring);
1870
1871         return LDB_SUCCESS;
1872 }
1873
1874 /*
1875   handle adding a linked attribute
1876  */
1877 static int replmd_modify_la_add(struct ldb_module *module,
1878                                 const struct dsdb_schema *schema,
1879                                 struct ldb_message *msg,
1880                                 struct ldb_message_element *el,
1881                                 struct ldb_message_element *old_el,
1882                                 const struct dsdb_attribute *schema_attr,
1883                                 uint64_t seq_num,
1884                                 time_t t,
1885                                 struct GUID *msg_guid,
1886                                 struct ldb_request *parent)
1887 {
1888         unsigned int i;
1889         struct parsed_dn *dns, *old_dns;
1890         TALLOC_CTX *tmp_ctx = talloc_new(msg);
1891         int ret;
1892         struct ldb_val *new_values = NULL;
1893         unsigned int num_new_values = 0;
1894         unsigned old_num_values = old_el?old_el->num_values:0;
1895         const struct GUID *invocation_id;
1896         struct ldb_context *ldb = ldb_module_get_ctx(module);
1897         NTTIME now;
1898
1899         unix_to_nt_time(&now, t);
1900
1901         ret = get_parsed_dns(module, tmp_ctx, el, &dns, schema_attr->syntax->ldap_oid, parent);
1902         if (ret != LDB_SUCCESS) {
1903                 talloc_free(tmp_ctx);
1904                 return ret;
1905         }
1906
1907         ret = get_parsed_dns(module, tmp_ctx, old_el, &old_dns, schema_attr->syntax->ldap_oid, parent);
1908         if (ret != LDB_SUCCESS) {
1909                 talloc_free(tmp_ctx);
1910                 return ret;
1911         }
1912
1913         invocation_id = samdb_ntds_invocation_id(ldb);
1914         if (!invocation_id) {
1915                 talloc_free(tmp_ctx);
1916                 return LDB_ERR_OPERATIONS_ERROR;
1917         }
1918
1919         ret = replmd_check_upgrade_links(old_dns, old_num_values, old_el, invocation_id);
1920         if (ret != LDB_SUCCESS) {
1921                 talloc_free(tmp_ctx);
1922                 return ret;
1923         }
1924
1925         /* for each new value, see if it exists already with the same GUID */
1926         for (i=0; i<el->num_values; i++) {
1927                 struct parsed_dn *p = parsed_dn_find(old_dns, old_num_values, dns[i].guid, NULL);
1928                 if (p == NULL) {
1929                         /* this is a new linked attribute value */
1930                         new_values = talloc_realloc(tmp_ctx, new_values, struct ldb_val, num_new_values+1);
1931                         if (new_values == NULL) {
1932                                 ldb_module_oom(module);
1933                                 talloc_free(tmp_ctx);
1934                                 return LDB_ERR_OPERATIONS_ERROR;
1935                         }
1936                         ret = replmd_build_la_val(new_values, &new_values[num_new_values], dns[i].dsdb_dn,
1937                                                   invocation_id, seq_num, seq_num, now, 0, false);
1938                         if (ret != LDB_SUCCESS) {
1939                                 talloc_free(tmp_ctx);
1940                                 return ret;
1941                         }
1942                         num_new_values++;
1943                 } else {
1944                         /* this is only allowed if the GUID was
1945                            previously deleted. */
1946                         uint32_t rmd_flags = dsdb_dn_rmd_flags(p->dsdb_dn->dn);
1947
1948                         if (!(rmd_flags & DSDB_RMD_FLAG_DELETED)) {
1949                                 ldb_asprintf_errstring(ldb, "Attribute %s already exists for target GUID %s",
1950                                                        el->name, GUID_string(tmp_ctx, p->guid));
1951                                 talloc_free(tmp_ctx);
1952                                 /* error codes for 'member' need to be
1953                                    special cased */
1954                                 if (ldb_attr_cmp(el->name, "member") == 0) {
1955                                         return LDB_ERR_ENTRY_ALREADY_EXISTS;
1956                                 } else {
1957                                         return LDB_ERR_ATTRIBUTE_OR_VALUE_EXISTS;
1958                                 }
1959                         }
1960                         ret = replmd_update_la_val(old_el->values, p->v, dns[i].dsdb_dn, p->dsdb_dn,
1961                                                    invocation_id, seq_num, seq_num, now, 0, false);
1962                         if (ret != LDB_SUCCESS) {
1963                                 talloc_free(tmp_ctx);
1964                                 return ret;
1965                         }
1966                 }
1967
1968                 ret = replmd_add_backlink(module, schema, msg_guid, dns[i].guid, true, schema_attr, true);
1969                 if (ret != LDB_SUCCESS) {
1970                         talloc_free(tmp_ctx);
1971                         return ret;
1972                 }
1973         }
1974
1975         /* add the new ones on to the end of the old values, constructing a new el->values */
1976         el->values = talloc_realloc(msg->elements, old_el?old_el->values:NULL,
1977                                     struct ldb_val,
1978                                     old_num_values+num_new_values);
1979         if (el->values == NULL) {
1980                 ldb_module_oom(module);
1981                 return LDB_ERR_OPERATIONS_ERROR;
1982         }
1983
1984         memcpy(&el->values[old_num_values], new_values, num_new_values*sizeof(struct ldb_val));
1985         el->num_values = old_num_values + num_new_values;
1986
1987         talloc_steal(msg->elements, el->values);
1988         talloc_steal(el->values, new_values);
1989
1990         talloc_free(tmp_ctx);
1991
1992         /* we now tell the backend to replace all existing values
1993            with the one we have constructed */
1994         el->flags = LDB_FLAG_MOD_REPLACE;
1995
1996         return LDB_SUCCESS;
1997 }
1998
1999
2000 /*
2001   handle deleting all active linked attributes
2002  */
2003 static int replmd_modify_la_delete(struct ldb_module *module,
2004                                    const struct dsdb_schema *schema,
2005                                    struct ldb_message *msg,
2006                                    struct ldb_message_element *el,
2007                                    struct ldb_message_element *old_el,
2008                                    const struct dsdb_attribute *schema_attr,
2009                                    uint64_t seq_num,
2010                                    time_t t,
2011                                    struct GUID *msg_guid,
2012                                    struct ldb_request *parent)
2013 {
2014         unsigned int i;
2015         struct parsed_dn *dns, *old_dns;
2016         TALLOC_CTX *tmp_ctx = talloc_new(msg);
2017         int ret;
2018         const struct GUID *invocation_id;
2019         struct ldb_context *ldb = ldb_module_get_ctx(module);
2020         NTTIME now;
2021
2022         unix_to_nt_time(&now, t);
2023
2024         /* check if there is nothing to delete */
2025         if ((!old_el || old_el->num_values == 0) &&
2026             el->num_values == 0) {
2027                 return LDB_SUCCESS;
2028         }
2029
2030         if (!old_el || old_el->num_values == 0) {
2031                 return LDB_ERR_NO_SUCH_ATTRIBUTE;
2032         }
2033
2034         ret = get_parsed_dns(module, tmp_ctx, el, &dns, schema_attr->syntax->ldap_oid, parent);
2035         if (ret != LDB_SUCCESS) {
2036                 talloc_free(tmp_ctx);
2037                 return ret;
2038         }
2039
2040         ret = get_parsed_dns(module, tmp_ctx, old_el, &old_dns, schema_attr->syntax->ldap_oid, parent);
2041         if (ret != LDB_SUCCESS) {
2042                 talloc_free(tmp_ctx);
2043                 return ret;
2044         }
2045
2046         invocation_id = samdb_ntds_invocation_id(ldb);
2047         if (!invocation_id) {
2048                 return LDB_ERR_OPERATIONS_ERROR;
2049         }
2050
2051         ret = replmd_check_upgrade_links(old_dns, old_el->num_values, old_el, invocation_id);
2052         if (ret != LDB_SUCCESS) {
2053                 talloc_free(tmp_ctx);
2054                 return ret;
2055         }
2056
2057         el->values = NULL;
2058
2059         /* see if we are being asked to delete any links that
2060            don't exist or are already deleted */
2061         for (i=0; i<el->num_values; i++) {
2062                 struct parsed_dn *p = &dns[i];
2063                 struct parsed_dn *p2;
2064                 uint32_t rmd_flags;
2065
2066                 p2 = parsed_dn_find(old_dns, old_el->num_values, p->guid, NULL);
2067                 if (!p2) {
2068                         ldb_asprintf_errstring(ldb, "Attribute %s doesn't exist for target GUID %s",
2069                                                el->name, GUID_string(tmp_ctx, p->guid));
2070                         if (ldb_attr_cmp(el->name, "member") == 0) {
2071                                 return LDB_ERR_UNWILLING_TO_PERFORM;
2072                         } else {
2073                                 return LDB_ERR_NO_SUCH_ATTRIBUTE;
2074                         }
2075                 }
2076                 rmd_flags = dsdb_dn_rmd_flags(p2->dsdb_dn->dn);
2077                 if (rmd_flags & DSDB_RMD_FLAG_DELETED) {
2078                         ldb_asprintf_errstring(ldb, "Attribute %s already deleted for target GUID %s",
2079                                                el->name, GUID_string(tmp_ctx, p->guid));
2080                         if (ldb_attr_cmp(el->name, "member") == 0) {
2081                                 return LDB_ERR_UNWILLING_TO_PERFORM;
2082                         } else {
2083                                 return LDB_ERR_NO_SUCH_ATTRIBUTE;
2084                         }
2085                 }
2086         }
2087
2088         /* for each new value, see if it exists already with the same GUID
2089            if it is not already deleted and matches the delete list then delete it
2090         */
2091         for (i=0; i<old_el->num_values; i++) {
2092                 struct parsed_dn *p = &old_dns[i];
2093                 uint32_t rmd_flags;
2094
2095                 if (el->num_values && parsed_dn_find(dns, el->num_values, p->guid, NULL) == NULL) {
2096                         continue;
2097                 }
2098
2099                 rmd_flags = dsdb_dn_rmd_flags(p->dsdb_dn->dn);
2100                 if (rmd_flags & DSDB_RMD_FLAG_DELETED) continue;
2101
2102                 ret = replmd_update_la_val(old_el->values, p->v, p->dsdb_dn, p->dsdb_dn,
2103                                            invocation_id, seq_num, seq_num, now, 0, true);
2104                 if (ret != LDB_SUCCESS) {
2105                         talloc_free(tmp_ctx);
2106                         return ret;
2107                 }
2108
2109                 ret = replmd_add_backlink(module, schema, msg_guid, old_dns[i].guid, false, schema_attr, true);
2110                 if (ret != LDB_SUCCESS) {
2111                         talloc_free(tmp_ctx);
2112                         return ret;
2113                 }
2114         }
2115
2116         el->values = talloc_steal(msg->elements, old_el->values);
2117         el->num_values = old_el->num_values;
2118
2119         talloc_free(tmp_ctx);
2120
2121         /* we now tell the backend to replace all existing values
2122            with the one we have constructed */
2123         el->flags = LDB_FLAG_MOD_REPLACE;
2124
2125         return LDB_SUCCESS;
2126 }
2127
2128 /*
2129   handle replacing a linked attribute
2130  */
2131 static int replmd_modify_la_replace(struct ldb_module *module,
2132                                     const struct dsdb_schema *schema,
2133                                     struct ldb_message *msg,
2134                                     struct ldb_message_element *el,
2135                                     struct ldb_message_element *old_el,
2136                                     const struct dsdb_attribute *schema_attr,
2137                                     uint64_t seq_num,
2138                                     time_t t,
2139                                     struct GUID *msg_guid,
2140                                     struct ldb_request *parent)
2141 {
2142         unsigned int i;
2143         struct parsed_dn *dns, *old_dns;
2144         TALLOC_CTX *tmp_ctx = talloc_new(msg);
2145         int ret;
2146         const struct GUID *invocation_id;
2147         struct ldb_context *ldb = ldb_module_get_ctx(module);
2148         struct ldb_val *new_values = NULL;
2149         unsigned int num_new_values = 0;
2150         unsigned int old_num_values = old_el?old_el->num_values:0;
2151         NTTIME now;
2152
2153         unix_to_nt_time(&now, t);
2154
2155         /* check if there is nothing to replace */
2156         if ((!old_el || old_el->num_values == 0) &&
2157             el->num_values == 0) {
2158                 return LDB_SUCCESS;
2159         }
2160
2161         ret = get_parsed_dns(module, tmp_ctx, el, &dns, schema_attr->syntax->ldap_oid, parent);
2162         if (ret != LDB_SUCCESS) {
2163                 talloc_free(tmp_ctx);
2164                 return ret;
2165         }
2166
2167         ret = get_parsed_dns(module, tmp_ctx, old_el, &old_dns, schema_attr->syntax->ldap_oid, parent);
2168         if (ret != LDB_SUCCESS) {
2169                 talloc_free(tmp_ctx);
2170                 return ret;
2171         }
2172
2173         invocation_id = samdb_ntds_invocation_id(ldb);
2174         if (!invocation_id) {
2175                 return LDB_ERR_OPERATIONS_ERROR;
2176         }
2177
2178         ret = replmd_check_upgrade_links(old_dns, old_num_values, old_el, invocation_id);
2179         if (ret != LDB_SUCCESS) {
2180                 talloc_free(tmp_ctx);
2181                 return ret;
2182         }
2183
2184         /* mark all the old ones as deleted */
2185         for (i=0; i<old_num_values; i++) {
2186                 struct parsed_dn *old_p = &old_dns[i];
2187                 struct parsed_dn *p;
2188                 uint32_t rmd_flags = dsdb_dn_rmd_flags(old_p->dsdb_dn->dn);
2189
2190                 if (rmd_flags & DSDB_RMD_FLAG_DELETED) continue;
2191
2192                 ret = replmd_add_backlink(module, schema, msg_guid, old_dns[i].guid, false, schema_attr, false);
2193                 if (ret != LDB_SUCCESS) {
2194                         talloc_free(tmp_ctx);
2195                         return ret;
2196                 }
2197
2198                 p = parsed_dn_find(dns, el->num_values, old_p->guid, NULL);
2199                 if (p) {
2200                         /* we don't delete it if we are re-adding it */
2201                         continue;
2202                 }
2203
2204                 ret = replmd_update_la_val(old_el->values, old_p->v, old_p->dsdb_dn, old_p->dsdb_dn,
2205                                            invocation_id, seq_num, seq_num, now, 0, true);
2206                 if (ret != LDB_SUCCESS) {
2207                         talloc_free(tmp_ctx);
2208                         return ret;
2209                 }
2210         }
2211
2212         /* for each new value, either update its meta-data, or add it
2213          * to old_el
2214         */
2215         for (i=0; i<el->num_values; i++) {
2216                 struct parsed_dn *p = &dns[i], *old_p;
2217
2218                 if (old_dns &&
2219                     (old_p = parsed_dn_find(old_dns,
2220                                             old_num_values, p->guid, NULL)) != NULL) {
2221                         /* update in place */
2222                         ret = replmd_update_la_val(old_el->values, old_p->v, p->dsdb_dn,
2223                                                    old_p->dsdb_dn, invocation_id,
2224                                                    seq_num, seq_num, now, 0, false);
2225                         if (ret != LDB_SUCCESS) {
2226                                 talloc_free(tmp_ctx);
2227                                 return ret;
2228                         }
2229                 } else {
2230                         /* add a new one */
2231                         new_values = talloc_realloc(tmp_ctx, new_values, struct ldb_val,
2232                                                     num_new_values+1);
2233                         if (new_values == NULL) {
2234                                 ldb_module_oom(module);
2235                                 talloc_free(tmp_ctx);
2236                                 return LDB_ERR_OPERATIONS_ERROR;
2237                         }
2238                         ret = replmd_build_la_val(new_values, &new_values[num_new_values], dns[i].dsdb_dn,
2239                                                   invocation_id, seq_num, seq_num, now, 0, false);
2240                         if (ret != LDB_SUCCESS) {
2241                                 talloc_free(tmp_ctx);
2242                                 return ret;
2243                         }
2244                         num_new_values++;
2245                 }
2246
2247                 ret = replmd_add_backlink(module, schema, msg_guid, dns[i].guid, true, schema_attr, false);
2248                 if (ret != LDB_SUCCESS) {
2249                         talloc_free(tmp_ctx);
2250                         return ret;
2251                 }
2252         }
2253
2254         /* add the new values to the end of old_el */
2255         if (num_new_values != 0) {
2256                 el->values = talloc_realloc(msg->elements, old_el?old_el->values:NULL,
2257                                             struct ldb_val, old_num_values+num_new_values);
2258                 if (el->values == NULL) {
2259                         ldb_module_oom(module);
2260                         return LDB_ERR_OPERATIONS_ERROR;
2261                 }
2262                 memcpy(&el->values[old_num_values], &new_values[0],
2263                        sizeof(struct ldb_val)*num_new_values);
2264                 el->num_values = old_num_values + num_new_values;
2265                 talloc_steal(msg->elements, new_values);
2266         } else {
2267                 el->values = old_el->values;
2268                 el->num_values = old_el->num_values;
2269                 talloc_steal(msg->elements, el->values);
2270         }
2271
2272         talloc_free(tmp_ctx);
2273
2274         /* we now tell the backend to replace all existing values
2275            with the one we have constructed */
2276         el->flags = LDB_FLAG_MOD_REPLACE;
2277
2278         return LDB_SUCCESS;
2279 }
2280
2281
2282 /*
2283   handle linked attributes in modify requests
2284  */
2285 static int replmd_modify_handle_linked_attribs(struct ldb_module *module,
2286                                                struct ldb_message *msg,
2287                                                uint64_t seq_num, time_t t,
2288                                                struct ldb_request *parent)
2289 {
2290         struct ldb_result *res;
2291         unsigned int i;
2292         int ret;
2293         struct ldb_context *ldb = ldb_module_get_ctx(module);
2294         struct ldb_message *old_msg;
2295
2296         const struct dsdb_schema *schema;
2297         struct GUID old_guid;
2298
2299         if (seq_num == 0) {
2300                 /* there the replmd_update_rpmd code has already
2301                  * checked and saw that there are no linked
2302                  * attributes */
2303                 return LDB_SUCCESS;
2304         }
2305
2306         if (dsdb_functional_level(ldb) == DS_DOMAIN_FUNCTION_2000) {
2307                 /* don't do anything special for linked attributes */
2308                 return LDB_SUCCESS;
2309         }
2310
2311         ret = dsdb_module_search_dn(module, msg, &res, msg->dn, NULL,
2312                                     DSDB_FLAG_NEXT_MODULE |
2313                                     DSDB_SEARCH_SHOW_RECYCLED |
2314                                     DSDB_SEARCH_REVEAL_INTERNALS |
2315                                     DSDB_SEARCH_SHOW_DN_IN_STORAGE_FORMAT,
2316                                     parent);
2317         if (ret != LDB_SUCCESS) {
2318                 return ret;
2319         }
2320         schema = dsdb_get_schema(ldb, res);
2321         if (!schema) {
2322                 return LDB_ERR_OPERATIONS_ERROR;
2323         }
2324
2325         old_msg = res->msgs[0];
2326
2327         old_guid = samdb_result_guid(old_msg, "objectGUID");
2328
2329         for (i=0; i<msg->num_elements; i++) {
2330                 struct ldb_message_element *el = &msg->elements[i];
2331                 struct ldb_message_element *old_el, *new_el;
2332                 const struct dsdb_attribute *schema_attr
2333                         = dsdb_attribute_by_lDAPDisplayName(schema, el->name);
2334                 if (!schema_attr) {
2335                         ldb_asprintf_errstring(ldb,
2336                                                "%s: attribute %s is not a valid attribute in schema",
2337                                                __FUNCTION__, el->name);
2338                         return LDB_ERR_OBJECT_CLASS_VIOLATION;
2339                 }
2340                 if (schema_attr->linkID == 0) {
2341                         continue;
2342                 }
2343                 if ((schema_attr->linkID & 1) == 1) {
2344                         if (parent && ldb_request_get_control(parent, DSDB_CONTROL_DBCHECK)) {
2345                                 continue;
2346                         }
2347                         /* Odd is for the target.  Illegal to modify */
2348                         ldb_asprintf_errstring(ldb,
2349                                                "attribute %s must not be modified directly, it is a linked attribute", el->name);
2350                         return LDB_ERR_UNWILLING_TO_PERFORM;
2351                 }
2352                 old_el = ldb_msg_find_element(old_msg, el->name);
2353                 switch (el->flags & LDB_FLAG_MOD_MASK) {
2354                 case LDB_FLAG_MOD_REPLACE:
2355                         ret = replmd_modify_la_replace(module, schema, msg, el, old_el, schema_attr, seq_num, t, &old_guid, parent);
2356                         break;
2357                 case LDB_FLAG_MOD_DELETE:
2358                         ret = replmd_modify_la_delete(module, schema, msg, el, old_el, schema_attr, seq_num, t, &old_guid, parent);
2359                         break;
2360                 case LDB_FLAG_MOD_ADD:
2361                         ret = replmd_modify_la_add(module, schema, msg, el, old_el, schema_attr, seq_num, t, &old_guid, parent);
2362                         break;
2363                 default:
2364                         ldb_asprintf_errstring(ldb,
2365                                                "invalid flags 0x%x for %s linked attribute",
2366                                                el->flags, el->name);
2367                         return LDB_ERR_UNWILLING_TO_PERFORM;
2368                 }
2369                 if (dsdb_check_single_valued_link(schema_attr, el) != LDB_SUCCESS) {
2370                         ldb_asprintf_errstring(ldb,
2371                                                "Attribute %s is single valued but more than one value has been supplied",
2372                                                el->name);
2373                         return LDB_ERR_ATTRIBUTE_OR_VALUE_EXISTS;
2374                 } else {
2375                         el->flags |= LDB_FLAG_INTERNAL_DISABLE_SINGLE_VALUE_CHECK;
2376                 }
2377
2378
2379
2380                 if (ret != LDB_SUCCESS) {
2381                         return ret;
2382                 }
2383                 if (old_el) {
2384                         ldb_msg_remove_attr(old_msg, el->name);
2385                 }
2386                 ldb_msg_add_empty(old_msg, el->name, 0, &new_el);
2387                 new_el->num_values = el->num_values;
2388                 new_el->values = talloc_steal(msg->elements, el->values);
2389
2390                 /* TODO: this relises a bit too heavily on the exact
2391                    behaviour of ldb_msg_find_element and
2392                    ldb_msg_remove_element */
2393                 old_el = ldb_msg_find_element(msg, el->name);
2394                 if (old_el != el) {
2395                         ldb_msg_remove_element(msg, old_el);
2396                         i--;
2397                 }
2398         }
2399
2400         talloc_free(res);
2401         return ret;
2402 }
2403
2404
2405
2406 static int replmd_modify(struct ldb_module *module, struct ldb_request *req)
2407 {
2408         struct samldb_msds_intid_persistant *msds_intid_struct;
2409         struct ldb_context *ldb;
2410         struct replmd_replicated_request *ac;
2411         struct ldb_request *down_req;
2412         struct ldb_message *msg;
2413         time_t t = time(NULL);
2414         int ret;
2415         bool is_urgent = false, rodc = false;
2416         unsigned int functional_level;
2417         const DATA_BLOB *guid_blob;
2418         struct ldb_control *sd_propagation_control;
2419
2420         /* do not manipulate our control entries */
2421         if (ldb_dn_is_special(req->op.mod.message->dn)) {
2422                 return ldb_next_request(module, req);
2423         }
2424
2425         sd_propagation_control = ldb_request_get_control(req,
2426                                         DSDB_CONTROL_SEC_DESC_PROPAGATION_OID);
2427         if (sd_propagation_control != NULL) {
2428                 if (req->op.mod.message->num_elements != 1) {
2429                         return ldb_module_operr(module);
2430                 }
2431                 ret = strcmp(req->op.mod.message->elements[0].name,
2432                              "nTSecurityDescriptor");
2433                 if (ret != 0) {
2434                         return ldb_module_operr(module);
2435                 }
2436
2437                 return ldb_next_request(module, req);
2438         }
2439
2440         ldb = ldb_module_get_ctx(module);
2441
2442         ldb_debug(ldb, LDB_DEBUG_TRACE, "replmd_modify\n");
2443
2444         guid_blob = ldb_msg_find_ldb_val(req->op.mod.message, "objectGUID");
2445         if ( guid_blob != NULL ) {
2446                 ldb_set_errstring(ldb,
2447                                   "replmd_modify: it's not allowed to change the objectGUID!");
2448                 return LDB_ERR_CONSTRAINT_VIOLATION;
2449         }
2450
2451         ac = replmd_ctx_init(module, req);
2452         if (ac == NULL) {
2453                 return ldb_module_oom(module);
2454         }
2455
2456         functional_level = dsdb_functional_level(ldb);
2457
2458         /* we have to copy the message as the caller might have it as a const */
2459         msg = ldb_msg_copy_shallow(ac, req->op.mod.message);
2460         if (msg == NULL) {
2461                 ldb_oom(ldb);
2462                 talloc_free(ac);
2463                 return LDB_ERR_OPERATIONS_ERROR;
2464         }
2465
2466         ldb_msg_remove_attr(msg, "whenChanged");
2467         ldb_msg_remove_attr(msg, "uSNChanged");
2468
2469         ret = replmd_update_rpmd(module, ac->schema, req, NULL,
2470                                  msg, &ac->seq_num, t, &is_urgent, &rodc);
2471         if (rodc && (ret == LDB_ERR_REFERRAL)) {
2472                 struct loadparm_context *lp_ctx;
2473                 char *referral;
2474
2475                 lp_ctx = talloc_get_type(ldb_get_opaque(ldb, "loadparm"),
2476                                          struct loadparm_context);
2477
2478                 referral = talloc_asprintf(req,
2479                                            "ldap://%s/%s",
2480                                            lpcfg_dnsdomain(lp_ctx),
2481                                            ldb_dn_get_linearized(msg->dn));
2482                 ret = ldb_module_send_referral(req, referral);
2483                 talloc_free(ac);
2484                 return ret;
2485         }
2486
2487         if (ret != LDB_SUCCESS) {
2488                 talloc_free(ac);
2489                 return ret;
2490         }
2491
2492         ret = replmd_modify_handle_linked_attribs(module, msg, ac->seq_num, t, req);
2493         if (ret != LDB_SUCCESS) {
2494                 talloc_free(ac);
2495                 return ret;
2496         }
2497
2498         /* TODO:
2499          * - replace the old object with the newly constructed one
2500          */
2501
2502         ac->is_urgent = is_urgent;
2503
2504         ret = ldb_build_mod_req(&down_req, ldb, ac,
2505                                 msg,
2506                                 req->controls,
2507                                 ac, replmd_op_callback,
2508                                 req);
2509         LDB_REQ_SET_LOCATION(down_req);
2510         if (ret != LDB_SUCCESS) {
2511                 talloc_free(ac);
2512                 return ret;
2513         }
2514
2515         /* current partition control is needed by "replmd_op_callback" */
2516         if (ldb_request_get_control(req, DSDB_CONTROL_CURRENT_PARTITION_OID) == NULL) {
2517                 ret = ldb_request_add_control(down_req,
2518                                               DSDB_CONTROL_CURRENT_PARTITION_OID,
2519                                               false, NULL);
2520                 if (ret != LDB_SUCCESS) {
2521                         talloc_free(ac);
2522                         return ret;
2523                 }
2524         }
2525
2526         /* If we are in functional level 2000, then
2527          * replmd_modify_handle_linked_attribs will have done
2528          * nothing */
2529         if (functional_level == DS_DOMAIN_FUNCTION_2000) {
2530                 ret = ldb_request_add_control(down_req, DSDB_CONTROL_APPLY_LINKS, false, NULL);
2531                 if (ret != LDB_SUCCESS) {
2532                         talloc_free(ac);
2533                         return ret;
2534                 }
2535         }
2536
2537         talloc_steal(down_req, msg);
2538
2539         /* we only change whenChanged and uSNChanged if the seq_num
2540            has changed */
2541         if (ac->seq_num != 0) {
2542                 ret = add_time_element(msg, "whenChanged", t);
2543                 if (ret != LDB_SUCCESS) {
2544                         talloc_free(ac);
2545                         ldb_operr(ldb);
2546                         return ret;
2547                 }
2548
2549                 ret = add_uint64_element(ldb, msg, "uSNChanged", ac->seq_num);
2550                 if (ret != LDB_SUCCESS) {
2551                         talloc_free(ac);
2552                         ldb_operr(ldb);
2553                         return ret;
2554                 }
2555         }
2556
2557         if (!ldb_dn_compare_base(ac->schema->base_dn, msg->dn)) {
2558                 /* Update the usn in the SAMLDB_MSDS_INTID_OPAQUE opaque */
2559                 msds_intid_struct = (struct samldb_msds_intid_persistant *) ldb_get_opaque(ldb, SAMLDB_MSDS_INTID_OPAQUE);
2560                 if (msds_intid_struct) {
2561                         msds_intid_struct->usn = ac->seq_num;
2562                 }
2563         }
2564
2565         /* go on with the call chain */
2566         return ldb_next_request(module, down_req);
2567 }
2568
2569 static int replmd_rename_callback(struct ldb_request *req, struct ldb_reply *ares);
2570
2571 /*
2572   handle a rename request
2573
2574   On a rename we need to do an extra ldb_modify which sets the
2575   whenChanged and uSNChanged attributes.  We do this in a callback after the success.
2576  */
2577 static int replmd_rename(struct ldb_module *module, struct ldb_request *req)
2578 {
2579         struct ldb_context *ldb;
2580         struct replmd_replicated_request *ac;
2581         int ret;
2582         struct ldb_request *down_req;
2583
2584         /* do not manipulate our control entries */
2585         if (ldb_dn_is_special(req->op.mod.message->dn)) {
2586                 return ldb_next_request(module, req);
2587         }
2588
2589         ldb = ldb_module_get_ctx(module);
2590
2591         ldb_debug(ldb, LDB_DEBUG_TRACE, "replmd_rename\n");
2592
2593         ac = replmd_ctx_init(module, req);
2594         if (ac == NULL) {
2595                 return ldb_module_oom(module);
2596         }
2597
2598         ret = ldb_build_rename_req(&down_req, ldb, ac,
2599                                    ac->req->op.rename.olddn,
2600                                    ac->req->op.rename.newdn,
2601                                    ac->req->controls,
2602                                    ac, replmd_rename_callback,
2603                                    ac->req);
2604         LDB_REQ_SET_LOCATION(down_req);
2605         if (ret != LDB_SUCCESS) {
2606                 talloc_free(ac);
2607                 return ret;
2608         }
2609
2610         /* go on with the call chain */
2611         return ldb_next_request(module, down_req);
2612 }
2613
2614 /* After the rename is compleated, update the whenchanged etc */
2615 static int replmd_rename_callback(struct ldb_request *req, struct ldb_reply *ares)
2616 {
2617         struct ldb_context *ldb;
2618         struct replmd_replicated_request *ac;
2619         struct ldb_request *down_req;
2620         struct ldb_message *msg;
2621         const struct dsdb_attribute *rdn_attr;
2622         const char *rdn_name;
2623         const struct ldb_val *rdn_val;
2624         const char *attrs[5] = { NULL, };
2625         time_t t = time(NULL);
2626         int ret;
2627         bool is_urgent = false, rodc = false;
2628
2629         ac = talloc_get_type(req->context, struct replmd_replicated_request);
2630         ldb = ldb_module_get_ctx(ac->module);
2631
2632         if (ares->error != LDB_SUCCESS) {
2633                 return ldb_module_done(ac->req, ares->controls,
2634                                         ares->response, ares->error);
2635         }
2636
2637         if (ares->type != LDB_REPLY_DONE) {
2638                 ldb_set_errstring(ldb,
2639                                   "invalid ldb_reply_type in callback");
2640                 talloc_free(ares);
2641                 return ldb_module_done(ac->req, NULL, NULL,
2642                                         LDB_ERR_OPERATIONS_ERROR);
2643         }
2644
2645         /* TODO:
2646          * - replace the old object with the newly constructed one
2647          */
2648
2649         msg = ldb_msg_new(ac);
2650         if (msg == NULL) {
2651                 ldb_oom(ldb);
2652                 return LDB_ERR_OPERATIONS_ERROR;
2653         }
2654
2655         msg->dn = ac->req->op.rename.newdn;
2656
2657         rdn_name = ldb_dn_get_rdn_name(msg->dn);
2658         if (rdn_name == NULL) {
2659                 talloc_free(ares);
2660                 return ldb_module_done(ac->req, NULL, NULL,
2661                                        ldb_operr(ldb));
2662         }
2663
2664         /* normalize the rdn attribute name */
2665         rdn_attr = dsdb_attribute_by_lDAPDisplayName(ac->schema, rdn_name);
2666         if (rdn_attr == NULL) {
2667                 talloc_free(ares);
2668                 return ldb_module_done(ac->req, NULL, NULL,
2669                                        ldb_operr(ldb));
2670         }
2671         rdn_name = rdn_attr->lDAPDisplayName;
2672
2673         rdn_val = ldb_dn_get_rdn_val(msg->dn);
2674         if (rdn_val == NULL) {
2675                 talloc_free(ares);
2676                 return ldb_module_done(ac->req, NULL, NULL,
2677                                        ldb_operr(ldb));
2678         }
2679
2680         if (ldb_msg_add_empty(msg, rdn_name, LDB_FLAG_MOD_REPLACE, NULL) != 0) {
2681                 talloc_free(ares);
2682                 return ldb_module_done(ac->req, NULL, NULL,
2683                                        ldb_oom(ldb));
2684         }
2685         if (ldb_msg_add_value(msg, rdn_name, rdn_val, NULL) != 0) {
2686                 talloc_free(ares);
2687                 return ldb_module_done(ac->req, NULL, NULL,
2688                                        ldb_oom(ldb));
2689         }
2690         if (ldb_msg_add_empty(msg, "name", LDB_FLAG_MOD_REPLACE, NULL) != 0) {
2691                 talloc_free(ares);
2692                 return ldb_module_done(ac->req, NULL, NULL,
2693                                        ldb_oom(ldb));
2694         }
2695         if (ldb_msg_add_value(msg, "name", rdn_val, NULL) != 0) {
2696                 talloc_free(ares);
2697                 return ldb_module_done(ac->req, NULL, NULL,
2698                                        ldb_oom(ldb));
2699         }
2700
2701         /*
2702          * here we let replmd_update_rpmd() only search for
2703          * the existing "replPropertyMetaData" and rdn_name attributes.
2704          *
2705          * We do not want the existing "name" attribute as
2706          * the "name" attribute needs to get the version
2707          * updated on rename even if the rdn value hasn't changed.
2708          *
2709          * This is the diff of the meta data, for a moved user
2710          * on a w2k8r2 server:
2711          *
2712          * # record 1
2713          * -dn: CN=sdf df,CN=Users,DC=bla,DC=base
2714          * +dn: CN=sdf df,OU=TestOU,DC=bla,DC=base
2715          *  replPropertyMetaData:     NDR: struct replPropertyMetaDataBlob
2716          *         version                  : 0x00000001 (1)
2717          *         reserved                 : 0x00000000 (0)
2718          * @@ -66,11 +66,11 @@ replPropertyMetaData:     NDR: struct re
2719          *                      local_usn                : 0x00000000000037a5 (14245)
2720          *                 array: struct replPropertyMetaData1
2721          *                      attid                    : DRSUAPI_ATTID_name (0x90001)
2722          * -                    version                  : 0x00000001 (1)
2723          * -                    originating_change_time  : Wed Feb  9 17:20:49 2011 CET
2724          * +                    version                  : 0x00000002 (2)
2725          * +                    originating_change_time  : Wed Apr  6 15:21:01 2011 CEST
2726          *                      originating_invocation_id: 0d36ca05-5507-4e62-aca3-354bab0d39e1
2727          * -                    originating_usn          : 0x00000000000037a5 (14245)
2728          * -                    local_usn                : 0x00000000000037a5 (14245)
2729          * +                    originating_usn          : 0x0000000000003834 (14388)
2730          * +                    local_usn                : 0x0000000000003834 (14388)
2731          *                 array: struct replPropertyMetaData1
2732          *                      attid                    : DRSUAPI_ATTID_userAccountControl (0x90008)
2733          *                      version                  : 0x00000004 (4)
2734          */
2735         attrs[0] = "replPropertyMetaData";
2736         attrs[1] = "objectClass";
2737         attrs[2] = "instanceType";
2738         attrs[3] = rdn_name;
2739         attrs[4] = NULL;
2740
2741         ret = replmd_update_rpmd(ac->module, ac->schema, req, attrs,
2742                                  msg, &ac->seq_num, t, &is_urgent, &rodc);
2743         if (rodc && (ret == LDB_ERR_REFERRAL)) {
2744                 struct ldb_dn *olddn = ac->req->op.rename.olddn;
2745                 struct loadparm_context *lp_ctx;
2746                 char *referral;
2747
2748                 lp_ctx = talloc_get_type(ldb_get_opaque(ldb, "loadparm"),
2749                                          struct loadparm_context);
2750
2751                 referral = talloc_asprintf(req,
2752                                            "ldap://%s/%s",
2753                                            lpcfg_dnsdomain(lp_ctx),
2754                                            ldb_dn_get_linearized(olddn));
2755                 ret = ldb_module_send_referral(req, referral);
2756                 talloc_free(ares);
2757                 return ldb_module_done(req, NULL, NULL, ret);
2758         }
2759
2760         if (ret != LDB_SUCCESS) {
2761                 talloc_free(ares);
2762                 return ldb_module_done(ac->req, NULL, NULL, ret);
2763         }
2764
2765         if (ac->seq_num == 0) {
2766                 talloc_free(ares);
2767                 return ldb_module_done(ac->req, NULL, NULL,
2768                                        ldb_error(ldb, ret,
2769                                         "internal error seq_num == 0"));
2770         }
2771         ac->is_urgent = is_urgent;
2772
2773         ret = ldb_build_mod_req(&down_req, ldb, ac,
2774                                 msg,
2775                                 req->controls,
2776                                 ac, replmd_op_callback,
2777                                 req);
2778         LDB_REQ_SET_LOCATION(down_req);
2779         if (ret != LDB_SUCCESS) {
2780                 talloc_free(ac);
2781                 return ret;
2782         }
2783
2784         /* current partition control is needed by "replmd_op_callback" */
2785         if (ldb_request_get_control(req, DSDB_CONTROL_CURRENT_PARTITION_OID) == NULL) {
2786                 ret = ldb_request_add_control(down_req,
2787                                               DSDB_CONTROL_CURRENT_PARTITION_OID,
2788                                               false, NULL);
2789                 if (ret != LDB_SUCCESS) {
2790                         talloc_free(ac);
2791                         return ret;
2792                 }
2793         }
2794
2795         talloc_steal(down_req, msg);
2796
2797         ret = add_time_element(msg, "whenChanged", t);
2798         if (ret != LDB_SUCCESS) {
2799                 talloc_free(ac);
2800                 ldb_operr(ldb);
2801                 return ret;
2802         }
2803
2804         ret = add_uint64_element(ldb, msg, "uSNChanged", ac->seq_num);
2805         if (ret != LDB_SUCCESS) {
2806                 talloc_free(ac);
2807                 ldb_operr(ldb);
2808                 return ret;
2809         }
2810
2811         /* go on with the call chain - do the modify after the rename */
2812         return ldb_next_request(ac->module, down_req);
2813 }
2814
2815 /*
2816  * remove links from objects that point at this object when an object
2817  * is deleted.  We remove it from the NEXT module per MS-DRSR 5.160
2818  * RemoveObj which states that link removal due to the object being
2819  * deleted is NOT an originating update - they just go away!
2820  *
2821  */
2822 static int replmd_delete_remove_link(struct ldb_module *module,
2823                                      const struct dsdb_schema *schema,
2824                                      struct ldb_dn *dn,
2825                                      struct ldb_message_element *el,
2826                                      const struct dsdb_attribute *sa,
2827                                      struct ldb_request *parent)
2828 {
2829         unsigned int i;
2830         TALLOC_CTX *tmp_ctx = talloc_new(module);
2831         struct ldb_context *ldb = ldb_module_get_ctx(module);
2832
2833         for (i=0; i<el->num_values; i++) {
2834                 struct dsdb_dn *dsdb_dn;
2835                 NTSTATUS status;
2836                 int ret;
2837                 struct GUID guid2;
2838                 struct ldb_message *msg;
2839                 const struct dsdb_attribute *target_attr;
2840                 struct ldb_message_element *el2;
2841                 struct ldb_val dn_val;
2842
2843                 if (dsdb_dn_is_deleted_val(&el->values[i])) {
2844                         continue;
2845                 }
2846
2847                 dsdb_dn = dsdb_dn_parse(tmp_ctx, ldb, &el->values[i], sa->syntax->ldap_oid);
2848                 if (!dsdb_dn) {
2849                         talloc_free(tmp_ctx);
2850                         return LDB_ERR_OPERATIONS_ERROR;
2851                 }
2852
2853                 status = dsdb_get_extended_dn_guid(dsdb_dn->dn, &guid2, "GUID");
2854                 if (!NT_STATUS_IS_OK(status)) {
2855                         talloc_free(tmp_ctx);
2856                         return LDB_ERR_OPERATIONS_ERROR;
2857                 }
2858
2859                 /* remove the link */
2860                 msg = ldb_msg_new(tmp_ctx);
2861                 if (!msg) {
2862                         ldb_module_oom(module);
2863                         talloc_free(tmp_ctx);
2864                         return LDB_ERR_OPERATIONS_ERROR;
2865                 }
2866
2867
2868                 msg->dn = dsdb_dn->dn;
2869
2870                 target_attr = dsdb_attribute_by_linkID(schema, sa->linkID ^ 1);
2871                 if (target_attr == NULL) {
2872                         continue;
2873                 }
2874
2875                 ret = ldb_msg_add_empty(msg, target_attr->lDAPDisplayName, LDB_FLAG_MOD_DELETE, &el2);
2876                 if (ret != LDB_SUCCESS) {
2877                         ldb_module_oom(module);
2878                         talloc_free(tmp_ctx);
2879                         return LDB_ERR_OPERATIONS_ERROR;
2880                 }
2881                 dn_val = data_blob_string_const(ldb_dn_get_linearized(dn));
2882                 el2->values = &dn_val;
2883                 el2->num_values = 1;
2884
2885                 ret = dsdb_module_modify(module, msg, DSDB_FLAG_OWN_MODULE, parent);
2886                 if (ret != LDB_SUCCESS) {
2887                         talloc_free(tmp_ctx);
2888                         return ret;
2889                 }
2890         }
2891         talloc_free(tmp_ctx);
2892         return LDB_SUCCESS;
2893 }
2894
2895
2896 /*
2897   handle update of replication meta data for deletion of objects
2898
2899   This also handles the mapping of delete to a rename operation
2900   to allow deletes to be replicated.
2901
2902   It also handles the incoming deleted objects, to ensure they are
2903   fully deleted here.  In that case re_delete is true, and we do not
2904   use this as a signal to change the deleted state, just reinforce it.
2905
2906  */
2907 static int replmd_delete_internals(struct ldb_module *module, struct ldb_request *req, bool re_delete)
2908 {
2909         int ret = LDB_ERR_OTHER;
2910         bool retb, disallow_move_on_delete;
2911         struct ldb_dn *old_dn, *new_dn;
2912         const char *rdn_name;
2913         const struct ldb_val *rdn_value, *new_rdn_value;
2914         struct GUID guid;
2915         struct ldb_context *ldb = ldb_module_get_ctx(module);
2916         const struct dsdb_schema *schema;
2917         struct ldb_message *msg, *old_msg;
2918         struct ldb_message_element *el;
2919         TALLOC_CTX *tmp_ctx;
2920         struct ldb_result *res, *parent_res;
2921         const char *preserved_attrs[] = {
2922                 /* yes, this really is a hard coded list. See MS-ADTS
2923                    section 3.1.1.5.5.1.1 */
2924                 "nTSecurityDescriptor", "attributeID", "attributeSyntax", "dNReferenceUpdate", "dNSHostName",
2925                 "flatName", "governsID", "groupType", "instanceType", "lDAPDisplayName", "legacyExchangeDN",
2926                 "isDeleted", "isRecycled", "lastKnownParent", "msDS-LastKnownRDN", "mS-DS-CreatorSID",
2927                 "mSMQOwnerID", "nCName", "objectClass", "distinguishedName", "objectGUID", "objectSid",
2928                 "oMSyntax", "proxiedObjectName", "name", "replPropertyMetaData", "sAMAccountName",
2929                 "securityIdentifier", "sIDHistory", "subClassOf", "systemFlags", "trustPartner", "trustDirection",
2930                 "trustType", "trustAttributes", "userAccountControl", "uSNChanged", "uSNCreated", "whenCreated",
2931                 "whenChanged", NULL};
2932         unsigned int i, el_count = 0;
2933         enum deletion_state deletion_state, next_deletion_state;
2934
2935         if (ldb_dn_is_special(req->op.del.dn)) {
2936                 return ldb_next_request(module, req);
2937         }
2938
2939         tmp_ctx = talloc_new(ldb);
2940         if (!tmp_ctx) {
2941                 ldb_oom(ldb);
2942                 return LDB_ERR_OPERATIONS_ERROR;
2943         }
2944
2945         schema = dsdb_get_schema(ldb, tmp_ctx);
2946         if (!schema) {
2947                 talloc_free(tmp_ctx);
2948                 return LDB_ERR_OPERATIONS_ERROR;
2949         }
2950
2951         old_dn = ldb_dn_copy(tmp_ctx, req->op.del.dn);
2952
2953         /* we need the complete msg off disk, so we can work out which
2954            attributes need to be removed */
2955         ret = dsdb_module_search_dn(module, tmp_ctx, &res, old_dn, NULL,
2956                                     DSDB_FLAG_NEXT_MODULE |
2957                                     DSDB_SEARCH_SHOW_RECYCLED |
2958                                     DSDB_SEARCH_REVEAL_INTERNALS |
2959                                     DSDB_SEARCH_SHOW_DN_IN_STORAGE_FORMAT, req);
2960         if (ret != LDB_SUCCESS) {
2961                 ldb_asprintf_errstring(ldb_module_get_ctx(module),
2962                                        "repmd_delete: Failed to %s %s, because we failed to find it: %s",
2963                                        re_delete ? "re-delete" : "delete",
2964                                        ldb_dn_get_linearized(old_dn),
2965                                        ldb_errstring(ldb_module_get_ctx(module)));
2966                 talloc_free(tmp_ctx);
2967                 return ret;
2968         }
2969         old_msg = res->msgs[0];
2970
2971         replmd_deletion_state(module, old_msg,
2972                               &deletion_state,
2973                               &next_deletion_state);
2974
2975         /* This supports us noticing an incoming isDeleted and acting on it */
2976         if (re_delete) {
2977                 SMB_ASSERT(deletion_state > OBJECT_NOT_DELETED);
2978                 next_deletion_state = deletion_state;
2979         }
2980
2981         if (next_deletion_state == OBJECT_REMOVED) {
2982                 struct auth_session_info *session_info =
2983                                 (struct auth_session_info *)ldb_get_opaque(ldb, "sessionInfo");
2984                 if (security_session_user_level(session_info, NULL) != SECURITY_SYSTEM) {
2985                         ldb_asprintf_errstring(ldb, "Refusing to delete deleted object %s",
2986                                         ldb_dn_get_linearized(old_msg->dn));
2987                         return LDB_ERR_UNWILLING_TO_PERFORM;
2988                 }
2989
2990                 /* it is already deleted - really remove it this time */
2991                 talloc_free(tmp_ctx);
2992                 return ldb_next_request(module, req);
2993         }
2994
2995         rdn_name = ldb_dn_get_rdn_name(old_dn);
2996         rdn_value = ldb_dn_get_rdn_val(old_dn);
2997         if ((rdn_name == NULL) || (rdn_value == NULL)) {
2998                 talloc_free(tmp_ctx);
2999                 return ldb_operr(ldb);
3000         }
3001
3002         msg = ldb_msg_new(tmp_ctx);
3003         if (msg == NULL) {
3004                 ldb_module_oom(module);
3005                 talloc_free(tmp_ctx);
3006                 return LDB_ERR_OPERATIONS_ERROR;
3007         }
3008
3009         msg->dn = old_dn;
3010
3011         /* consider the SYSTEM_FLAG_DISALLOW_MOVE_ON_DELETE flag */
3012         disallow_move_on_delete =
3013                 (ldb_msg_find_attr_as_int(old_msg, "systemFlags", 0)
3014                  & SYSTEM_FLAG_DISALLOW_MOVE_ON_DELETE);
3015
3016         /* work out where we will be renaming this object to */
3017         if (!disallow_move_on_delete) {
3018                 struct ldb_dn *deleted_objects_dn;
3019                 ret = dsdb_get_deleted_objects_dn(ldb, tmp_ctx, old_dn,
3020                                                   &deleted_objects_dn);
3021
3022                 /*
3023                  * We should not move objects if we can't find the
3024                  * deleted objects DN.  Not moving (or otherwise
3025                  * harming) the Deleted Objects DN itself is handled
3026                  * in the caller.
3027                  */
3028                 if (re_delete && (ret != LDB_SUCCESS)) {
3029                         new_dn = ldb_dn_get_parent(tmp_ctx, old_dn);
3030                         if (new_dn == NULL) {
3031                                 ldb_module_oom(module);
3032                                 talloc_free(tmp_ctx);
3033                                 return LDB_ERR_OPERATIONS_ERROR;
3034                         }
3035                 } else if (ret != LDB_SUCCESS) {
3036                         /* this is probably an attempted delete on a partition
3037                          * that doesn't allow delete operations, such as the
3038                          * schema partition */
3039                         ldb_asprintf_errstring(ldb, "No Deleted Objects container for DN %s",
3040                                                ldb_dn_get_linearized(old_dn));
3041                         talloc_free(tmp_ctx);
3042                         return LDB_ERR_UNWILLING_TO_PERFORM;
3043                 } else {
3044                         new_dn = deleted_objects_dn;
3045                 }
3046         } else {
3047                 new_dn = ldb_dn_get_parent(tmp_ctx, old_dn);
3048                 if (new_dn == NULL) {
3049                         ldb_module_oom(module);
3050                         talloc_free(tmp_ctx);
3051                         return LDB_ERR_OPERATIONS_ERROR;
3052                 }
3053         }
3054
3055         if (deletion_state == OBJECT_NOT_DELETED) {
3056                 /* get the objects GUID from the search we just did */
3057                 guid = samdb_result_guid(old_msg, "objectGUID");
3058
3059                 /* Add a formatted child */
3060                 retb = ldb_dn_add_child_fmt(new_dn, "%s=%s\\0ADEL:%s",
3061                                             rdn_name,
3062                                             ldb_dn_escape_value(tmp_ctx, *rdn_value),
3063                                             GUID_string(tmp_ctx, &guid));
3064                 if (!retb) {
3065                         DEBUG(0,(__location__ ": Unable to add a formatted child to dn: %s",
3066                                  ldb_dn_get_linearized(new_dn)));
3067                         talloc_free(tmp_ctx);
3068                         return LDB_ERR_OPERATIONS_ERROR;
3069                 }
3070
3071                 ret = ldb_msg_add_string(msg, "isDeleted", "TRUE");
3072                 if (ret != LDB_SUCCESS) {
3073                         DEBUG(0,(__location__ ": Failed to add isDeleted string to the msg\n"));
3074                         ldb_module_oom(module);
3075                         talloc_free(tmp_ctx);
3076                         return ret;
3077                 }
3078                 msg->elements[el_count++].flags = LDB_FLAG_MOD_REPLACE;
3079         } else {
3080                 /*
3081                  * No matter what has happened with other renames etc, try again to
3082                  * get this to be under the deleted DN. See MS-DRSR 5.160 RemoveObj
3083                  */
3084
3085                 struct ldb_dn *rdn = ldb_dn_copy(tmp_ctx, old_dn);
3086                 retb = ldb_dn_remove_base_components(rdn, ldb_dn_get_comp_num(rdn) - 1);
3087                 if (!retb) {
3088                         DEBUG(0,(__location__ ": Unable to add a prepare rdn of %s",
3089                                  ldb_dn_get_linearized(rdn)));
3090                         talloc_free(tmp_ctx);
3091                         return LDB_ERR_OPERATIONS_ERROR;
3092                 }
3093                 SMB_ASSERT(ldb_dn_get_comp_num(rdn) == 1);
3094
3095                 retb = ldb_dn_add_child(new_dn, rdn);
3096                 if (!retb) {
3097                         DEBUG(0,(__location__ ": Unable to add rdn %s to base dn: %s",
3098                                  ldb_dn_get_linearized(rdn),
3099                                  ldb_dn_get_linearized(new_dn)));
3100                         talloc_free(tmp_ctx);
3101                         return LDB_ERR_OPERATIONS_ERROR;
3102                 }
3103         }
3104
3105         /*
3106           now we need to modify the object in the following ways:
3107
3108           - add isDeleted=TRUE
3109           - update rDN and name, with new rDN
3110           - remove linked attributes
3111           - remove objectCategory and sAMAccountType
3112           - remove attribs not on the preserved list
3113              - preserved if in above list, or is rDN
3114           - remove all linked attribs from this object
3115           - remove all links from other objects to this object
3116           - add lastKnownParent
3117           - update replPropertyMetaData?
3118
3119           see MS-ADTS "Tombstone Requirements" section 3.1.1.5.5.1.1
3120          */
3121
3122         if (deletion_state == OBJECT_NOT_DELETED) {
3123                 /* we need the storage form of the parent GUID */
3124                 ret = dsdb_module_search_dn(module, tmp_ctx, &parent_res,
3125                                             ldb_dn_get_parent(tmp_ctx, old_dn), NULL,
3126                                             DSDB_FLAG_NEXT_MODULE |
3127                                             DSDB_SEARCH_SHOW_DN_IN_STORAGE_FORMAT |
3128                                             DSDB_SEARCH_REVEAL_INTERNALS|
3129                                             DSDB_SEARCH_SHOW_RECYCLED, req);
3130                 if (ret != LDB_SUCCESS) {
3131                         ldb_asprintf_errstring(ldb_module_get_ctx(module),
3132                                                "repmd_delete: Failed to %s %s, because we failed to find it's parent (%s): %s",
3133                                                re_delete ? "re-delete" : "delete",
3134                                                ldb_dn_get_linearized(old_dn),
3135                                                ldb_dn_get_linearized(ldb_dn_get_parent(tmp_ctx, old_dn)),
3136                                                ldb_errstring(ldb_module_get_ctx(module)));
3137                         talloc_free(tmp_ctx);
3138                         return ret;
3139                 }
3140
3141                 ret = ldb_msg_add_steal_string(msg, "lastKnownParent",
3142                                                    ldb_dn_get_extended_linearized(tmp_ctx, parent_res->msgs[0]->dn, 1));
3143                 if (ret != LDB_SUCCESS) {
3144                         DEBUG(0,(__location__ ": Failed to add lastKnownParent string to the msg\n"));
3145                         ldb_module_oom(module);
3146                         talloc_free(tmp_ctx);
3147                         return ret;
3148                 }
3149                 msg->elements[el_count++].flags = LDB_FLAG_MOD_REPLACE;
3150
3151                 if (next_deletion_state == OBJECT_DELETED) {
3152                         ret = ldb_msg_add_value(msg, "msDS-LastKnownRDN", rdn_value, NULL);
3153                         if (ret != LDB_SUCCESS) {
3154                                 DEBUG(0,(__location__ ": Failed to add msDS-LastKnownRDN string to the msg\n"));
3155                                 ldb_module_oom(module);
3156                                 talloc_free(tmp_ctx);
3157                                 return ret;
3158                         }
3159                         msg->elements[el_count++].flags = LDB_FLAG_MOD_ADD;
3160                 }
3161         }
3162
3163         switch (next_deletion_state) {
3164
3165         case OBJECT_RECYCLED:
3166         case OBJECT_TOMBSTONE:
3167
3168                 /*
3169                  * MS-ADTS 3.1.1.5.5.1.1 Tombstone Requirements
3170                  * describes what must be removed from a tombstone
3171                  * object
3172                  *
3173                  * MS-ADTS 3.1.1.5.5.1.3 Recycled-Object Requirements
3174                  * describes what must be removed from a recycled
3175                  * object
3176                  *
3177                  */
3178
3179                 /*
3180                  * we also mark it as recycled, meaning this object can't be
3181                  * recovered (we are stripping its attributes).
3182                  * This is done only if we have this schema object of course ...
3183                  * This behavior is identical to the one of Windows 2008R2 which
3184                  * always set the isRecycled attribute, even if the recycle-bin is
3185                  * not activated and what ever the forest level is.
3186                  */
3187                 if (dsdb_attribute_by_lDAPDisplayName(schema, "isRecycled") != NULL) {
3188                         ret = ldb_msg_add_string(msg, "isRecycled", "TRUE");
3189                         if (ret != LDB_SUCCESS) {
3190                                 DEBUG(0,(__location__ ": Failed to add isRecycled string to the msg\n"));
3191                                 ldb_module_oom(module);
3192                                 talloc_free(tmp_ctx);
3193                                 return ret;
3194                         }
3195                         msg->elements[el_count++].flags = LDB_FLAG_MOD_REPLACE;
3196                 }
3197
3198                 /* work out which of the old attributes we will be removing */
3199                 for (i=0; i<old_msg->num_elements; i++) {
3200                         const struct dsdb_attribute *sa;
3201                         el = &old_msg->elements[i];
3202                         sa = dsdb_attribute_by_lDAPDisplayName(schema, el->name);
3203                         if (!sa) {
3204                                 talloc_free(tmp_ctx);
3205                                 return LDB_ERR_OPERATIONS_ERROR;
3206                         }
3207                         if (ldb_attr_cmp(el->name, rdn_name) == 0) {
3208                                 /* don't remove the rDN */
3209                                 continue;
3210                         }
3211                         if (sa->linkID && (sa->linkID & 1)) {
3212                                 /*
3213                                   we have a backlink in this object
3214                                   that needs to be removed. We're not
3215                                   allowed to remove it directly
3216                                   however, so we instead setup a
3217                                   modify to delete the corresponding
3218                                   forward link
3219                                  */
3220                                 ret = replmd_delete_remove_link(module, schema, old_dn, el, sa, req);
3221                                 if (ret != LDB_SUCCESS) {
3222                                         talloc_free(tmp_ctx);
3223                                         return LDB_ERR_OPERATIONS_ERROR;
3224                                 }
3225                                 /* now we continue, which means we
3226                                    won't remove this backlink
3227                                    directly
3228                                 */
3229                                 continue;
3230                         }
3231                         if (!sa->linkID) {
3232                                 if (ldb_attr_in_list(preserved_attrs, el->name)) {
3233                                         continue;
3234                                 }
3235                                 if (sa->searchFlags & SEARCH_FLAG_PRESERVEONDELETE) {
3236                                         continue;
3237                                 }
3238                         }
3239                         ret = ldb_msg_add_empty(msg, el->name, LDB_FLAG_MOD_DELETE, &el);
3240                         if (ret != LDB_SUCCESS) {
3241                                 talloc_free(tmp_ctx);
3242                                 ldb_module_oom(module);
3243                                 return ret;
3244                         }
3245                 }
3246
3247                 /* Duplicate with the below - we remove the
3248                  * samAccountType as an originating update, in case it
3249                  * somehow came back.  The objectCategory will have
3250                  * gone in the above */
3251                 ret = ldb_msg_add_empty(msg, "sAMAccountType", LDB_FLAG_MOD_REPLACE, NULL);
3252                 if (ret != LDB_SUCCESS) {
3253                         talloc_free(tmp_ctx);
3254                         ldb_module_oom(module);
3255                         return ret;
3256                 }
3257
3258                 break;
3259
3260         case OBJECT_DELETED:
3261                 /*
3262                  * MS-ADTS 3.1.1.5.5.1.2 Deleted-Object Requirements
3263                  * describes what must be removed from a deleted
3264                  * object
3265                  */
3266
3267                 ret = ldb_msg_add_empty(msg, "objectCategory", LDB_FLAG_MOD_REPLACE, NULL);
3268                 if (ret != LDB_SUCCESS) {
3269                         talloc_free(tmp_ctx);
3270                         ldb_module_oom(module);
3271                         return ret;
3272                 }
3273
3274                 ret = ldb_msg_add_empty(msg, "sAMAccountType", LDB_FLAG_MOD_REPLACE, NULL);
3275                 if (ret != LDB_SUCCESS) {
3276                         talloc_free(tmp_ctx);
3277                         ldb_module_oom(module);
3278                         return ret;
3279                 }
3280
3281                 break;
3282
3283         default:
3284                 break;
3285         }
3286
3287         if (deletion_state == OBJECT_NOT_DELETED) {
3288                 const struct dsdb_attribute *sa;
3289
3290                 /* work out what the new rdn value is, for updating the
3291                    rDN and name fields */
3292                 new_rdn_value = ldb_dn_get_rdn_val(new_dn);
3293                 if (new_rdn_value == NULL) {
3294                         talloc_free(tmp_ctx);
3295                         return ldb_operr(ldb);
3296                 }
3297
3298                 sa = dsdb_attribute_by_lDAPDisplayName(schema, rdn_name);
3299                 if (!sa) {
3300                         talloc_free(tmp_ctx);
3301                         return LDB_ERR_OPERATIONS_ERROR;
3302                 }
3303
3304                 ret = ldb_msg_add_value(msg, sa->lDAPDisplayName, new_rdn_value,
3305                                         &el);
3306                 if (ret != LDB_SUCCESS) {
3307                         talloc_free(tmp_ctx);
3308                         return ret;
3309                 }
3310                 el->flags = LDB_FLAG_MOD_REPLACE;
3311
3312                 el = ldb_msg_find_element(old_msg, "name");
3313                 if (el) {
3314                         ret = ldb_msg_add_value(msg, "name", new_rdn_value, &el);
3315                         if (ret != LDB_SUCCESS) {
3316                                 talloc_free(tmp_ctx);
3317                                 return ret;
3318                         }
3319                         el->flags = LDB_FLAG_MOD_REPLACE;
3320                 }
3321         }
3322
3323         /*
3324          * TODO: Per MS-DRSR 5.160 RemoveObj we should remove links directly, not as an originating update!
3325          *
3326          */
3327
3328         ret = dsdb_module_modify(module, msg, DSDB_FLAG_OWN_MODULE, req);
3329         if (ret != LDB_SUCCESS) {
3330                 ldb_asprintf_errstring(ldb, "replmd_delete: Failed to modify object %s in delete - %s",
3331                                        ldb_dn_get_linearized(old_dn), ldb_errstring(ldb));
3332                 talloc_free(tmp_ctx);
3333                 return ret;
3334         }
3335
3336         /*
3337          * No matter what has happned with other renames, try again to
3338          * get this to be under the deleted DN.
3339          */
3340         if (strcmp(ldb_dn_get_linearized(old_dn), ldb_dn_get_linearized(new_dn)) != 0) {
3341                 /* now rename onto the new DN */
3342                 ret = dsdb_module_rename(module, old_dn, new_dn, DSDB_FLAG_NEXT_MODULE, req);
3343                 if (ret != LDB_SUCCESS){
3344                         DEBUG(0,(__location__ ": Failed to rename object from '%s' to '%s' - %s\n",
3345                                  ldb_dn_get_linearized(old_dn),
3346                                  ldb_dn_get_linearized(new_dn),
3347                                  ldb_errstring(ldb)));
3348                         talloc_free(tmp_ctx);
3349                         return ret;
3350                 }
3351         }
3352
3353         talloc_free(tmp_ctx);
3354
3355         return ldb_module_done(req, NULL, NULL, LDB_SUCCESS);
3356 }
3357
3358 static int replmd_delete(struct ldb_module *module, struct ldb_request *req)
3359 {
3360         return replmd_delete_internals(module, req, false);
3361 }
3362
3363
3364 static int replmd_replicated_request_error(struct replmd_replicated_request *ar, int ret)
3365 {
3366         return ret;
3367 }
3368
3369 static int replmd_replicated_request_werror(struct replmd_replicated_request *ar, WERROR status)
3370 {
3371         int ret = LDB_ERR_OTHER;
3372         /* TODO: do some error mapping */
3373         return ret;
3374 }
3375
3376
3377 static struct replPropertyMetaData1 *
3378 replmd_replPropertyMetaData1_find_attid(struct replPropertyMetaDataBlob *md_blob,
3379                                         enum drsuapi_DsAttributeId attid)
3380 {
3381         uint32_t i;
3382         struct replPropertyMetaDataCtr1 *rpmd_ctr = &md_blob->ctr.ctr1;
3383
3384         for (i = 0; i < rpmd_ctr->count; i++) {
3385                 if (rpmd_ctr->array[i].attid == attid) {
3386                         return &rpmd_ctr->array[i];
3387                 }
3388         }
3389         return NULL;
3390 }
3391
3392
3393 /*
3394    return true if an update is newer than an existing entry
3395    see section 5.11 of MS-ADTS
3396 */
3397 static bool replmd_update_is_newer(const struct GUID *current_invocation_id,
3398                                    const struct GUID *update_invocation_id,
3399                                    uint32_t current_version,
3400                                    uint32_t update_version,
3401                                    NTTIME current_change_time,
3402                                    NTTIME update_change_time)
3403 {
3404         if (update_version != current_version) {
3405                 return update_version > current_version;
3406         }
3407         if (update_change_time != current_change_time) {
3408                 return update_change_time > current_change_time;
3409         }
3410         return GUID_compare(update_invocation_id, current_invocation_id) > 0;
3411 }
3412
3413 static bool replmd_replPropertyMetaData1_is_newer(struct replPropertyMetaData1 *cur_m,
3414                                                   struct replPropertyMetaData1 *new_m)
3415 {
3416         return replmd_update_is_newer(&cur_m->originating_invocation_id,
3417                                       &new_m->originating_invocation_id,
3418                                       cur_m->version,
3419                                       new_m->version,
3420                                       cur_m->originating_change_time,
3421                                       new_m->originating_change_time);
3422 }
3423
3424
3425 /*
3426   form a conflict DN
3427  */
3428 static struct ldb_dn *replmd_conflict_dn(TALLOC_CTX *mem_ctx, struct ldb_dn *dn, struct GUID *guid)
3429 {
3430         const struct ldb_val *rdn_val;
3431         const char *rdn_name;
3432         struct ldb_dn *new_dn;
3433
3434         rdn_val = ldb_dn_get_rdn_val(dn);
3435         rdn_name = ldb_dn_get_rdn_name(dn);
3436         if (!rdn_val || !rdn_name) {
3437                 return NULL;
3438         }
3439
3440         new_dn = ldb_dn_copy(mem_ctx, dn);
3441         if (!new_dn) {
3442                 return NULL;
3443         }
3444
3445         if (!ldb_dn_remove_child_components(new_dn, 1)) {
3446                 return NULL;
3447         }
3448
3449         if (!ldb_dn_add_child_fmt(new_dn, "%s=%s\\0ACNF:%s",
3450                                   rdn_name,
3451                                   ldb_dn_escape_value(new_dn, *rdn_val),
3452                                   GUID_string(new_dn, guid))) {
3453                 return NULL;
3454         }
3455
3456         return new_dn;
3457 }
3458
3459
3460 /*
3461   perform a modify operation which sets the rDN and name attributes to
3462   their current values. This has the effect of changing these
3463   attributes to have been last updated by the current DC. This is
3464   needed to ensure that renames performed as part of conflict
3465   resolution are propogated to other DCs
3466  */
3467 static int replmd_name_modify(struct replmd_replicated_request *ar,
3468                               struct ldb_request *req, struct ldb_dn *dn)
3469 {
3470         struct ldb_message *msg;
3471         const char *rdn_name;
3472         const struct ldb_val *rdn_val;
3473         const struct dsdb_attribute *rdn_attr;
3474         int ret;
3475
3476         msg = ldb_msg_new(req);
3477         if (msg == NULL) {
3478                 goto failed;
3479         }
3480         msg->dn = dn;
3481
3482         rdn_name = ldb_dn_get_rdn_name(dn);
3483         if (rdn_name == NULL) {
3484                 goto failed;
3485         }
3486
3487         /* normalize the rdn attribute name */
3488         rdn_attr = dsdb_attribute_by_lDAPDisplayName(ar->schema, rdn_name);
3489         if (rdn_attr == NULL) {
3490                 goto failed;
3491         }
3492         rdn_name = rdn_attr->lDAPDisplayName;
3493
3494         rdn_val = ldb_dn_get_rdn_val(dn);
3495         if (rdn_val == NULL) {
3496                 goto failed;
3497         }
3498
3499         if (ldb_msg_add_empty(msg, rdn_name, LDB_FLAG_MOD_REPLACE, NULL) != 0) {
3500                 goto failed;
3501         }
3502         if (ldb_msg_add_value(msg, rdn_name, rdn_val, NULL) != 0) {
3503                 goto failed;
3504         }
3505         if (ldb_msg_add_empty(msg, "name", LDB_FLAG_MOD_REPLACE, NULL) != 0) {
3506                 goto failed;
3507         }
3508         if (ldb_msg_add_value(msg, "name", rdn_val, NULL) != 0) {
3509                 goto failed;
3510         }
3511
3512         ret = dsdb_module_modify(ar->module, msg, DSDB_FLAG_OWN_MODULE, req);
3513         if (ret != LDB_SUCCESS) {
3514                 DEBUG(0,(__location__ ": Failed to modify rDN/name of conflict DN '%s' - %s",
3515                          ldb_dn_get_linearized(dn),
3516                          ldb_errstring(ldb_module_get_ctx(ar->module))));
3517                 return ret;
3518         }
3519
3520         talloc_free(msg);
3521
3522         return LDB_SUCCESS;
3523
3524 failed:
3525         talloc_free(msg);
3526         DEBUG(0,(__location__ ": Failed to setup modify rDN/name of conflict DN '%s'",
3527                  ldb_dn_get_linearized(dn)));
3528         return LDB_ERR_OPERATIONS_ERROR;
3529 }
3530
3531
3532 /*
3533   callback for conflict DN handling where we have renamed the incoming
3534   record. After renaming it, we need to ensure the change of name and
3535   rDN for the incoming record is seen as an originating update by this DC.
3536
3537   This also handles updating lastKnownParent for entries sent to lostAndFound
3538  */
3539 static int replmd_op_name_modify_callback(struct ldb_request *req, struct ldb_reply *ares)
3540 {
3541         struct replmd_replicated_request *ar =
3542                 talloc_get_type_abort(req->context, struct replmd_replicated_request);
3543         struct ldb_dn *conflict_dn;
3544         int ret;
3545
3546         if (ares->error != LDB_SUCCESS) {
3547                 /* call the normal callback for everything except success */
3548                 return replmd_op_callback(req, ares);
3549         }
3550
3551         switch (req->operation) {
3552         case LDB_ADD:
3553                 conflict_dn = req->op.add.message->dn;
3554                 break;
3555         case LDB_MODIFY:
3556                 conflict_dn = req->op.mod.message->dn;
3557                 break;
3558         default:
3559                 smb_panic("replmd_op_name_modify_callback called in unknown circumstances");
3560         }
3561
3562         /* perform a modify of the rDN and name of the record */
3563         ret = replmd_name_modify(ar, req, conflict_dn);
3564         if (ret != LDB_SUCCESS) {
3565                 ares->error = ret;
3566                 return replmd_op_callback(req, ares);
3567         }
3568
3569         if (ar->objs->objects[ar->index_current].last_known_parent) {
3570                 struct ldb_message *msg = ldb_msg_new(req);
3571                 if (msg == NULL) {
3572                         ldb_module_oom(ar->module);
3573                         return LDB_ERR_OPERATIONS_ERROR;
3574                 }
3575
3576                 msg->dn = req->op.add.message->dn;
3577
3578                 ret = ldb_msg_add_steal_string(msg, "lastKnownParent",
3579                                                ldb_dn_get_extended_linearized(msg, ar->objs->objects[ar->index_current].last_known_parent, 1));
3580                 if (ret != LDB_SUCCESS) {
3581                         DEBUG(0,(__location__ ": Failed to add lastKnownParent string to the msg\n"));
3582                         ldb_module_oom(ar->module);
3583                         return ret;
3584                 }
3585                 msg->elements[0].flags = LDB_FLAG_MOD_REPLACE;
3586
3587                 ret = dsdb_module_modify(ar->module, msg, DSDB_FLAG_OWN_MODULE, req);
3588                 if (ret != LDB_SUCCESS) {
3589                         DEBUG(0,(__location__ ": Failed to modify lastKnownParent of lostAndFound DN '%s' - %s",
3590                                  ldb_dn_get_linearized(msg->dn),
3591                                  ldb_errstring(ldb_module_get_ctx(ar->module))));
3592                         return ret;
3593                 }
3594                 TALLOC_FREE(msg);
3595         }
3596
3597         return replmd_op_callback(req, ares);
3598 }
3599
3600 /*
3601   callback for replmd_replicated_apply_add() and replmd_replicated_handle_rename()
3602   This copes with the creation of conflict records in the case where
3603   the DN exists, but with a different objectGUID
3604  */
3605 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))
3606 {
3607         struct ldb_dn *conflict_dn;
3608         struct replmd_replicated_request *ar =
3609                 talloc_get_type_abort(req->context, struct replmd_replicated_request);
3610         struct ldb_result *res;
3611         const char *attrs[] = { "replPropertyMetaData", "objectGUID", NULL };
3612         int ret;
3613         const struct ldb_val *omd_value;
3614         struct replPropertyMetaDataBlob omd, *rmd;
3615         enum ndr_err_code ndr_err;
3616         bool rename_incoming_record, rodc;
3617         struct replPropertyMetaData1 *rmd_name, *omd_name;
3618         struct ldb_message *msg;
3619
3620         req->callback = callback;
3621
3622         if (ares->error != LDB_ERR_ENTRY_ALREADY_EXISTS) {
3623                 /* call the normal callback for everything except
3624                    conflicts */
3625                 return ldb_module_done(req, ares->controls, ares->response, ares->error);
3626         }
3627
3628         ret = samdb_rodc(ldb_module_get_ctx(ar->module), &rodc);
3629         if (ret != LDB_SUCCESS) {
3630                 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)));
3631                 return ldb_module_done(req, ares->controls, ares->response, LDB_ERR_OPERATIONS_ERROR);
3632         }
3633         /*
3634          * we have a conflict, and need to decide if we will keep the
3635          * new record or the old record
3636          */
3637
3638         msg = ar->objs->objects[ar->index_current].msg;
3639
3640         switch (req->operation) {
3641         case LDB_ADD:
3642                 conflict_dn = msg->dn;
3643                 break;
3644         case LDB_RENAME:
3645                 conflict_dn = req->op.rename.newdn;
3646                 break;
3647         default:
3648                 return ldb_module_done(req, ares->controls, ares->response, ldb_module_operr(ar->module));
3649         }
3650
3651         if (rodc) {
3652                 /*
3653                  * We are on an RODC, or were a GC for this
3654                  * partition, so we have to fail this until
3655                  * someone who owns the partition sorts it
3656                  * out 
3657                  */
3658                 ldb_asprintf_errstring(ldb_module_get_ctx(ar->module), 
3659                                        "Conflict adding object '%s' from incoming replication as we are read only for the partition.  \n"
3660                                        " - We must fail the operation until a master for this partition resolves the conflict",
3661                                        ldb_dn_get_linearized(conflict_dn));
3662                 goto failed;
3663         }
3664
3665         /*
3666          * first we need the replPropertyMetaData attribute from the
3667          * old record
3668          */
3669         ret = dsdb_module_search_dn(ar->module, req, &res, conflict_dn,
3670                                     attrs,
3671                                     DSDB_FLAG_NEXT_MODULE |
3672                                     DSDB_SEARCH_SHOW_DELETED |
3673                                     DSDB_SEARCH_SHOW_RECYCLED, req);
3674         if (ret != LDB_SUCCESS) {
3675                 DEBUG(0,(__location__ ": Unable to find object for conflicting record '%s'\n",
3676                          ldb_dn_get_linearized(conflict_dn)));
3677                 goto failed;
3678         }
3679
3680         omd_value = ldb_msg_find_ldb_val(res->msgs[0], "replPropertyMetaData");
3681         if (omd_value == NULL) {
3682                 DEBUG(0,(__location__ ": Unable to find replPropertyMetaData for conflicting record '%s'\n",
3683                          ldb_dn_get_linearized(conflict_dn)));
3684                 goto failed;
3685         }
3686
3687         ndr_err = ndr_pull_struct_blob(omd_value, res->msgs[0], &omd,
3688                                        (ndr_pull_flags_fn_t)ndr_pull_replPropertyMetaDataBlob);
3689         if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
3690                 DEBUG(0,(__location__ ": Failed to parse old replPropertyMetaData for %s\n",
3691                          ldb_dn_get_linearized(conflict_dn)));
3692                 goto failed;
3693         }
3694
3695         rmd = ar->objs->objects[ar->index_current].meta_data;
3696
3697         /* we decide which is newer based on the RPMD on the name
3698            attribute.  See [MS-DRSR] ResolveNameConflict */
3699         rmd_name = replmd_replPropertyMetaData1_find_attid(rmd, DRSUAPI_ATTID_name);
3700         omd_name = replmd_replPropertyMetaData1_find_attid(&omd, DRSUAPI_ATTID_name);
3701         if (!rmd_name || !omd_name) {
3702                 DEBUG(0,(__location__ ": Failed to find name attribute in replPropertyMetaData for %s\n",
3703                          ldb_dn_get_linearized(conflict_dn)));
3704                 goto failed;
3705         }
3706
3707         rename_incoming_record = !(ar->objs->dsdb_repl_flags & DSDB_REPL_FLAG_PRIORITISE_INCOMING) &&
3708                 !replmd_replPropertyMetaData1_is_newer(omd_name, rmd_name);
3709
3710         if (rename_incoming_record) {
3711                 struct GUID guid;
3712                 struct ldb_dn *new_dn;
3713
3714                 /*
3715                  * We want to run the original callback here, which
3716                  * will return LDB_ERR_ENTRY_ALREADY_EXISTS to the
3717                  * caller, which will in turn know to rename the
3718                  * incoming record.  The error string is set in case
3719                  * this isn't handled properly at some point in the
3720                  * future.
3721                  */
3722                 if (req->operation == LDB_RENAME) {
3723                         ldb_asprintf_errstring(ldb_module_get_ctx(ar->module),
3724                                                "Unable to handle incoming renames where this would "
3725                                                "create a conflict. Incoming record is %s (caller to handle)\n",
3726                                                ldb_dn_get_extended_linearized(req, conflict_dn, 1));
3727
3728                         goto failed;
3729                 }
3730
3731                 guid = samdb_result_guid(msg, "objectGUID");
3732                 if (GUID_all_zero(&guid)) {
3733                         DEBUG(0,(__location__ ": Failed to find objectGUID for conflicting incoming record %s\n",
3734                                  ldb_dn_get_linearized(conflict_dn)));
3735                         goto failed;
3736                 }
3737                 new_dn = replmd_conflict_dn(req, conflict_dn, &guid);
3738                 if (new_dn == NULL) {
3739                         DEBUG(0,(__location__ ": Failed to form conflict DN for %s\n",
3740                                  ldb_dn_get_linearized(conflict_dn)));
3741                         goto failed;
3742                 }
3743
3744                 DEBUG(2,(__location__ ": Resolving conflict record via incoming rename '%s' -> '%s'\n",
3745                          ldb_dn_get_linearized(conflict_dn), ldb_dn_get_linearized(new_dn)));
3746
3747                 /* re-submit the request, but with a different
3748                    callback, so we don't loop forever. */
3749                 msg->dn = new_dn;
3750                 req->callback = replmd_op_name_modify_callback;
3751
3752                 return ldb_next_request(ar->module, req);
3753         } else {
3754                 /* we are renaming the existing record */
3755                 struct GUID guid;
3756                 struct ldb_dn *new_dn;
3757
3758                 guid = samdb_result_guid(res->msgs[0], "objectGUID");
3759                 if (GUID_all_zero(&guid)) {
3760                         DEBUG(0,(__location__ ": Failed to find objectGUID for existing conflict record %s\n",
3761                                  ldb_dn_get_linearized(conflict_dn)));
3762                         goto failed;
3763                 }
3764
3765                 new_dn = replmd_conflict_dn(req, conflict_dn, &guid);
3766                 if (new_dn == NULL) {
3767                         DEBUG(0,(__location__ ": Failed to form conflict DN for %s\n",
3768                                  ldb_dn_get_linearized(conflict_dn)));
3769                         goto failed;
3770                 }
3771
3772                 DEBUG(2,(__location__ ": Resolving conflict record via existing rename '%s' -> '%s'\n",
3773                          ldb_dn_get_linearized(conflict_dn), ldb_dn_get_linearized(new_dn)));
3774
3775                 ret = dsdb_module_rename(ar->module, conflict_dn, new_dn,
3776                                          DSDB_FLAG_OWN_MODULE, req);
3777                 if (ret != LDB_SUCCESS) {
3778                         DEBUG(0,(__location__ ": Failed to rename conflict dn '%s' to '%s' - %s\n",
3779                                  ldb_dn_get_linearized(conflict_dn),
3780                                  ldb_dn_get_linearized(new_dn),
3781                                  ldb_errstring(ldb_module_get_ctx(ar->module))));
3782                         goto failed;
3783                 }
3784
3785                 /*
3786                  * now we need to ensure that the rename is seen as an
3787                  * originating update. We do that with a modify.
3788                  */
3789                 ret = replmd_name_modify(ar, req, new_dn);
3790                 if (ret != LDB_SUCCESS) {
3791                         goto failed;
3792                 }
3793
3794                 return ldb_next_request(ar->module, req);
3795         }
3796
3797 failed:
3798         /* on failure do the original callback. This means replication
3799          * will stop with an error, but there is not much else we can
3800          * do
3801          */
3802         return ldb_module_done(req, ares->controls, ares->response, ares->error);
3803 }
3804
3805 /*
3806   callback for replmd_replicated_apply_add()
3807   This copes with the creation of conflict records in the case where
3808   the DN exists, but with a different objectGUID
3809  */
3810 static int replmd_op_add_callback(struct ldb_request *req, struct ldb_reply *ares)
3811 {
3812         struct replmd_replicated_request *ar =
3813                 talloc_get_type_abort(req->context, struct replmd_replicated_request);
3814
3815         if (ar->objs->objects[ar->index_current].last_known_parent) {
3816                 /* This is like a conflict DN, where we put the object in LostAndFound
3817                    see MS-DRSR 4.1.10.6.10 FindBestParentObject */
3818                 return replmd_op_possible_conflict_callback(req, ares, replmd_op_name_modify_callback);
3819         }
3820
3821         return replmd_op_possible_conflict_callback(req, ares, replmd_op_callback);
3822 }
3823
3824 /*
3825   callback for replmd_replicated_handle_rename()
3826   This copes with the creation of conflict records in the case where
3827   the DN exists, but with a different objectGUID
3828  */
3829 static int replmd_op_rename_callback(struct ldb_request *req, struct ldb_reply *ares)
3830 {
3831         return replmd_op_possible_conflict_callback(req, ares, ldb_modify_default_callback);
3832 }
3833
3834 /*
3835   this is called when a new object comes in over DRS
3836  */
3837 static int replmd_replicated_apply_add(struct replmd_replicated_request *ar)
3838 {
3839         struct ldb_context *ldb;
3840         struct ldb_request *change_req;
3841         enum ndr_err_code ndr_err;
3842         struct ldb_message *msg;
3843         struct replPropertyMetaDataBlob *md;
3844         struct ldb_val md_value;
3845         unsigned int i;
3846         int ret;
3847         bool remote_isDeleted = false;
3848
3849         ldb = ldb_module_get_ctx(ar->module);
3850         msg = ar->objs->objects[ar->index_current].msg;
3851         md = ar->objs->objects[ar->index_current].meta_data;
3852
3853         ret = ldb_sequence_number(ldb, LDB_SEQ_NEXT, &ar->seq_num);
3854         if (ret != LDB_SUCCESS) {
3855                 return replmd_replicated_request_error(ar, ret);
3856         }
3857
3858         ret = ldb_msg_add_value(msg, "objectGUID", &ar->objs->objects[ar->index_current].guid_value, NULL);
3859         if (ret != LDB_SUCCESS) {
3860                 return replmd_replicated_request_error(ar, ret);
3861         }
3862
3863         ret = ldb_msg_add_string(msg, "whenChanged", ar->objs->objects[ar->index_current].when_changed);
3864         if (ret != LDB_SUCCESS) {
3865                 return replmd_replicated_request_error(ar, ret);
3866         }
3867
3868         ret = samdb_msg_add_uint64(ldb, msg, msg, "uSNCreated", ar->seq_num);
3869         if (ret != LDB_SUCCESS) {
3870                 return replmd_replicated_request_error(ar, ret);
3871         }
3872
3873         ret = samdb_msg_add_uint64(ldb, msg, msg, "uSNChanged", ar->seq_num);
3874         if (ret != LDB_SUCCESS) {
3875                 return replmd_replicated_request_error(ar, ret);
3876         }
3877
3878         /* remove any message elements that have zero values */
3879         for (i=0; i<msg->num_elements; i++) {
3880                 struct ldb_message_element *el = &msg->elements[i];
3881
3882                 if (el->num_values == 0) {
3883                         DEBUG(4,(__location__ ": Removing attribute %s with num_values==0\n",
3884                                  el->name));
3885                         memmove(el, el+1, sizeof(*el)*(msg->num_elements - (i+1)));
3886                         msg->num_elements--;
3887                         i--;
3888                         continue;
3889                 }
3890         }
3891
3892         remote_isDeleted = ldb_msg_find_attr_as_bool(msg,
3893                                                      "isDeleted", false);
3894
3895         /*
3896          * the meta data array is already sorted by the caller
3897          */
3898         for (i=0; i < md->ctr.ctr1.count; i++) {
3899                 md->ctr.ctr1.array[i].local_usn = ar->seq_num;
3900         }
3901         ndr_err = ndr_push_struct_blob(&md_value, msg, md,
3902                                        (ndr_push_flags_fn_t)ndr_push_replPropertyMetaDataBlob);
3903         if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
3904                 NTSTATUS nt_status = ndr_map_error2ntstatus(ndr_err);
3905                 return replmd_replicated_request_werror(ar, ntstatus_to_werror(nt_status));
3906         }
3907         ret = ldb_msg_add_value(msg, "replPropertyMetaData", &md_value, NULL);
3908         if (ret != LDB_SUCCESS) {
3909                 return replmd_replicated_request_error(ar, ret);
3910         }
3911
3912         replmd_ldb_message_sort(msg, ar->schema);
3913
3914         if (!remote_isDeleted) {
3915                 ret = dsdb_module_schedule_sd_propagation(ar->module,
3916                                                           ar->objs->partition_dn,
3917                                                           msg->dn, true);
3918                 if (ret != LDB_SUCCESS) {
3919                         return replmd_replicated_request_error(ar, ret);
3920                 }
3921         }
3922
3923         ar->isDeleted = remote_isDeleted;
3924
3925         if (DEBUGLVL(4)) {
3926                 char *s = ldb_ldif_message_string(ldb, ar, LDB_CHANGETYPE_ADD, msg);
3927                 DEBUG(4, ("DRS replication add message:\n%s\n", s));
3928                 talloc_free(s);
3929         }
3930
3931         ret = ldb_build_add_req(&change_req,
3932                                 ldb,
3933                                 ar,
3934                                 msg,
3935                                 ar->controls,
3936                                 ar,
3937                                 replmd_op_add_callback,
3938                                 ar->req);
3939         LDB_REQ_SET_LOCATION(change_req);
3940         if (ret != LDB_SUCCESS) return replmd_replicated_request_error(ar, ret);
3941
3942         /* current partition control needed by "repmd_op_callback" */
3943         ret = ldb_request_add_control(change_req,
3944                                       DSDB_CONTROL_CURRENT_PARTITION_OID,
3945                                       false, NULL);
3946         if (ret != LDB_SUCCESS) return replmd_replicated_request_error(ar, ret);
3947
3948         if (ar->objs->dsdb_repl_flags & DSDB_REPL_FLAG_PARTIAL_REPLICA) {
3949                 /* this tells the partition module to make it a
3950                    partial replica if creating an NC */
3951                 ret = ldb_request_add_control(change_req,
3952                                               DSDB_CONTROL_PARTIAL_REPLICA,
3953                                               false, NULL);
3954                 if (ret != LDB_SUCCESS) return replmd_replicated_request_error(ar, ret);
3955         }
3956
3957         return ldb_next_request(ar->module, change_req);
3958 }
3959
3960 static int replmd_replicated_apply_search_for_parent_callback(struct ldb_request *req,
3961                                                               struct ldb_reply *ares)
3962 {
3963         struct replmd_replicated_request *ar = talloc_get_type(req->context,
3964                                                struct replmd_replicated_request);
3965         int ret;
3966
3967         if (!ares) {
3968                 return ldb_module_done(ar->req, NULL, NULL,
3969                                         LDB_ERR_OPERATIONS_ERROR);
3970         }
3971         if (ares->error != LDB_SUCCESS &&
3972             ares->error != LDB_ERR_NO_SUCH_OBJECT) {
3973                 /*
3974                  * TODO: deal with the above error that the parent object doesn't exist
3975                  */
3976
3977                 return ldb_module_done(ar->req, ares->controls,
3978                                         ares->response, ares->error);
3979         }
3980
3981         switch (ares->type) {
3982         case LDB_REPLY_ENTRY:
3983         {
3984                 struct ldb_message *parent_msg = ares->message;
3985                 struct ldb_message *msg = ar->objs->objects[ar->index_current].msg;
3986                 struct ldb_dn *parent_dn;
3987                 int comp_num;
3988
3989                 if (!ldb_msg_check_string_attribute(msg, "isDeleted", "TRUE")
3990                     && ldb_msg_check_string_attribute(parent_msg, "isDeleted", "TRUE")) {
3991                         /* Per MS-DRSR 4.1.10.6.10
3992                          * FindBestParentObject we need to move this
3993                          * new object under a deleted object to
3994                          * lost-and-found */
3995                         struct ldb_dn *nc_root;
3996
3997                         ret = dsdb_find_nc_root(ldb_module_get_ctx(ar->module), msg, msg->dn, &nc_root);
3998                         if (ret == LDB_ERR_NO_SUCH_OBJECT) {
3999                                 ldb_asprintf_errstring(ldb_module_get_ctx(ar->module),
4000                                                        "No suitable NC root found for %s.  "
4001                                                        "We need to move this object because parent object %s "
4002                                                        "is deleted, but this object is not.",
4003                                                        ldb_dn_get_linearized(msg->dn),
4004                                                        ldb_dn_get_linearized(parent_msg->dn));
4005                                 return ldb_module_done(ar->req, NULL, NULL, LDB_ERR_OPERATIONS_ERROR);
4006                         } else if (ret != LDB_SUCCESS) {
4007                                 ldb_asprintf_errstring(ldb_module_get_ctx(ar->module),
4008                                                        "Unable to find NC root for %s: %s. "
4009                                                        "We need to move this object because parent object %s "
4010                                                        "is deleted, but this object is not.",
4011                                                        ldb_dn_get_linearized(msg->dn),
4012                                                        ldb_errstring(ldb_module_get_ctx(ar->module)),
4013                                                        ldb_dn_get_linearized(parent_msg->dn));
4014                                 return ldb_module_done(ar->req, NULL, NULL, LDB_ERR_OPERATIONS_ERROR);
4015                         }
4016                         
4017                         ret = dsdb_wellknown_dn(ldb_module_get_ctx(ar->module), msg,
4018                                                 nc_root,
4019                                                 DS_GUID_LOSTANDFOUND_CONTAINER,
4020                                                 &parent_dn);
4021                         if (ret != LDB_SUCCESS) {
4022                                 ldb_asprintf_errstring(ldb_module_get_ctx(ar->module),
4023                                                        "Unable to find LostAndFound Container for %s "
4024                                                        "in partition %s: %s. "
4025                                                        "We need to move this object because parent object %s "
4026                                                        "is deleted, but this object is not.",
4027                                                        ldb_dn_get_linearized(msg->dn), ldb_dn_get_linearized(nc_root),
4028                                                        ldb_errstring(ldb_module_get_ctx(ar->module)),
4029                                                        ldb_dn_get_linearized(parent_msg->dn));
4030                                 return ldb_module_done(ar->req, NULL, NULL, LDB_ERR_OPERATIONS_ERROR);
4031                         }
4032                         ar->objs->objects[ar->index_current].last_known_parent
4033                                 = talloc_steal(ar->objs->objects[ar->index_current].msg, parent_msg->dn);
4034                 } else {
4035                         parent_dn = parent_msg->dn;
4036                 }
4037
4038                 comp_num = ldb_dn_get_comp_num(msg->dn);
4039                 if (comp_num > 1) {
4040                         if (!ldb_dn_remove_base_components(msg->dn, comp_num - 1)) {
4041                                 talloc_free(ares);
4042                                 return ldb_module_done(ar->req, NULL, NULL, ldb_module_operr(ar->module));
4043                         }
4044                 }
4045                 if (!ldb_dn_add_base(msg->dn, parent_dn)) {
4046                         talloc_free(ares);
4047                         return ldb_module_done(ar->req, NULL, NULL, ldb_module_operr(ar->module));
4048                 }
4049                 break;
4050         }
4051         case LDB_REPLY_REFERRAL:
4052                 /* we ignore referrals */
4053                 break;
4054
4055         case LDB_REPLY_DONE:
4056                 if (ar->search_msg != NULL) {
4057                         ret = replmd_replicated_apply_merge(ar);
4058                 } else {
4059                         ret = replmd_replicated_apply_add(ar);
4060                 }
4061                 if (ret != LDB_SUCCESS) {
4062                         return ldb_module_done(ar->req, NULL, NULL, ret);
4063                 }
4064         }
4065
4066         talloc_free(ares);
4067         return LDB_SUCCESS;
4068 }
4069
4070 /*
4071  * Look for the parent object, so we put the new object in the right
4072  * place This is akin to NameObject in MS-DRSR - this routine and the
4073  * callbacks find the right parent name, and correct name for this
4074  * object
4075  */
4076
4077 static int replmd_replicated_apply_search_for_parent(struct replmd_replicated_request *ar)
4078 {
4079         struct ldb_context *ldb;
4080         int ret;
4081         char *tmp_str;
4082         char *filter;
4083         struct ldb_request *search_req;
4084         static const char *attrs[] = {"isDeleted", NULL};
4085
4086         ldb = ldb_module_get_ctx(ar->module);
4087
4088         if (!ar->objs->objects[ar->index_current].parent_guid_value.data) {
4089                 if (ar->search_msg != NULL) {
4090                         return replmd_replicated_apply_merge(ar);
4091                 } else {
4092                         return replmd_replicated_apply_add(ar);
4093                 }
4094         }
4095
4096         tmp_str = ldb_binary_encode(ar, ar->objs->objects[ar->index_current].parent_guid_value);
4097         if (!tmp_str) return replmd_replicated_request_werror(ar, WERR_NOMEM);
4098
4099         filter = talloc_asprintf(ar, "(objectGUID=%s)", tmp_str);
4100         if (!filter) return replmd_replicated_request_werror(ar, WERR_NOMEM);
4101         talloc_free(tmp_str);
4102
4103         ret = ldb_build_search_req(&search_req,
4104                                    ldb,
4105                                    ar,
4106                                    ar->objs->partition_dn,
4107                                    LDB_SCOPE_SUBTREE,
4108                                    filter,
4109                                    attrs,
4110                                    NULL,
4111                                    ar,
4112                                    replmd_replicated_apply_search_for_parent_callback,
4113                                    ar->req);
4114         LDB_REQ_SET_LOCATION(search_req);
4115
4116         ret = dsdb_request_add_controls(search_req, 
4117                                         DSDB_SEARCH_SHOW_RECYCLED|
4118                                         DSDB_SEARCH_SHOW_DELETED|
4119                                         DSDB_SEARCH_SHOW_EXTENDED_DN);
4120         if (ret != LDB_SUCCESS) {
4121                 return ret;
4122         }
4123
4124         return ldb_next_request(ar->module, search_req);
4125 }
4126
4127 /*
4128   handle renames that come in over DRS replication
4129  */
4130 static int replmd_replicated_handle_rename(struct replmd_replicated_request *ar,
4131                                            struct ldb_message *msg,
4132                                            struct ldb_request *parent)
4133 {
4134         struct ldb_request *req;
4135         int ret;
4136         TALLOC_CTX *tmp_ctx = talloc_new(msg);
4137         struct ldb_result *res;
4138
4139         DEBUG(4,("replmd_replicated_request rename %s => %s\n",
4140                  ldb_dn_get_linearized(ar->search_msg->dn),
4141                  ldb_dn_get_linearized(msg->dn)));
4142
4143
4144         res = talloc_zero(tmp_ctx, struct ldb_result);
4145         if (!res) {
4146                 talloc_free(tmp_ctx);
4147                 return ldb_oom(ldb_module_get_ctx(ar->module));
4148         }
4149
4150         /* pass rename to the next module
4151          * so it doesn't appear as an originating update */
4152         ret = ldb_build_rename_req(&req, ldb_module_get_ctx(ar->module), tmp_ctx,
4153                                    ar->search_msg->dn, msg->dn,
4154                                    NULL,
4155                                    ar,
4156                                    replmd_op_rename_callback,
4157                                    parent);
4158         LDB_REQ_SET_LOCATION(req);
4159         if (ret != LDB_SUCCESS) {
4160                 talloc_free(tmp_ctx);
4161                 return ret;
4162         }
4163
4164         ret = dsdb_request_add_controls(req, DSDB_MODIFY_RELAX);
4165         if (ret != LDB_SUCCESS) {
4166                 talloc_free(tmp_ctx);
4167                 return ret;
4168         }
4169
4170         ret = ldb_next_request(ar->module, req);
4171
4172         if (ret == LDB_SUCCESS) {
4173                 ret = ldb_wait(req->handle, LDB_WAIT_ALL);
4174         }
4175
4176         talloc_free(tmp_ctx);
4177         return ret;
4178 }
4179
4180
4181 static int replmd_replicated_apply_merge(struct replmd_replicated_request *ar)
4182 {
4183         struct ldb_context *ldb;
4184         struct ldb_request *change_req;
4185         enum ndr_err_code ndr_err;
4186         struct ldb_message *msg;
4187         struct replPropertyMetaDataBlob *rmd;
4188         struct replPropertyMetaDataBlob omd;
4189         const struct ldb_val *omd_value;
4190         struct replPropertyMetaDataBlob nmd;
4191         struct ldb_val nmd_value;
4192         unsigned int i;
4193         uint32_t j,ni=0;
4194         unsigned int removed_attrs = 0;
4195         int ret;
4196         int (*callback)(struct ldb_request *req, struct ldb_reply *ares) = replmd_op_callback;
4197         bool isDeleted = false;
4198         bool local_isDeleted = false;
4199         bool remote_isDeleted = false;
4200         bool take_remote_isDeleted = false;
4201         bool sd_updated = false;
4202         bool renamed = false;
4203
4204         ldb = ldb_module_get_ctx(ar->module);
4205         msg = ar->objs->objects[ar->index_current].msg;
4206
4207         rmd = ar->objs->objects[ar->index_current].meta_data;
4208         ZERO_STRUCT(omd);
4209         omd.version = 1;
4210
4211         /* find existing meta data */
4212         omd_value = ldb_msg_find_ldb_val(ar->search_msg, "replPropertyMetaData");
4213         if (omd_value) {
4214                 ndr_err = ndr_pull_struct_blob(omd_value, ar, &omd,
4215                                                (ndr_pull_flags_fn_t)ndr_pull_replPropertyMetaDataBlob);
4216                 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
4217                         NTSTATUS nt_status = ndr_map_error2ntstatus(ndr_err);
4218                         return replmd_replicated_request_werror(ar, ntstatus_to_werror(nt_status));
4219                 }
4220
4221                 if (omd.version != 1) {
4222                         return replmd_replicated_request_werror(ar, WERR_DS_DRA_INTERNAL_ERROR);
4223                 }
4224         }
4225
4226         local_isDeleted = ldb_msg_find_attr_as_bool(ar->search_msg,
4227                                                     "isDeleted", false);
4228         remote_isDeleted = ldb_msg_find_attr_as_bool(msg,
4229                                                      "isDeleted", false);
4230
4231         if (strcmp(ldb_dn_get_linearized(msg->dn), ldb_dn_get_linearized(ar->search_msg->dn)) == 0) {
4232                 ret = LDB_SUCCESS;
4233         } else {
4234                 /*
4235                  * handle renames, even just by case that come in over
4236                  * DRS.  Changes in the parent DN don't hit us here,
4237                  * because the search for a parent will clean up those
4238                  * components.
4239                  *
4240                  * We also have already filtered out the case where
4241                  * the peer has an older name to what we have (see
4242                  * replmd_replicated_apply_search_callback())
4243                  */
4244                 renamed = true;
4245                 ret = replmd_replicated_handle_rename(ar, msg, ar->req);
4246         }
4247
4248         /*
4249          * This particular error code means that we already tried the
4250          * conflict algrorithm, and the existing record name was newer, so we
4251          * need to rename the incoming record
4252          */
4253         if (ret == LDB_ERR_ENTRY_ALREADY_EXISTS) {
4254                 struct GUID guid;
4255                 NTSTATUS status;
4256                 struct ldb_dn *new_dn;
4257                 status = GUID_from_ndr_blob(&ar->objs->objects[ar->index_current].guid_value, &guid);
4258                 /* This really, really can't fail */
4259                 SMB_ASSERT(NT_STATUS_IS_OK(status));
4260
4261                 new_dn = replmd_conflict_dn(msg, msg->dn, &guid);
4262                 if (new_dn == NULL) {
4263                         ldb_asprintf_errstring(ldb_module_get_ctx(ar->module),
4264                                                                   "Failed to form conflict DN for %s\n",
4265                                                                   ldb_dn_get_linearized(msg->dn));
4266
4267                         return replmd_replicated_request_werror(ar, WERR_NOMEM);
4268                 }
4269
4270                 ret = dsdb_module_rename(ar->module, ar->search_msg->dn, new_dn,
4271                                          DSDB_FLAG_NEXT_MODULE, ar->req);
4272                 if (ret != LDB_SUCCESS) {
4273                         ldb_asprintf_errstring(ldb_module_get_ctx(ar->module),
4274                                                "Failed to rename incoming conflicting dn '%s' (was '%s') to '%s' - %s\n",
4275                                                ldb_dn_get_linearized(msg->dn),
4276                                                ldb_dn_get_linearized(ar->search_msg->dn),
4277                                                ldb_dn_get_linearized(new_dn),
4278                                                ldb_errstring(ldb_module_get_ctx(ar->module)));
4279                         return replmd_replicated_request_werror(ar, WERR_DS_DRA_DB_ERROR);
4280                 }
4281
4282                 /* Set the callback to one that will fix up the name to be a conflict DN */
4283                 callback = replmd_op_name_modify_callback;
4284                 msg->dn = new_dn;
4285                 renamed = true;
4286         } else if (ret != LDB_SUCCESS) {
4287                 ldb_debug(ldb, LDB_DEBUG_FATAL,
4288                           "replmd_replicated_request rename %s => %s failed - %s\n",
4289                           ldb_dn_get_linearized(ar->search_msg->dn),
4290                           ldb_dn_get_linearized(msg->dn),
4291                           ldb_errstring(ldb));
4292                 return replmd_replicated_request_werror(ar, WERR_DS_DRA_DB_ERROR);
4293         }
4294
4295         ZERO_STRUCT(nmd);
4296         nmd.version = 1;
4297         nmd.ctr.ctr1.count = omd.ctr.ctr1.count + rmd->ctr.ctr1.count;
4298         nmd.ctr.ctr1.array = talloc_array(ar,
4299                                           struct replPropertyMetaData1,
4300                                           nmd.ctr.ctr1.count);
4301         if (!nmd.ctr.ctr1.array) return replmd_replicated_request_werror(ar, WERR_NOMEM);
4302
4303         /* first copy the old meta data */
4304         for (i=0; i < omd.ctr.ctr1.count; i++) {
4305                 nmd.ctr.ctr1.array[ni]  = omd.ctr.ctr1.array[i];
4306                 ni++;
4307         }
4308
4309         ar->seq_num = 0;
4310         /* now merge in the new meta data */
4311         for (i=0; i < rmd->ctr.ctr1.count; i++) {
4312                 bool found = false;
4313
4314                 for (j=0; j < ni; j++) {
4315                         bool cmp;
4316
4317                         if (rmd->ctr.ctr1.array[i].attid != nmd.ctr.ctr1.array[j].attid) {
4318                                 continue;
4319                         }
4320
4321                         if (ar->objs->dsdb_repl_flags & DSDB_REPL_FLAG_PRIORITISE_INCOMING) {
4322                                 /* if we compare equal then do an
4323                                    update. This is used when a client
4324                                    asks for a FULL_SYNC, and can be
4325                                    used to recover a corrupt
4326                                    replica */
4327                                 cmp = !replmd_replPropertyMetaData1_is_newer(&rmd->ctr.ctr1.array[i],
4328                                                                              &nmd.ctr.ctr1.array[j]);
4329                         } else {
4330                                 cmp = replmd_replPropertyMetaData1_is_newer(&nmd.ctr.ctr1.array[j],
4331                                                                             &rmd->ctr.ctr1.array[i]);
4332                         }
4333                         if (cmp) {
4334                                 /* replace the entry */
4335                                 nmd.ctr.ctr1.array[j] = rmd->ctr.ctr1.array[i];
4336                                 if (ar->seq_num == 0) {
4337                                         ret = ldb_sequence_number(ldb, LDB_SEQ_NEXT, &ar->seq_num);
4338                                         if (ret != LDB_SUCCESS) {
4339                                                 return replmd_replicated_request_error(ar, ret);
4340                                         }
4341                                 }
4342                                 nmd.ctr.ctr1.array[j].local_usn = ar->seq_num;
4343                                 switch (nmd.ctr.ctr1.array[j].attid) {
4344                                 case DRSUAPI_ATTID_ntSecurityDescriptor:
4345                                         sd_updated = true;
4346                                         break;
4347                                 case DRSUAPI_ATTID_isDeleted:
4348                                         take_remote_isDeleted = true;
4349                                         break;
4350                                 default:
4351                                         break;
4352                                 }
4353                                 found = true;
4354                                 break;
4355                         }
4356
4357                         if (rmd->ctr.ctr1.array[i].attid != DRSUAPI_ATTID_instanceType) {
4358                                 DEBUG(3,("Discarding older DRS attribute update to %s on %s from %s\n",
4359                                          msg->elements[i-removed_attrs].name,
4360                                          ldb_dn_get_linearized(msg->dn),
4361                                          GUID_string(ar, &rmd->ctr.ctr1.array[i].originating_invocation_id)));
4362                         }
4363
4364                         /* we don't want to apply this change so remove the attribute */
4365                         ldb_msg_remove_element(msg, &msg->elements[i-removed_attrs]);
4366                         removed_attrs++;
4367
4368                         found = true;
4369                         break;
4370                 }
4371
4372                 if (found) continue;
4373
4374                 nmd.ctr.ctr1.array[ni] = rmd->ctr.ctr1.array[i];
4375                 if (ar->seq_num == 0) {
4376                         ret = ldb_sequence_number(ldb, LDB_SEQ_NEXT, &ar->seq_num);
4377                         if (ret != LDB_SUCCESS) {
4378                                 return replmd_replicated_request_error(ar, ret);
4379                         }
4380                 }
4381                 nmd.ctr.ctr1.array[ni].local_usn = ar->seq_num;
4382                 switch (nmd.ctr.ctr1.array[ni].attid) {
4383                 case DRSUAPI_ATTID_ntSecurityDescriptor:
4384                         sd_updated = true;
4385                         break;
4386                 case DRSUAPI_ATTID_isDeleted:
4387                         take_remote_isDeleted = true;
4388                         break;
4389                 default:
4390                         break;
4391                 }
4392                 ni++;
4393         }
4394
4395         /*
4396          * finally correct the size of the meta_data array
4397          */
4398         nmd.ctr.ctr1.count = ni;
4399
4400         /*
4401          * the rdn attribute (the alias for the name attribute),
4402          * 'cn' for most objects is the last entry in the meta data array
4403          * we have stored
4404          *
4405          * sort the new meta data array
4406          */
4407         ret = replmd_replPropertyMetaDataCtr1_sort(&nmd.ctr.ctr1, ar->schema, msg->dn);
4408         if (ret != LDB_SUCCESS) {
4409                 return ret;
4410         }
4411
4412         /*
4413          * Work out if this object is deleted, so we can prune any extra attributes.  See MS-DRSR 4.1.10.6.9
4414          * UpdateObject.
4415          *
4416          * This also controls SD propagation below
4417          */
4418         if (take_remote_isDeleted) {
4419                 isDeleted = remote_isDeleted;
4420         } else {
4421                 isDeleted = local_isDeleted;
4422         }
4423
4424         ar->isDeleted = isDeleted;
4425
4426         /*
4427          * check if some replicated attributes left, otherwise skip the ldb_modify() call
4428          */
4429         if (msg->num_elements == 0) {
4430                 ldb_debug(ldb, LDB_DEBUG_TRACE, "replmd_replicated_apply_merge[%u]: skip replace\n",
4431                           ar->index_current);
4432
4433                 return replmd_replicated_apply_isDeleted(ar);
4434         }
4435
4436         ldb_debug(ldb, LDB_DEBUG_TRACE, "replmd_replicated_apply_merge[%u]: replace %u attributes\n",
4437                   ar->index_current, msg->num_elements);
4438
4439         if (renamed) {
4440                 sd_updated = true;
4441         }
4442
4443         if (sd_updated && !isDeleted) {
4444                 ret = dsdb_module_schedule_sd_propagation(ar->module,
4445                                                           ar->objs->partition_dn,
4446                                                           msg->dn, true);
4447                 if (ret != LDB_SUCCESS) {
4448                         return ldb_operr(ldb);
4449                 }
4450         }
4451
4452         /* create the meta data value */
4453         ndr_err = ndr_push_struct_blob(&nmd_value, msg, &nmd,
4454                                        (ndr_push_flags_fn_t)ndr_push_replPropertyMetaDataBlob);
4455         if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
4456                 NTSTATUS nt_status = ndr_map_error2ntstatus(ndr_err);
4457                 return replmd_replicated_request_werror(ar, ntstatus_to_werror(nt_status));
4458         }
4459
4460         /*
4461          * when we know that we'll modify the record, add the whenChanged, uSNChanged
4462          * and replPopertyMetaData attributes
4463          */
4464         ret = ldb_msg_add_string(msg, "whenChanged", ar->objs->objects[ar->index_current].when_changed);
4465         if (ret != LDB_SUCCESS) {
4466                 return replmd_replicated_request_error(ar, ret);
4467         }
4468         ret = samdb_msg_add_uint64(ldb, msg, msg, "uSNChanged", ar->seq_num);
4469         if (ret != LDB_SUCCESS) {
4470                 return replmd_replicated_request_error(ar, ret);
4471         }
4472         ret = ldb_msg_add_value(msg, "replPropertyMetaData", &nmd_value, NULL);
4473         if (ret != LDB_SUCCESS) {
4474                 return replmd_replicated_request_error(ar, ret);
4475         }
4476
4477         replmd_ldb_message_sort(msg, ar->schema);
4478
4479         /* we want to replace the old values */
4480         for (i=0; i < msg->num_elements; i++) {
4481                 msg->elements[i].flags = LDB_FLAG_MOD_REPLACE;
4482         }
4483
4484         if (DEBUGLVL(4)) {
4485                 char *s = ldb_ldif_message_string(ldb, ar, LDB_CHANGETYPE_MODIFY, msg);
4486                 DEBUG(4, ("DRS replication modify message:\n%s\n", s));
4487                 talloc_free(s);
4488         }
4489
4490         ret = ldb_build_mod_req(&change_req,
4491                                 ldb,
4492                                 ar,
4493                                 msg,
4494                                 ar->controls,
4495                                 ar,
4496                                 callback,
4497                                 ar->req);
4498         LDB_REQ_SET_LOCATION(change_req);
4499         if (ret != LDB_SUCCESS) return replmd_replicated_request_error(ar, ret);
4500
4501         /* current partition control needed by "repmd_op_callback" */
4502         ret = ldb_request_add_control(change_req,
4503                                       DSDB_CONTROL_CURRENT_PARTITION_OID,
4504                                       false, NULL);
4505         if (ret != LDB_SUCCESS) return replmd_replicated_request_error(ar, ret);
4506
4507         return ldb_next_request(ar->module, change_req);
4508 }
4509
4510 static int replmd_replicated_apply_search_callback(struct ldb_request *req,
4511                                                    struct ldb_reply *ares)
4512 {
4513         struct replmd_replicated_request *ar = talloc_get_type(req->context,
4514                                                struct replmd_replicated_request);
4515         int ret;
4516
4517         if (!ares) {
4518                 return ldb_module_done(ar->req, NULL, NULL,
4519                                         LDB_ERR_OPERATIONS_ERROR);
4520         }
4521         if (ares->error != LDB_SUCCESS &&
4522             ares->error != LDB_ERR_NO_SUCH_OBJECT) {
4523                 return ldb_module_done(ar->req, ares->controls,
4524                                         ares->response, ares->error);
4525         }
4526
4527         switch (ares->type) {
4528         case LDB_REPLY_ENTRY:
4529                 ar->search_msg = talloc_steal(ar, ares->message);
4530                 break;
4531
4532         case LDB_REPLY_REFERRAL:
4533                 /* we ignore referrals */
4534                 break;
4535
4536         case LDB_REPLY_DONE:
4537         {
4538                 struct replPropertyMetaData1 *md_remote;
4539                 struct replPropertyMetaData1 *md_local;
4540
4541                 struct replPropertyMetaDataBlob omd;
4542                 const struct ldb_val *omd_value;
4543                 struct replPropertyMetaDataBlob *rmd;
4544                 struct ldb_message *msg;
4545
4546                 ar->objs->objects[ar->index_current].last_known_parent = NULL;
4547
4548                 /*
4549                  * This is the ADD case, find the appropriate parent,
4550                  * as this object doesn't exist locally:
4551                  */
4552                 if (ar->search_msg == NULL) {
4553                         ret = replmd_replicated_apply_search_for_parent(ar);
4554                         if (ret != LDB_SUCCESS) {
4555                                 return ldb_module_done(ar->req, NULL, NULL, ret);
4556                         }
4557                         talloc_free(ares);
4558                         return LDB_SUCCESS;
4559                 }
4560
4561                 /*
4562                  * Otherwise, in the MERGE case, work out if we are
4563                  * attempting a rename, and if so find the parent the
4564                  * newly renamed object wants to belong under (which
4565                  * may not be the parent in it's attached string DN
4566                  */
4567                 rmd = ar->objs->objects[ar->index_current].meta_data;
4568                 ZERO_STRUCT(omd);
4569                 omd.version = 1;
4570
4571                 /* find existing meta data */
4572                 omd_value = ldb_msg_find_ldb_val(ar->search_msg, "replPropertyMetaData");
4573                 if (omd_value) {
4574                         enum ndr_err_code ndr_err;
4575                         ndr_err = ndr_pull_struct_blob(omd_value, ar, &omd,
4576                                                        (ndr_pull_flags_fn_t)ndr_pull_replPropertyMetaDataBlob);
4577                         if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
4578                                 NTSTATUS nt_status = ndr_map_error2ntstatus(ndr_err);
4579                                 return replmd_replicated_request_werror(ar, ntstatus_to_werror(nt_status));
4580                         }
4581
4582                         if (omd.version != 1) {
4583                                 return replmd_replicated_request_werror(ar, WERR_DS_DRA_INTERNAL_ERROR);
4584                         }
4585                 }
4586
4587                 /*
4588                  * now we need to check for double renames. We could have a
4589                  * local rename pending which our replication partner hasn't
4590                  * received yet. We choose which one wins by looking at the
4591                  * attribute stamps on the two objects, the newer one wins
4592                  */
4593                 md_remote = replmd_replPropertyMetaData1_find_attid(rmd, DRSUAPI_ATTID_name);
4594                 md_local  = replmd_replPropertyMetaData1_find_attid(&omd, DRSUAPI_ATTID_name);
4595                 /* if there is no name attribute then we have to assume the
4596                    object we've received is in fact newer */
4597                 if (ar->objs->dsdb_repl_flags & DSDB_REPL_FLAG_PRIORITISE_INCOMING ||
4598                     !md_remote || !md_local ||
4599                     replmd_replPropertyMetaData1_is_newer(md_local, md_remote)) {
4600                         ret = replmd_replicated_apply_search_for_parent(ar);
4601                 } else {
4602                         msg = ar->objs->objects[ar->index_current].msg;
4603
4604                         /* Otherwise, just merge on the existing object, force no rename */
4605                         DEBUG(4,(__location__ ": Keeping object %s and rejecting older rename to %s\n",
4606                                  ldb_dn_get_linearized(ar->search_msg->dn),
4607                                  ldb_dn_get_linearized(msg->dn)));
4608
4609                         /*
4610                          * This assignment ensures that the strcmp()
4611                          * in replmd_replicated_apply_merge() avoids
4612                          * the rename call
4613                          */
4614                         msg->dn = ar->search_msg->dn;
4615                         ret = replmd_replicated_apply_merge(ar);
4616                 }
4617                 if (ret != LDB_SUCCESS) {
4618                         return ldb_module_done(ar->req, NULL, NULL, ret);
4619                 }
4620         }
4621         }
4622
4623         talloc_free(ares);
4624         return LDB_SUCCESS;
4625 }
4626
4627 static int replmd_replicated_uptodate_vector(struct replmd_replicated_request *ar);
4628
4629 static int replmd_replicated_apply_next(struct replmd_replicated_request *ar)
4630 {
4631         struct ldb_context *ldb;
4632         int ret;
4633         char *tmp_str;
4634         char *filter;
4635         struct ldb_request *search_req;
4636
4637         if (ar->index_current >= ar->objs->num_objects) {
4638                 /* done with it, go to next stage */
4639                 return replmd_replicated_uptodate_vector(ar);
4640         }
4641
4642         ldb = ldb_module_get_ctx(ar->module);
4643         ar->search_msg = NULL;
4644         ar->isDeleted = false;
4645
4646         tmp_str = ldb_binary_encode(ar, ar->objs->objects[ar->index_current].guid_value);
4647         if (!tmp_str) return replmd_replicated_request_werror(ar, WERR_NOMEM);
4648
4649         filter = talloc_asprintf(ar, "(objectGUID=%s)", tmp_str);
4650         if (!filter) return replmd_replicated_request_werror(ar, WERR_NOMEM);
4651         talloc_free(tmp_str);
4652
4653         ret = ldb_build_search_req(&search_req,
4654                                    ldb,
4655                                    ar,
4656                                    NULL,
4657                                    LDB_SCOPE_SUBTREE,
4658                                    filter,
4659                                    NULL,
4660                                    NULL,
4661                                    ar,
4662                                    replmd_replicated_apply_search_callback,
4663                                    ar->req);
4664         LDB_REQ_SET_LOCATION(search_req);
4665
4666         ret = dsdb_request_add_controls(search_req, DSDB_SEARCH_SEARCH_ALL_PARTITIONS|DSDB_SEARCH_SHOW_RECYCLED);
4667
4668         if (ret != LDB_SUCCESS) {
4669                 return ret;
4670         }
4671
4672         return ldb_next_request(ar->module, search_req);
4673 }
4674
4675 /*
4676  * This is essentially a wrapper for replmd_replicated_apply_next()
4677  *
4678  * This is needed to ensure that both codepaths call this handler.
4679  */
4680 static int replmd_replicated_apply_isDeleted(struct replmd_replicated_request *ar)
4681 {
4682         struct ldb_dn *deleted_objects_dn;
4683         struct ldb_message *msg = ar->objs->objects[ar->index_current].msg;
4684         int ret = dsdb_get_deleted_objects_dn(ldb_module_get_ctx(ar->module), msg, msg->dn,
4685                                               &deleted_objects_dn);
4686         if (ar->isDeleted && (ret != LDB_SUCCESS || ldb_dn_compare(msg->dn, deleted_objects_dn) != 0)) {
4687                 /*
4688                  * Do a delete here again, so that if there is
4689                  * anything local that conflicts with this
4690                  * object being deleted, it is removed.  This
4691                  * includes links.  See MS-DRSR 4.1.10.6.9
4692                  * UpdateObject.
4693                  *
4694                  * If the object is already deleted, and there
4695                  * is no more work required, it doesn't do
4696                  * anything.
4697                  */
4698
4699                 /* This has been updated to point to the DN we eventually did the modify on */
4700
4701                 struct ldb_request *del_req;
4702                 struct ldb_result *res;
4703
4704                 TALLOC_CTX *tmp_ctx = talloc_new(ar);
4705                 if (!tmp_ctx) {
4706                         ret = ldb_oom(ldb_module_get_ctx(ar->module));
4707                         return ret;
4708                 }
4709
4710                 res = talloc_zero(tmp_ctx, struct ldb_result);
4711                 if (!res) {
4712                         ret = ldb_oom(ldb_module_get_ctx(ar->module));
4713                         talloc_free(tmp_ctx);
4714                         return ret;
4715                 }
4716
4717                 /* Build a delete request, which hopefully will artually turn into nothing */
4718                 ret = ldb_build_del_req(&del_req, ldb_module_get_ctx(ar->module), tmp_ctx,
4719                                         msg->dn,
4720                                         NULL,
4721                                         res,
4722                                         ldb_modify_default_callback,
4723                                         ar->req);
4724                 LDB_REQ_SET_LOCATION(del_req);
4725                 if (ret != LDB_SUCCESS) {
4726                         talloc_free(tmp_ctx);
4727                         return ret;
4728                 }
4729
4730                 /*
4731                  * This is the guts of the call, call back
4732                  * into our delete code, but setting the
4733                  * re_delete flag so we delete anything that
4734                  * shouldn't be there on a deleted or recycled
4735                  * object
4736                  */
4737                 ret = replmd_delete_internals(ar->module, del_req, true);
4738                 if (ret == LDB_SUCCESS) {
4739                         ret = ldb_wait(del_req->handle, LDB_WAIT_ALL);
4740                 }
4741
4742                 talloc_free(tmp_ctx);
4743                 if (ret != LDB_SUCCESS) {
4744                         return ret;
4745                 }
4746         }
4747
4748         ar->index_current++;
4749         return replmd_replicated_apply_next(ar);
4750 }
4751
4752 static int replmd_replicated_uptodate_modify_callback(struct ldb_request *req,
4753                                                       struct ldb_reply *ares)
4754 {
4755         struct ldb_context *ldb;
4756         struct replmd_replicated_request *ar = talloc_get_type(req->context,
4757                                                struct replmd_replicated_request);
4758         ldb = ldb_module_get_ctx(ar->module);
4759
4760         if (!ares) {
4761                 return ldb_module_done(ar->req, NULL, NULL,
4762                                         LDB_ERR_OPERATIONS_ERROR);
4763         }
4764         if (ares->error != LDB_SUCCESS) {
4765                 return ldb_module_done(ar->req, ares->controls,
4766                                         ares->response, ares->error);
4767         }
4768
4769         if (ares->type != LDB_REPLY_DONE) {
4770                 ldb_asprintf_errstring(ldb, "Invalid LDB reply type %d", ares->type);
4771                 return ldb_module_done(ar->req, NULL, NULL,
4772                                         LDB_ERR_OPERATIONS_ERROR);
4773         }
4774
4775         talloc_free(ares);
4776
4777         return ldb_module_done(ar->req, NULL, NULL, LDB_SUCCESS);
4778 }
4779
4780 static int replmd_replicated_uptodate_modify(struct replmd_replicated_request *ar)
4781 {
4782         struct ldb_context *ldb;
4783         struct ldb_request *change_req;
4784         enum ndr_err_code ndr_err;
4785         struct ldb_message *msg;
4786         struct replUpToDateVectorBlob ouv;
4787         const struct ldb_val *ouv_value;
4788         const struct drsuapi_DsReplicaCursor2CtrEx *ruv;
4789         struct replUpToDateVectorBlob nuv;
4790         struct ldb_val nuv_value;
4791         struct ldb_message_element *nuv_el = NULL;
4792         const struct GUID *our_invocation_id;
4793         struct ldb_message_element *orf_el = NULL;
4794         struct repsFromToBlob nrf;
4795         struct ldb_val *nrf_value = NULL;
4796         struct ldb_message_element *nrf_el = NULL;
4797         unsigned int i;
4798         uint32_t j,ni=0;
4799         bool found = false;
4800         time_t t = time(NULL);
4801         NTTIME now;
4802         int ret;
4803         uint32_t instanceType;
4804
4805         ldb = ldb_module_get_ctx(ar->module);
4806         ruv = ar->objs->uptodateness_vector;
4807         ZERO_STRUCT(ouv);
4808         ouv.version = 2;
4809         ZERO_STRUCT(nuv);
4810         nuv.version = 2;
4811
4812         unix_to_nt_time(&now, t);
4813
4814         if (ar->search_msg == NULL) {
4815                 /* this happens for a REPL_OBJ call where we are
4816                    creating the target object by replicating it. The
4817                    subdomain join code does this for the partition DN
4818                 */
4819                 DEBUG(4,(__location__ ": Skipping UDV and repsFrom update as no target DN\n"));
4820                 return ldb_module_done(ar->req, NULL, NULL, LDB_SUCCESS);
4821         }
4822
4823         instanceType = ldb_msg_find_attr_as_uint(ar->search_msg, "instanceType", 0);
4824         if (! (instanceType & INSTANCE_TYPE_IS_NC_HEAD)) {
4825                 DEBUG(4,(__location__ ": Skipping UDV and repsFrom update as not NC root: %s\n",
4826                          ldb_dn_get_linearized(ar->search_msg->dn)));
4827                 return ldb_module_done(ar->req, NULL, NULL, LDB_SUCCESS);
4828         }
4829
4830         /*
4831          * first create the new replUpToDateVector
4832          */
4833         ouv_value = ldb_msg_find_ldb_val(ar->search_msg, "replUpToDateVector");
4834         if (ouv_value) {
4835                 ndr_err = ndr_pull_struct_blob(ouv_value, ar, &ouv,
4836                                                (ndr_pull_flags_fn_t)ndr_pull_replUpToDateVectorBlob);
4837                 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
4838                         NTSTATUS nt_status = ndr_map_error2ntstatus(ndr_err);
4839                         return replmd_replicated_request_werror(ar, ntstatus_to_werror(nt_status));
4840                 }
4841
4842                 if (ouv.version != 2) {
4843                         return replmd_replicated_request_werror(ar, WERR_DS_DRA_INTERNAL_ERROR);
4844                 }
4845         }
4846
4847         /*
4848          * the new uptodateness vector will at least
4849          * contain 1 entry, one for the source_dsa
4850          *
4851          * plus optional values from our old vector and the one from the source_dsa
4852          */
4853         nuv.ctr.ctr2.count = ouv.ctr.ctr2.count;
4854         if (ruv) nuv.ctr.ctr2.count += ruv->count;
4855         nuv.ctr.ctr2.cursors = talloc_array(ar,
4856                                             struct drsuapi_DsReplicaCursor2,
4857                                             nuv.ctr.ctr2.count);
4858         if (!nuv.ctr.ctr2.cursors) return replmd_replicated_request_werror(ar, WERR_NOMEM);
4859
4860         /* first copy the old vector */
4861         for (i=0; i < ouv.ctr.ctr2.count; i++) {
4862                 nuv.ctr.ctr2.cursors[ni] = ouv.ctr.ctr2.cursors[i];
4863                 ni++;
4864         }
4865
4866         /* get our invocation_id if we have one already attached to the ldb */
4867         our_invocation_id = samdb_ntds_invocation_id(ldb);
4868         if (our_invocation_id == NULL) {
4869                 DEBUG(0, ("repl_meta_data: Could not find our own server's invocationID!\n"));
4870                 return replmd_replicated_request_werror(ar, WERR_DS_DRA_INTERNAL_ERROR);                
4871         }
4872
4873         /* merge in the source_dsa vector is available */
4874         for (i=0; (ruv && i < ruv->count); i++) {
4875                 found = false;
4876
4877                 if (our_invocation_id &&
4878                     GUID_equal(&ruv->cursors[i].source_dsa_invocation_id,
4879                                our_invocation_id)) {
4880                         continue;
4881                 }
4882
4883                 for (j=0; j < ni; j++) {
4884                         if (!GUID_equal(&ruv->cursors[i].source_dsa_invocation_id,
4885                                         &nuv.ctr.ctr2.cursors[j].source_dsa_invocation_id)) {
4886                                 continue;
4887                         }
4888
4889                         found = true;
4890
4891                         if (ruv->cursors[i].highest_usn > nuv.ctr.ctr2.cursors[j].highest_usn) {
4892                                 nuv.ctr.ctr2.cursors[j] = ruv->cursors[i];
4893                         }
4894                         break;
4895                 }
4896
4897                 if (found) continue;
4898
4899                 /* if it's not there yet, add it */
4900                 nuv.ctr.ctr2.cursors[ni] = ruv->cursors[i];
4901                 ni++;
4902         }
4903
4904         /*
4905          * finally correct the size of the cursors array
4906          */
4907         nuv.ctr.ctr2.count = ni;
4908
4909         /*
4910          * sort the cursors
4911          */
4912         TYPESAFE_QSORT(nuv.ctr.ctr2.cursors, nuv.ctr.ctr2.count, drsuapi_DsReplicaCursor2_compare);
4913
4914         /*
4915          * create the change ldb_message
4916          */
4917         msg = ldb_msg_new(ar);
4918         if (!msg) return replmd_replicated_request_werror(ar, WERR_NOMEM);
4919         msg->dn = ar->search_msg->dn;
4920
4921         ndr_err = ndr_push_struct_blob(&nuv_value, msg, &nuv,
4922                                        (ndr_push_flags_fn_t)ndr_push_replUpToDateVectorBlob);
4923         if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
4924                 NTSTATUS nt_status = ndr_map_error2ntstatus(ndr_err);
4925                 return replmd_replicated_request_werror(ar, ntstatus_to_werror(nt_status));
4926         }
4927         ret = ldb_msg_add_value(msg, "replUpToDateVector", &nuv_value, &nuv_el);
4928         if (ret != LDB_SUCCESS) {
4929                 return replmd_replicated_request_error(ar, ret);
4930         }
4931         nuv_el->flags = LDB_FLAG_MOD_REPLACE;
4932
4933         /*
4934          * now create the new repsFrom value from the given repsFromTo1 structure
4935          */
4936         ZERO_STRUCT(nrf);
4937         nrf.version                                     = 1;
4938         nrf.ctr.ctr1                                    = *ar->objs->source_dsa;
4939         nrf.ctr.ctr1.last_attempt                       = now;
4940         nrf.ctr.ctr1.last_success                       = now;
4941         nrf.ctr.ctr1.result_last_attempt                = WERR_OK;
4942
4943         /*
4944          * first see if we already have a repsFrom value for the current source dsa
4945          * if so we'll later replace this value
4946          */
4947         orf_el = ldb_msg_find_element(ar->search_msg, "repsFrom");
4948         if (orf_el) {
4949                 for (i=0; i < orf_el->num_values; i++) {
4950                         struct repsFromToBlob *trf;
4951
4952                         trf = talloc(ar, struct repsFromToBlob);
4953                         if (!trf) return replmd_replicated_request_werror(ar, WERR_NOMEM);
4954
4955                         ndr_err = ndr_pull_struct_blob(&orf_el->values[i], trf, trf,
4956                                                        (ndr_pull_flags_fn_t)ndr_pull_repsFromToBlob);
4957                         if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
4958                                 NTSTATUS nt_status = ndr_map_error2ntstatus(ndr_err);
4959                                 return replmd_replicated_request_werror(ar, ntstatus_to_werror(nt_status));
4960                         }
4961
4962                         if (trf->version != 1) {
4963                                 return replmd_replicated_request_werror(ar, WERR_DS_DRA_INTERNAL_ERROR);
4964                         }
4965
4966                         /*
4967                          * we compare the source dsa objectGUID not the invocation_id
4968                          * because we want only one repsFrom value per source dsa
4969                          * and when the invocation_id of the source dsa has changed we don't need
4970                          * the old repsFrom with the old invocation_id
4971                          */
4972                         if (!GUID_equal(&trf->ctr.ctr1.source_dsa_obj_guid,
4973                                         &ar->objs->source_dsa->source_dsa_obj_guid)) {
4974                                 talloc_free(trf);
4975                                 continue;
4976                         }
4977
4978                         talloc_free(trf);
4979                         nrf_value = &orf_el->values[i];
4980                         break;
4981                 }
4982
4983                 /*
4984                  * copy over all old values to the new ldb_message
4985                  */
4986                 ret = ldb_msg_add_empty(msg, "repsFrom", 0, &nrf_el);
4987                 if (ret != LDB_SUCCESS) return replmd_replicated_request_error(ar, ret);
4988                 *nrf_el = *orf_el;
4989         }
4990
4991         /*
4992          * if we haven't found an old repsFrom value for the current source dsa
4993          * we'll add a new value
4994          */
4995         if (!nrf_value) {
4996                 struct ldb_val zero_value;
4997                 ZERO_STRUCT(zero_value);
4998                 ret = ldb_msg_add_value(msg, "repsFrom", &zero_value, &nrf_el);
4999                 if (ret != LDB_SUCCESS) return replmd_replicated_request_error(ar, ret);
5000
5001                 nrf_value = &nrf_el->values[nrf_el->num_values - 1];
5002         }
5003
5004         /* we now fill the value which is already attached to ldb_message */
5005         ndr_err = ndr_push_struct_blob(nrf_value, msg,
5006                                        &nrf,
5007                                        (ndr_push_flags_fn_t)ndr_push_repsFromToBlob);
5008         if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
5009                 NTSTATUS nt_status = ndr_map_error2ntstatus(ndr_err);
5010                 return replmd_replicated_request_werror(ar, ntstatus_to_werror(nt_status));
5011         }
5012
5013         /*
5014          * the ldb_message_element for the attribute, has all the old values and the new one
5015          * so we'll replace the whole attribute with all values
5016          */
5017         nrf_el->flags = LDB_FLAG_MOD_REPLACE;
5018
5019         if (CHECK_DEBUGLVL(4)) {
5020                 char *s = ldb_ldif_message_string(ldb, ar, LDB_CHANGETYPE_MODIFY, msg);
5021                 DEBUG(4, ("DRS replication uptodate modify message:\n%s\n", s));
5022                 talloc_free(s);
5023         }
5024
5025         /* prepare the ldb_modify() request */
5026         ret = ldb_build_mod_req(&change_req,
5027                                 ldb,
5028                                 ar,
5029                                 msg,
5030                                 ar->controls,
5031                                 ar,
5032                                 replmd_replicated_uptodate_modify_callback,
5033                                 ar->req);
5034         LDB_REQ_SET_LOCATION(change_req);
5035         if (ret != LDB_SUCCESS) return replmd_replicated_request_error(ar, ret);
5036
5037         return ldb_next_request(ar->module, change_req);
5038 }
5039
5040 static int replmd_replicated_uptodate_search_callback(struct ldb_request *req,
5041                                                       struct ldb_reply *ares)
5042 {
5043         struct replmd_replicated_request *ar = talloc_get_type(req->context,
5044                                                struct replmd_replicated_request);
5045         int ret;
5046
5047         if (!ares) {
5048                 return ldb_module_done(ar->req, NULL, NULL,
5049                                         LDB_ERR_OPERATIONS_ERROR);
5050         }
5051         if (ares->error != LDB_SUCCESS &&
5052             ares->error != LDB_ERR_NO_SUCH_OBJECT) {
5053                 return ldb_module_done(ar->req, ares->controls,
5054                                         ares->response, ares->error);
5055         }
5056
5057         switch (ares->type) {
5058         case LDB_REPLY_ENTRY:
5059                 ar->search_msg = talloc_steal(ar, ares->message);
5060                 break;
5061
5062         case LDB_REPLY_REFERRAL:
5063                 /* we ignore referrals */
5064                 break;
5065
5066         case LDB_REPLY_DONE:
5067                 ret = replmd_replicated_uptodate_modify(ar);
5068                 if (ret != LDB_SUCCESS) {
5069                         return ldb_module_done(ar->req, NULL, NULL, ret);
5070                 }
5071         }
5072
5073         talloc_free(ares);
5074         return LDB_SUCCESS;
5075 }
5076
5077
5078 static int replmd_replicated_uptodate_vector(struct replmd_replicated_request *ar)
5079 {
5080         struct ldb_context *ldb;
5081         int ret;
5082         static const char *attrs[] = {
5083                 "replUpToDateVector",
5084                 "repsFrom",
5085                 "instanceType",
5086                 NULL
5087         };
5088         struct ldb_request *search_req;
5089
5090         ldb = ldb_module_get_ctx(ar->module);
5091         ar->search_msg = NULL;
5092
5093         ret = ldb_build_search_req(&search_req,
5094                                    ldb,
5095                                    ar,
5096                                    ar->objs->partition_dn,
5097                                    LDB_SCOPE_BASE,
5098                                    "(objectClass=*)",
5099                                    attrs,
5100                                    NULL,
5101                                    ar,
5102                                    replmd_replicated_uptodate_search_callback,
5103                                    ar->req);
5104         LDB_REQ_SET_LOCATION(search_req);
5105         if (ret != LDB_SUCCESS) return replmd_replicated_request_error(ar, ret);
5106
5107         return ldb_next_request(ar->module, search_req);
5108 }
5109
5110
5111
5112 static int replmd_extended_replicated_objects(struct ldb_module *module, struct ldb_request *req)
5113 {
5114         struct ldb_context *ldb;
5115         struct dsdb_extended_replicated_objects *objs;
5116         struct replmd_replicated_request *ar;
5117         struct ldb_control **ctrls;
5118         int ret;
5119         uint32_t i;
5120         struct replmd_private *replmd_private =
5121                 talloc_get_type(ldb_module_get_private(module), struct replmd_private);
5122         struct dsdb_control_replicated_update *rep_update;
5123
5124         ldb = ldb_module_get_ctx(module);
5125
5126         ldb_debug(ldb, LDB_DEBUG_TRACE, "replmd_extended_replicated_objects\n");
5127
5128         objs = talloc_get_type(req->op.extended.data, struct dsdb_extended_replicated_objects);
5129         if (!objs) {
5130                 ldb_debug(ldb, LDB_DEBUG_FATAL, "replmd_extended_replicated_objects: invalid extended data\n");
5131                 return LDB_ERR_PROTOCOL_ERROR;
5132         }
5133
5134         if (objs->version != DSDB_EXTENDED_REPLICATED_OBJECTS_VERSION) {
5135                 ldb_debug(ldb, LDB_DEBUG_FATAL, "replmd_extended_replicated_objects: extended data invalid version [%u != %u]\n",
5136                           objs->version, DSDB_EXTENDED_REPLICATED_OBJECTS_VERSION);
5137                 return LDB_ERR_PROTOCOL_ERROR;
5138         }
5139
5140         ar = replmd_ctx_init(module, req);
5141         if (!ar)
5142                 return LDB_ERR_OPERATIONS_ERROR;
5143
5144         /* Set the flags to have the replmd_op_callback run over the full set of objects */
5145         ar->apply_mode = true;
5146         ar->objs = objs;
5147         ar->schema = dsdb_get_schema(ldb, ar);
5148         if (!ar->schema) {
5149                 ldb_debug_set(ldb, LDB_DEBUG_FATAL, "replmd_ctx_init: no loaded schema found\n");
5150                 talloc_free(ar);
5151                 DEBUG(0,(__location__ ": %s\n", ldb_errstring(ldb)));
5152                 return LDB_ERR_CONSTRAINT_VIOLATION;
5153         }
5154
5155         ctrls = req->controls;
5156
5157         if (req->controls) {
5158                 req->controls = talloc_memdup(ar, req->controls,
5159                                               talloc_get_size(req->controls));
5160                 if (!req->controls) return replmd_replicated_request_werror(ar, WERR_NOMEM);
5161         }
5162
5163         /* This allows layers further down to know if a change came in
5164            over replication and what the replication flags were */
5165         rep_update = talloc_zero(ar, struct dsdb_control_replicated_update);
5166         if (rep_update == NULL) {
5167                 return ldb_module_oom(module);
5168         }
5169         rep_update->dsdb_repl_flags = objs->dsdb_repl_flags;
5170
5171         ret = ldb_request_add_control(req, DSDB_CONTROL_REPLICATED_UPDATE_OID, false, rep_update);
5172         if (ret != LDB_SUCCESS) {
5173                 return ret;
5174         }
5175
5176         /* If this change contained linked attributes in the body
5177          * (rather than in the links section) we need to update
5178          * backlinks in linked_attributes */
5179         ret = ldb_request_add_control(req, DSDB_CONTROL_APPLY_LINKS, false, NULL);
5180         if (ret != LDB_SUCCESS) {
5181                 return ret;
5182         }
5183
5184         ar->controls = req->controls;
5185         req->controls = ctrls;
5186
5187         DEBUG(4,("linked_attributes_count=%u\n", objs->linked_attributes_count));
5188
5189         /* save away the linked attributes for the end of the
5190            transaction */
5191         for (i=0; i<ar->objs->linked_attributes_count; i++) {
5192                 struct la_entry *la_entry;
5193
5194                 if (replmd_private->la_ctx == NULL) {
5195                         replmd_private->la_ctx = talloc_new(replmd_private);
5196                 }
5197                 la_entry = talloc(replmd_private->la_ctx, struct la_entry);
5198                 if (la_entry == NULL) {
5199                         ldb_oom(ldb);
5200                         return LDB_ERR_OPERATIONS_ERROR;
5201                 }
5202                 la_entry->la = talloc(la_entry, struct drsuapi_DsReplicaLinkedAttribute);
5203                 if (la_entry->la == NULL) {
5204                         talloc_free(la_entry);
5205                         ldb_oom(ldb);
5206                         return LDB_ERR_OPERATIONS_ERROR;
5207                 }
5208                 *la_entry->la = ar->objs->linked_attributes[i];
5209
5210                 /* we need to steal the non-scalars so they stay
5211                    around until the end of the transaction */
5212                 talloc_steal(la_entry->la, la_entry->la->identifier);
5213                 talloc_steal(la_entry->la, la_entry->la->value.blob);
5214
5215                 DLIST_ADD(replmd_private->la_list, la_entry);
5216         }
5217
5218         return replmd_replicated_apply_next(ar);
5219 }
5220
5221 /*
5222   process one linked attribute structure
5223  */
5224 static int replmd_process_linked_attribute(struct ldb_module *module,
5225                                            struct la_entry *la_entry,
5226                                            struct ldb_request *parent)
5227 {
5228         struct drsuapi_DsReplicaLinkedAttribute *la = la_entry->la;
5229         struct ldb_context *ldb = ldb_module_get_ctx(module);
5230         struct ldb_message *msg;
5231         struct ldb_message *target_msg = NULL;
5232         TALLOC_CTX *tmp_ctx = talloc_new(la_entry);
5233         const struct dsdb_schema *schema = dsdb_get_schema(ldb, tmp_ctx);
5234         int ret;
5235         const struct dsdb_attribute *attr;
5236         struct dsdb_dn *dsdb_dn;
5237         uint64_t seq_num = 0;
5238         struct ldb_message_element *old_el;
5239         WERROR status;
5240         time_t t = time(NULL);
5241         struct ldb_result *res;
5242         struct ldb_result *target_res;
5243         const char *attrs[4];
5244         const char *attrs2[] = { "isDeleted", "isRecycled", NULL };
5245         struct parsed_dn *pdn_list, *pdn;
5246         struct GUID guid = GUID_zero();
5247         NTSTATUS ntstatus;
5248         bool active = (la->flags & DRSUAPI_DS_LINKED_ATTRIBUTE_FLAG_ACTIVE)?true:false;
5249         const struct GUID *our_invocation_id;
5250
5251         enum deletion_state deletion_state = OBJECT_NOT_DELETED;
5252         enum deletion_state target_deletion_state = OBJECT_NOT_DELETED;
5253
5254 /*
5255 linked_attributes[0]:
5256      &objs->linked_attributes[i]: struct drsuapi_DsReplicaLinkedAttribute
5257         identifier               : *
5258             identifier: struct drsuapi_DsReplicaObjectIdentifier
5259                 __ndr_size               : 0x0000003a (58)
5260                 __ndr_size_sid           : 0x00000000 (0)
5261                 guid                     : 8e95b6a9-13dd-4158-89db-3220a5be5cc7
5262                 sid                      : S-0-0
5263                 __ndr_size_dn            : 0x00000000 (0)
5264                 dn                       : ''
5265         attid                    : DRSUAPI_ATTID_member (0x1F)
5266         value: struct drsuapi_DsAttributeValue
5267             __ndr_size               : 0x0000007e (126)
5268             blob                     : *
5269                 blob                     : DATA_BLOB length=126
5270         flags                    : 0x00000001 (1)
5271                1: DRSUAPI_DS_LINKED_ATTRIBUTE_FLAG_ACTIVE
5272         originating_add_time     : Wed Sep  2 22:20:01 2009 EST
5273         meta_data: struct drsuapi_DsReplicaMetaData
5274             version                  : 0x00000015 (21)
5275             originating_change_time  : Wed Sep  2 23:39:07 2009 EST
5276             originating_invocation_id: 794640f3-18cf-40ee-a211-a93992b67a64
5277             originating_usn          : 0x000000000001e19c (123292)
5278
5279 (for cases where the link is to a normal DN)
5280      &target: struct drsuapi_DsReplicaObjectIdentifier3
5281         __ndr_size               : 0x0000007e (126)
5282         __ndr_size_sid           : 0x0000001c (28)
5283         guid                     : 7639e594-db75-4086-b0d4-67890ae46031
5284         sid                      : S-1-5-21-2848215498-2472035911-1947525656-19924
5285         __ndr_size_dn            : 0x00000022 (34)
5286         dn                       : 'CN=UOne,OU=TestOU,DC=vsofs8,DC=com'
5287  */
5288
5289         /* find the attribute being modified */
5290         attr = dsdb_attribute_by_attributeID_id(schema, la->attid);
5291         if (attr == NULL) {
5292                 DEBUG(0, (__location__ ": Unable to find attributeID 0x%x\n", la->attid));
5293                 talloc_free(tmp_ctx);
5294                 return LDB_ERR_OPERATIONS_ERROR;
5295         }
5296
5297         attrs[0] = attr->lDAPDisplayName;
5298         attrs[1] = "isDeleted";
5299         attrs[1] = "isRecycled";
5300         attrs[2] = NULL;
5301
5302         /* get the existing message from the db for the object with
5303            this GUID, returning attribute being modified. We will then
5304            use this msg as the basis for a modify call */
5305         ret = dsdb_module_search(module, tmp_ctx, &res, NULL, LDB_SCOPE_SUBTREE, attrs,
5306                                  DSDB_FLAG_NEXT_MODULE |
5307                                  DSDB_SEARCH_SEARCH_ALL_PARTITIONS |
5308                                  DSDB_SEARCH_SHOW_RECYCLED |
5309                                  DSDB_SEARCH_SHOW_DN_IN_STORAGE_FORMAT |
5310                                  DSDB_SEARCH_REVEAL_INTERNALS,
5311                                  parent,
5312                                  "objectGUID=%s", GUID_string(tmp_ctx, &la->identifier->guid));
5313         if (ret != LDB_SUCCESS) {
5314                 talloc_free(tmp_ctx);
5315                 return ret;
5316         }
5317         if (res->count != 1) {
5318                 ldb_asprintf_errstring(ldb, "DRS linked attribute for GUID %s - DN not found",
5319                                        GUID_string(tmp_ctx, &la->identifier->guid));
5320                 talloc_free(tmp_ctx);
5321                 return LDB_ERR_NO_SUCH_OBJECT;
5322         }
5323         msg = res->msgs[0];
5324
5325         /*
5326          * Check for deleted objects per MS-DRSR 4.1.10.6.13
5327          * ProcessLinkValue, because link updates are not applied to
5328          * recycled and tombstone objects.  We don't have to delete
5329          * any existing link, that should have happened when the
5330          * object deletion was replicated or initiated.
5331          */
5332
5333         replmd_deletion_state(module, msg, &deletion_state, NULL);
5334
5335         if (deletion_state >= OBJECT_RECYCLED) {
5336                 talloc_free(tmp_ctx);
5337                 return LDB_SUCCESS;
5338         }
5339
5340         old_el = ldb_msg_find_element(msg, attr->lDAPDisplayName);
5341         if (old_el == NULL) {
5342                 ret = ldb_msg_add_empty(msg, attr->lDAPDisplayName, LDB_FLAG_MOD_REPLACE, &old_el);
5343                 if (ret != LDB_SUCCESS) {
5344                         ldb_module_oom(module);
5345                         talloc_free(tmp_ctx);
5346                         return LDB_ERR_OPERATIONS_ERROR;
5347                 }
5348         } else {
5349                 old_el->flags = LDB_FLAG_MOD_REPLACE;
5350         }
5351
5352         /* parse the existing links */
5353         ret = get_parsed_dns(module, tmp_ctx, old_el, &pdn_list, attr->syntax->ldap_oid, parent);
5354         if (ret != LDB_SUCCESS) {
5355                 talloc_free(tmp_ctx);
5356                 return ret;
5357         }
5358
5359         /* get our invocationId */
5360         our_invocation_id = samdb_ntds_invocation_id(ldb);
5361         if (!our_invocation_id) {
5362                 ldb_debug_set(ldb, LDB_DEBUG_ERROR, __location__ ": unable to find invocationId\n");
5363                 talloc_free(tmp_ctx);
5364                 return LDB_ERR_OPERATIONS_ERROR;
5365         }
5366
5367         ret = replmd_check_upgrade_links(pdn_list, old_el->num_values, old_el, our_invocation_id);
5368         if (ret != LDB_SUCCESS) {
5369                 talloc_free(tmp_ctx);
5370                 return ret;
5371         }
5372
5373         status = dsdb_dn_la_from_blob(ldb, attr, schema, tmp_ctx, la->value.blob, &dsdb_dn);
5374         if (!W_ERROR_IS_OK(status)) {
5375                 ldb_asprintf_errstring(ldb, "Failed to parsed linked attribute blob for %s on %s - %s\n",
5376                                        old_el->name, ldb_dn_get_linearized(msg->dn), win_errstr(status));
5377                 talloc_free(tmp_ctx);
5378                 return LDB_ERR_OPERATIONS_ERROR;
5379         }
5380
5381         ntstatus = dsdb_get_extended_dn_guid(dsdb_dn->dn, &guid, "GUID");
5382         if (!NT_STATUS_IS_OK(ntstatus) && !active) {
5383                 /*
5384                  * This strange behaviour (allowing a NULL/missing
5385                  * GUID) originally comes from:
5386                  *
5387                  * commit e3054ce0fe0f8f62d2f5b2a77893e7a1479128bd
5388                  * Author: Andrew Tridgell <tridge@samba.org>
5389                  * Date:   Mon Dec 21 21:21:55 2009 +1100
5390                  *
5391                  *  s4-drs: cope better with NULL GUIDS from DRS
5392                  *
5393                  *  It is valid to get a NULL GUID over DRS for a deleted forward link. We
5394                  *  need to match by DN if possible when seeing if we should update an
5395                  *  existing link.
5396                  *
5397                  *  Pair-Programmed-With: Andrew Bartlett <abartlet@samba.org>
5398                  */
5399
5400                 ret = dsdb_module_search_dn(module, tmp_ctx, &target_res,
5401                                             dsdb_dn->dn, attrs2,
5402                                             DSDB_FLAG_NEXT_MODULE |
5403                                             DSDB_SEARCH_SHOW_RECYCLED |
5404                                             DSDB_SEARCH_SEARCH_ALL_PARTITIONS |
5405                                             DSDB_SEARCH_SHOW_DN_IN_STORAGE_FORMAT,
5406                                             parent);
5407         } else if (!NT_STATUS_IS_OK(ntstatus)) {
5408                 ldb_asprintf_errstring(ldb, "Failed to find GUID in linked attribute blob for %s on %s from %s",
5409                                        old_el->name,
5410                                        ldb_dn_get_linearized(dsdb_dn->dn),
5411                                        ldb_dn_get_linearized(msg->dn));
5412                 talloc_free(tmp_ctx);
5413                 return LDB_ERR_OPERATIONS_ERROR;
5414         } else {
5415                 ret = dsdb_module_search(module, tmp_ctx, &target_res,
5416                                          NULL, LDB_SCOPE_SUBTREE,
5417                                          attrs2,
5418                                          DSDB_FLAG_NEXT_MODULE |
5419                                          DSDB_SEARCH_SHOW_RECYCLED |
5420                                          DSDB_SEARCH_SEARCH_ALL_PARTITIONS |
5421                                          DSDB_SEARCH_SHOW_DN_IN_STORAGE_FORMAT,
5422                                          parent,
5423                                          "objectGUID=%s",
5424                                          GUID_string(tmp_ctx, &guid));
5425         }
5426
5427         if (ret != LDB_SUCCESS) {
5428                 ldb_asprintf_errstring(ldb_module_get_ctx(module), "Failed to re-resolve GUID %s: %s\n",
5429                                        GUID_string(tmp_ctx, &guid),
5430                                        ldb_errstring(ldb_module_get_ctx(module)));
5431                 talloc_free(tmp_ctx);
5432                 return ret;
5433         }
5434
5435         if (target_res->count == 0) {
5436                 DEBUG(2,(__location__ ": WARNING: Failed to re-resolve GUID %s - using %s\n",
5437                          GUID_string(tmp_ctx, &guid),
5438                          ldb_dn_get_linearized(dsdb_dn->dn)));
5439         } else if (target_res->count != 1) {
5440                 ldb_asprintf_errstring(ldb_module_get_ctx(module), "More than one object found matching objectGUID %s\n",
5441                                        GUID_string(tmp_ctx, &guid));
5442                 talloc_free(tmp_ctx);
5443                 return LDB_ERR_OPERATIONS_ERROR;
5444         } else {
5445                 target_msg = target_res->msgs[0];
5446                 dsdb_dn->dn = talloc_steal(dsdb_dn, target_msg->dn);
5447         }
5448
5449         /*
5450          * Check for deleted objects per MS-DRSR 4.1.10.6.13
5451          * ProcessLinkValue, because link updates are not applied to
5452          * recycled and tombstone objects.  We don't have to delete
5453          * any existing link, that should have happened when the
5454          * object deletion was replicated or initiated.
5455          */
5456         replmd_deletion_state(module, target_msg,
5457                               &target_deletion_state, NULL);
5458
5459         if (target_deletion_state >= OBJECT_RECYCLED) {
5460                 talloc_free(tmp_ctx);
5461                 return LDB_SUCCESS;
5462         }
5463
5464         /* see if this link already exists */
5465         pdn = parsed_dn_find(pdn_list, old_el->num_values, &guid, dsdb_dn->dn);
5466         if (pdn != NULL) {
5467                 /* see if this update is newer than what we have already */
5468                 struct GUID invocation_id = GUID_zero();
5469                 uint32_t version = 0;
5470                 uint32_t originating_usn = 0;
5471                 NTTIME change_time = 0;
5472                 uint32_t rmd_flags = dsdb_dn_rmd_flags(pdn->dsdb_dn->dn);
5473
5474                 dsdb_get_extended_dn_guid(pdn->dsdb_dn->dn, &invocation_id, "RMD_INVOCID");
5475                 dsdb_get_extended_dn_uint32(pdn->dsdb_dn->dn, &version, "RMD_VERSION");
5476                 dsdb_get_extended_dn_uint32(pdn->dsdb_dn->dn, &originating_usn, "RMD_ORIGINATING_USN");
5477                 dsdb_get_extended_dn_nttime(pdn->dsdb_dn->dn, &change_time, "RMD_CHANGETIME");
5478
5479                 if (!replmd_update_is_newer(&invocation_id,
5480                                             &la->meta_data.originating_invocation_id,
5481                                             version,
5482                                             la->meta_data.version,
5483                                             change_time,
5484                                             la->meta_data.originating_change_time)) {
5485                         DEBUG(3,("Discarding older DRS linked attribute update to %s on %s from %s\n",
5486                                  old_el->name, ldb_dn_get_linearized(msg->dn),
5487                                  GUID_string(tmp_ctx, &la->meta_data.originating_invocation_id)));
5488                         talloc_free(tmp_ctx);
5489                         return LDB_SUCCESS;
5490                 }
5491
5492                 /* get a seq_num for this change */
5493                 ret = ldb_sequence_number(ldb, LDB_SEQ_NEXT, &seq_num);
5494                 if (ret != LDB_SUCCESS) {
5495                         talloc_free(tmp_ctx);
5496                         return ret;
5497                 }
5498
5499                 if (!(rmd_flags & DSDB_RMD_FLAG_DELETED)) {
5500                         /* remove the existing backlink */
5501                         ret = replmd_add_backlink(module, schema, &la->identifier->guid, &guid, false, attr, false);
5502                         if (ret != LDB_SUCCESS) {
5503                                 talloc_free(tmp_ctx);
5504                                 return ret;
5505                         }
5506                 }
5507
5508                 ret = replmd_update_la_val(tmp_ctx, pdn->v, dsdb_dn, pdn->dsdb_dn,
5509                                            &la->meta_data.originating_invocation_id,
5510                                            la->meta_data.originating_usn, seq_num,
5511                                            la->meta_data.originating_change_time,
5512                                            la->meta_data.version,
5513                                            !active);
5514                 if (ret != LDB_SUCCESS) {
5515                         talloc_free(tmp_ctx);
5516                         return ret;
5517                 }
5518
5519                 if (active) {
5520                         /* add the new backlink */
5521                         ret = replmd_add_backlink(module, schema, &la->identifier->guid, &guid, true, attr, false);
5522                         if (ret != LDB_SUCCESS) {
5523                                 talloc_free(tmp_ctx);
5524                                 return ret;
5525                         }
5526                 }
5527         } else {
5528                 /* get a seq_num for this change */
5529                 ret = ldb_sequence_number(ldb, LDB_SEQ_NEXT, &seq_num);
5530                 if (ret != LDB_SUCCESS) {
5531                         talloc_free(tmp_ctx);
5532                         return ret;
5533                 }
5534
5535                 old_el->values = talloc_realloc(msg->elements, old_el->values,
5536                                                 struct ldb_val, old_el->num_values+1);
5537                 if (!old_el->values) {
5538                         ldb_module_oom(module);
5539                         return LDB_ERR_OPERATIONS_ERROR;
5540                 }
5541                 old_el->num_values++;
5542
5543                 ret = replmd_build_la_val(tmp_ctx, &old_el->values[old_el->num_values-1], dsdb_dn,
5544                                           &la->meta_data.originating_invocation_id,
5545                                           la->meta_data.originating_usn, seq_num,
5546                                           la->meta_data.originating_change_time,
5547                                           la->meta_data.version,
5548                                           (la->flags & DRSUAPI_DS_LINKED_ATTRIBUTE_FLAG_ACTIVE)?false:true);
5549                 if (ret != LDB_SUCCESS) {
5550                         talloc_free(tmp_ctx);
5551                         return ret;
5552                 }
5553
5554                 if (active) {
5555                         ret = replmd_add_backlink(module, schema, &la->identifier->guid, &guid,
5556                                                   true, attr, false);
5557                         if (ret != LDB_SUCCESS) {
5558                                 talloc_free(tmp_ctx);
5559                                 return ret;
5560                         }
5561                 }
5562         }
5563
5564         /* we only change whenChanged and uSNChanged if the seq_num
5565            has changed */
5566         ret = add_time_element(msg, "whenChanged", t);
5567         if (ret != LDB_SUCCESS) {
5568                 talloc_free(tmp_ctx);
5569                 ldb_operr(ldb);
5570                 return ret;
5571         }
5572
5573         ret = add_uint64_element(ldb, msg, "uSNChanged", seq_num);
5574         if (ret != LDB_SUCCESS) {
5575                 talloc_free(tmp_ctx);
5576                 ldb_operr(ldb);
5577                 return ret;
5578         }
5579
5580         old_el = ldb_msg_find_element(msg, attr->lDAPDisplayName);
5581         if (old_el == NULL) {
5582                 talloc_free(tmp_ctx);
5583                 return ldb_operr(ldb);
5584         }
5585
5586         ret = dsdb_check_single_valued_link(attr, old_el);
5587         if (ret != LDB_SUCCESS) {
5588                 talloc_free(tmp_ctx);
5589                 return ret;
5590         }
5591
5592         old_el->flags |= LDB_FLAG_INTERNAL_DISABLE_SINGLE_VALUE_CHECK;
5593
5594         ret = dsdb_module_modify(module, msg, DSDB_FLAG_NEXT_MODULE, parent);
5595         if (ret != LDB_SUCCESS) {
5596                 ldb_debug(ldb, LDB_DEBUG_WARNING, "Failed to apply linked attribute change '%s'\n%s\n",
5597                           ldb_errstring(ldb),
5598                           ldb_ldif_message_string(ldb, tmp_ctx, LDB_CHANGETYPE_MODIFY, msg));
5599                 talloc_free(tmp_ctx);
5600                 return ret;
5601         }
5602
5603         talloc_free(tmp_ctx);
5604
5605         return ret;
5606 }
5607
5608 static int replmd_extended(struct ldb_module *module, struct ldb_request *req)
5609 {
5610         if (strcmp(req->op.extended.oid, DSDB_EXTENDED_REPLICATED_OBJECTS_OID) == 0) {
5611                 return replmd_extended_replicated_objects(module, req);
5612         }
5613
5614         return ldb_next_request(module, req);
5615 }
5616
5617
5618 /*
5619   we hook into the transaction operations to allow us to
5620   perform the linked attribute updates at the end of the whole
5621   transaction. This allows a forward linked attribute to be created
5622   before the object is created. During a vampire, w2k8 sends us linked
5623   attributes before the objects they are part of.
5624  */
5625 static int replmd_start_transaction(struct ldb_module *module)
5626 {
5627         /* create our private structure for this transaction */
5628         struct replmd_private *replmd_private = talloc_get_type(ldb_module_get_private(module),
5629                                                                 struct replmd_private);
5630         replmd_txn_cleanup(replmd_private);
5631
5632         /* free any leftover mod_usn records from cancelled
5633            transactions */
5634         while (replmd_private->ncs) {
5635                 struct nc_entry *e = replmd_private->ncs;
5636                 DLIST_REMOVE(replmd_private->ncs, e);
5637                 talloc_free(e);
5638         }
5639
5640         return ldb_next_start_trans(module);
5641 }
5642
5643 /*
5644   on prepare commit we loop over our queued la_context structures and
5645   apply each of them
5646  */
5647 static int replmd_prepare_commit(struct ldb_module *module)
5648 {
5649         struct replmd_private *replmd_private =
5650                 talloc_get_type(ldb_module_get_private(module), struct replmd_private);
5651         struct la_entry *la, *prev;
5652         struct la_backlink *bl;
5653         int ret;
5654
5655         /* walk the list backwards, to do the first entry first, as we
5656          * added the entries with DLIST_ADD() which puts them at the
5657          * start of the list */
5658         for (la = DLIST_TAIL(replmd_private->la_list); la; la=prev) {
5659                 prev = DLIST_PREV(la);
5660                 DLIST_REMOVE(replmd_private->la_list, la);
5661                 ret = replmd_process_linked_attribute(module, la, NULL);
5662                 if (ret != LDB_SUCCESS) {
5663                         replmd_txn_cleanup(replmd_private);
5664                         return ret;
5665                 }
5666         }
5667
5668         /* process our backlink list, creating and deleting backlinks
5669            as necessary */
5670         for (bl=replmd_private->la_backlinks; bl; bl=bl->next) {
5671                 ret = replmd_process_backlink(module, bl, NULL);
5672                 if (ret != LDB_SUCCESS) {
5673                         replmd_txn_cleanup(replmd_private);
5674                         return ret;
5675                 }
5676         }
5677
5678         replmd_txn_cleanup(replmd_private);
5679
5680         /* possibly change @REPLCHANGED */
5681         ret = replmd_notify_store(module, NULL);
5682         if (ret != LDB_SUCCESS) {
5683                 return ret;
5684         }
5685
5686         return ldb_next_prepare_commit(module);
5687 }
5688
5689 static int replmd_del_transaction(struct ldb_module *module)
5690 {
5691         struct replmd_private *replmd_private =
5692                 talloc_get_type(ldb_module_get_private(module), struct replmd_private);
5693         replmd_txn_cleanup(replmd_private);
5694
5695         return ldb_next_del_trans(module);
5696 }
5697
5698
5699 static const struct ldb_module_ops ldb_repl_meta_data_module_ops = {
5700         .name          = "repl_meta_data",
5701         .init_context      = replmd_init,
5702         .add               = replmd_add,
5703         .modify            = replmd_modify,
5704         .rename            = replmd_rename,
5705         .del               = replmd_delete,
5706         .extended          = replmd_extended,
5707         .start_transaction = replmd_start_transaction,
5708         .prepare_commit    = replmd_prepare_commit,
5709         .del_transaction   = replmd_del_transaction,
5710 };
5711
5712 int ldb_repl_meta_data_module_init(const char *version)
5713 {
5714         LDB_MODULE_CHECK_VERSION(version);
5715         return ldb_register_module(&ldb_repl_meta_data_module_ops);
5716 }