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