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