347cf0f8d49986c539c1a42bdb32df063fa48512
[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 attrs2[] = { "uSNChanged", "objectClass", "instanceType", NULL };
1411         struct ldb_result *res;
1412         struct ldb_context *ldb;
1413         struct ldb_message_element *objectclass_el;
1414         enum urgent_situation situation;
1415         bool rmd_is_provided;
1416         bool rmd_is_just_resorted = false;
1417         const char *not_rename_attrs[4 + msg->num_elements];
1418         
1419         if (rename_attrs) {
1420                 attrs = rename_attrs;
1421         } else {
1422                 for (i = 0; i < msg->num_elements; i++) {
1423                         not_rename_attrs[i] = msg->elements[i].name;
1424                 }
1425                 not_rename_attrs[i] = "replPropertyMetaData";
1426                 not_rename_attrs[i+1] = "objectClass";
1427                 not_rename_attrs[i+2] = "instanceType";
1428                 not_rename_attrs[i+3] = NULL;
1429                 attrs = not_rename_attrs;
1430         }
1431
1432         ldb = ldb_module_get_ctx(module);
1433
1434         our_invocation_id = samdb_ntds_invocation_id(ldb);
1435         if (!our_invocation_id) {
1436                 /* this happens during an initial vampire while
1437                    updating the schema */
1438                 DEBUG(5,("No invocationID - skipping replPropertyMetaData update\n"));
1439                 return LDB_SUCCESS;
1440         }
1441
1442         unix_to_nt_time(&now, t);
1443
1444         if (ldb_request_get_control(req, DSDB_CONTROL_CHANGEREPLMETADATA_OID)) {
1445                 rmd_is_provided = true;
1446                 if (ldb_request_get_control(req, DSDB_CONTROL_CHANGEREPLMETADATA_RESORT_OID)) {
1447                         rmd_is_just_resorted = true;
1448                 }
1449         } else {
1450                 rmd_is_provided = false;
1451         }
1452
1453         /* if isDeleted is present and is TRUE, then we consider we are deleting,
1454          * otherwise we consider we are updating */
1455         if (ldb_msg_check_string_attribute(msg, "isDeleted", "TRUE")) {
1456                 situation = REPL_URGENT_ON_DELETE;
1457         } else if (rename_attrs) {
1458                 situation = REPL_URGENT_ON_CREATE | REPL_URGENT_ON_DELETE;
1459         } else {
1460                 situation = REPL_URGENT_ON_UPDATE;
1461         }
1462
1463         if (rmd_is_provided) {
1464                 /* In this case the change_replmetadata control was supplied */
1465                 /* We check that it's the only attribute that is provided
1466                  * (it's a rare case so it's better to keep the code simplier)
1467                  * We also check that the highest local_usn is bigger or the same as
1468                  * uSNChanged. */
1469                 uint64_t db_seq;
1470                 if( msg->num_elements != 1 ||
1471                         strncmp(msg->elements[0].name,
1472                                 "replPropertyMetaData", 20) ) {
1473                         DEBUG(0,(__location__ ": changereplmetada control called without "\
1474                                 "a specified replPropertyMetaData attribute or with others\n"));
1475                         return LDB_ERR_OPERATIONS_ERROR;
1476                 }
1477                 if (situation != REPL_URGENT_ON_UPDATE) {
1478                         DEBUG(0,(__location__ ": changereplmetada control can't be called when deleting an object\n"));
1479                         return LDB_ERR_OPERATIONS_ERROR;
1480                 }
1481                 omd_value = ldb_msg_find_ldb_val(msg, "replPropertyMetaData");
1482                 if (!omd_value) {
1483                         DEBUG(0,(__location__ ": replPropertyMetaData was not specified for Object %s\n",
1484                                  ldb_dn_get_linearized(msg->dn)));
1485                         return LDB_ERR_OPERATIONS_ERROR;
1486                 }
1487                 ndr_err = ndr_pull_struct_blob(omd_value, msg, &omd,
1488                                                (ndr_pull_flags_fn_t)ndr_pull_replPropertyMetaDataBlob);
1489                 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
1490                         DEBUG(0,(__location__ ": Failed to parse replPropertyMetaData for %s\n",
1491                                  ldb_dn_get_linearized(msg->dn)));
1492                         return LDB_ERR_OPERATIONS_ERROR;
1493                 }
1494
1495                 ret = dsdb_module_search_dn(module, msg, &res, msg->dn, attrs2,
1496                                             DSDB_FLAG_NEXT_MODULE |
1497                                             DSDB_SEARCH_SHOW_RECYCLED |
1498                                             DSDB_SEARCH_SHOW_EXTENDED_DN |
1499                                             DSDB_SEARCH_SHOW_DN_IN_STORAGE_FORMAT |
1500                                             DSDB_SEARCH_REVEAL_INTERNALS, req);
1501
1502                 if (ret != LDB_SUCCESS) {
1503                         return ret;
1504                 }
1505
1506                 if (rmd_is_just_resorted == false) {
1507                         *seq_num = find_max_local_usn(omd);
1508
1509                         db_seq = ldb_msg_find_attr_as_uint64(res->msgs[0], "uSNChanged", 0);
1510
1511                         /*
1512                          * The test here now allows for a new
1513                          * replPropertyMetaData with no change, if was
1514                          * just dbcheck re-sorting the values.
1515                          */
1516                         if (*seq_num <= db_seq) {
1517                                 DEBUG(0,(__location__ ": changereplmetada control provided but max(local_usn)" \
1518                                          " is less than uSNChanged (max = %lld uSNChanged = %lld)\n",
1519                                          (long long)*seq_num, (long long)db_seq));
1520                                 return LDB_ERR_OPERATIONS_ERROR;
1521                         }
1522                 }
1523
1524         } else {
1525                 /* search for the existing replPropertyMetaDataBlob. We need
1526                  * to use REVEAL and ask for DNs in storage format to support
1527                  * the check for values being the same in
1528                  * replmd_update_rpmd_element()
1529                  */
1530                 ret = dsdb_module_search_dn(module, msg, &res, msg->dn, attrs,
1531                                             DSDB_FLAG_NEXT_MODULE |
1532                                             DSDB_SEARCH_SHOW_RECYCLED |
1533                                             DSDB_SEARCH_SHOW_EXTENDED_DN |
1534                                             DSDB_SEARCH_SHOW_DN_IN_STORAGE_FORMAT |
1535                                             DSDB_SEARCH_REVEAL_INTERNALS, req);
1536                 if (ret != LDB_SUCCESS) {
1537                         return ret;
1538                 }
1539
1540                 omd_value = ldb_msg_find_ldb_val(res->msgs[0], "replPropertyMetaData");
1541                 if (!omd_value) {
1542                         DEBUG(0,(__location__ ": Object %s does not have a replPropertyMetaData attribute\n",
1543                                  ldb_dn_get_linearized(msg->dn)));
1544                         return LDB_ERR_OPERATIONS_ERROR;
1545                 }
1546
1547                 ndr_err = ndr_pull_struct_blob(omd_value, msg, &omd,
1548                                                (ndr_pull_flags_fn_t)ndr_pull_replPropertyMetaDataBlob);
1549                 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
1550                         DEBUG(0,(__location__ ": Failed to parse replPropertyMetaData for %s\n",
1551                                  ldb_dn_get_linearized(msg->dn)));
1552                         return LDB_ERR_OPERATIONS_ERROR;
1553                 }
1554
1555                 if (omd.version != 1) {
1556                         DEBUG(0,(__location__ ": bad version %u in replPropertyMetaData for %s\n",
1557                                  omd.version, ldb_dn_get_linearized(msg->dn)));
1558                         return LDB_ERR_OPERATIONS_ERROR;
1559                 }
1560
1561                 for (i=0; i<msg->num_elements; i++) {
1562                         struct ldb_message_element *old_el;
1563                         old_el = ldb_msg_find_element(res->msgs[0], msg->elements[i].name);
1564                         ret = replmd_update_rpmd_element(ldb, msg, &msg->elements[i], old_el, &omd, schema, seq_num,
1565                                                          our_invocation_id,
1566                                                          now, is_schema_nc,
1567                                                          req);
1568                         if (ret != LDB_SUCCESS) {
1569                                 return ret;
1570                         }
1571
1572                         if (!*is_urgent && (situation == REPL_URGENT_ON_UPDATE)) {
1573                                 *is_urgent = replmd_check_urgent_attribute(&msg->elements[i]);
1574                         }
1575
1576                 }
1577         }
1578
1579         /*
1580          * Assert that we have an objectClass attribute - this is major
1581          * corruption if we don't have this!
1582          */
1583         objectclass_el = ldb_msg_find_element(res->msgs[0], "objectClass");
1584         if (objectclass_el != NULL) {
1585                 /*
1586                  * Now check if this objectClass means we need to do urgent replication
1587                  */
1588                 if (!*is_urgent && replmd_check_urgent_objectclass(objectclass_el,
1589                                                                    situation)) {
1590                         *is_urgent = true;
1591                 }
1592         } else if (!ldb_request_get_control(req, DSDB_CONTROL_DBCHECK)) {
1593                 ldb_asprintf_errstring(ldb, __location__
1594                                        ": objectClass missing on %s\n",
1595                                        ldb_dn_get_linearized(msg->dn));
1596                 return LDB_ERR_OBJECT_CLASS_VIOLATION;
1597         }
1598
1599         /*
1600          * replmd_update_rpmd_element has done an update if the
1601          * seq_num is set
1602          */
1603         if (*seq_num != 0 || rmd_is_just_resorted == true) {
1604                 struct ldb_val *md_value;
1605                 struct ldb_message_element *el;
1606
1607                 /*if we are RODC and this is a DRSR update then its ok*/
1608                 if (!ldb_request_get_control(req, DSDB_CONTROL_REPLICATED_UPDATE_OID)
1609                     && !ldb_request_get_control(req, DSDB_CONTROL_DBCHECK_MODIFY_RO_REPLICA)) {
1610                         unsigned instanceType;
1611
1612                         ret = samdb_rodc(ldb, rodc);
1613                         if (ret != LDB_SUCCESS) {
1614                                 DEBUG(4, (__location__ ": unable to tell if we are an RODC\n"));
1615                         } else if (*rodc) {
1616                                 ldb_set_errstring(ldb, "RODC modify is forbidden!");
1617                                 return LDB_ERR_REFERRAL;
1618                         }
1619
1620                         instanceType = ldb_msg_find_attr_as_uint(res->msgs[0], "instanceType", INSTANCE_TYPE_WRITE);
1621                         if (!(instanceType & INSTANCE_TYPE_WRITE)) {
1622                                 return ldb_error(ldb, LDB_ERR_UNWILLING_TO_PERFORM,
1623                                                  "cannot change replicated attribute on partial replica");
1624                         }
1625                 }
1626
1627                 md_value = talloc(msg, struct ldb_val);
1628                 if (md_value == NULL) {
1629                         ldb_oom(ldb);
1630                         return LDB_ERR_OPERATIONS_ERROR;
1631                 }
1632
1633                 ret = replmd_replPropertyMetaDataCtr1_sort_and_verify(ldb, &omd.ctr.ctr1, msg->dn);
1634                 if (ret != LDB_SUCCESS) {
1635                         ldb_asprintf_errstring(ldb, "%s: %s", __func__, ldb_errstring(ldb));
1636                         return ret;
1637                 }
1638
1639                 ndr_err = ndr_push_struct_blob(md_value, msg, &omd,
1640                                                (ndr_push_flags_fn_t)ndr_push_replPropertyMetaDataBlob);
1641                 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
1642                         DEBUG(0,(__location__ ": Failed to marshall replPropertyMetaData for %s\n",
1643                                  ldb_dn_get_linearized(msg->dn)));
1644                         return LDB_ERR_OPERATIONS_ERROR;
1645                 }
1646
1647                 ret = ldb_msg_add_empty(msg, "replPropertyMetaData", LDB_FLAG_MOD_REPLACE, &el);
1648                 if (ret != LDB_SUCCESS) {
1649                         DEBUG(0,(__location__ ": Failed to add updated replPropertyMetaData %s\n",
1650                                  ldb_dn_get_linearized(msg->dn)));
1651                         return ret;
1652                 }
1653
1654                 el->num_values = 1;
1655                 el->values = md_value;
1656         }
1657
1658         return LDB_SUCCESS;
1659 }
1660
1661 struct parsed_dn {
1662         struct dsdb_dn *dsdb_dn;
1663         struct GUID guid;
1664         struct ldb_val *v;
1665 };
1666
1667 static int parsed_dn_compare(struct parsed_dn *pdn1, struct parsed_dn *pdn2)
1668 {
1669         return GUID_compare(&pdn1->guid, &pdn2->guid);
1670 }
1671
1672 static int GUID_compare_struct(struct GUID *g1, struct GUID g2)
1673 {
1674         return GUID_compare(g1, &g2);
1675 }
1676
1677 static struct parsed_dn *parsed_dn_find(struct parsed_dn *pdn,
1678                                         unsigned int count, struct GUID *guid,
1679                                         struct ldb_dn *dn)
1680 {
1681         struct parsed_dn *ret;
1682         unsigned int i;
1683         if (dn && GUID_all_zero(guid)) {
1684                 /* when updating a link using DRS, we sometimes get a
1685                    NULL GUID. We then need to try and match by DN */
1686                 for (i=0; i<count; i++) {
1687                         if (ldb_dn_compare(pdn[i].dsdb_dn->dn, dn) == 0) {
1688                                 dsdb_get_extended_dn_guid(pdn[i].dsdb_dn->dn, guid, "GUID");
1689                                 return &pdn[i];
1690                         }
1691                 }
1692                 return NULL;
1693         }
1694         BINARY_ARRAY_SEARCH(pdn, count, guid, guid, GUID_compare_struct, ret);
1695         return ret;
1696 }
1697
1698 /*
1699   get a series of message element values as an array of DNs and GUIDs
1700   the result is sorted by GUID
1701  */
1702 static int get_parsed_dns(struct ldb_module *module, TALLOC_CTX *mem_ctx,
1703                           struct ldb_message_element *el, struct parsed_dn **pdn,
1704                           const char *ldap_oid, struct ldb_request *parent)
1705 {
1706         unsigned int i;
1707         struct ldb_context *ldb = ldb_module_get_ctx(module);
1708
1709         if (el == NULL) {
1710                 *pdn = NULL;
1711                 return LDB_SUCCESS;
1712         }
1713
1714         (*pdn) = talloc_array(mem_ctx, struct parsed_dn, el->num_values);
1715         if (!*pdn) {
1716                 ldb_module_oom(module);
1717                 return LDB_ERR_OPERATIONS_ERROR;
1718         }
1719
1720         for (i=0; i<el->num_values; i++) {
1721                 struct ldb_val *v = &el->values[i];
1722                 NTSTATUS status;
1723                 struct ldb_dn *dn;
1724                 struct parsed_dn *p;
1725
1726                 p = &(*pdn)[i];
1727
1728                 p->dsdb_dn = dsdb_dn_parse(*pdn, ldb, v, ldap_oid);
1729                 if (p->dsdb_dn == NULL) {
1730                         return LDB_ERR_INVALID_DN_SYNTAX;
1731                 }
1732
1733                 dn = p->dsdb_dn->dn;
1734
1735                 status = dsdb_get_extended_dn_guid(dn, &p->guid, "GUID");
1736                 if (NT_STATUS_EQUAL(status, NT_STATUS_OBJECT_NAME_NOT_FOUND)) {
1737                         /* we got a DN without a GUID - go find the GUID */
1738                         int ret = dsdb_module_guid_by_dn(module, dn, &p->guid, parent);
1739                         if (ret != LDB_SUCCESS) {
1740                                 ldb_asprintf_errstring(ldb, "Unable to find GUID for DN %s\n",
1741                                                        ldb_dn_get_linearized(dn));
1742                                 if (ret == LDB_ERR_NO_SUCH_OBJECT &&
1743                                     LDB_FLAG_MOD_TYPE(el->flags) == LDB_FLAG_MOD_DELETE &&
1744                                     ldb_attr_cmp(el->name, "member") == 0) {
1745                                         return LDB_ERR_UNWILLING_TO_PERFORM;
1746                                 }
1747                                 return ret;
1748                         }
1749                         ret = dsdb_set_extended_dn_guid(dn, &p->guid, "GUID");
1750                         if (ret != LDB_SUCCESS) {
1751                                 return ret;
1752                         }
1753                 } else if (!NT_STATUS_IS_OK(status)) {
1754                         return LDB_ERR_OPERATIONS_ERROR;
1755                 }
1756
1757                 /* keep a pointer to the original ldb_val */
1758                 p->v = v;
1759         }
1760
1761         TYPESAFE_QSORT(*pdn, el->num_values, parsed_dn_compare);
1762
1763         return LDB_SUCCESS;
1764 }
1765
1766 /*
1767   build a new extended DN, including all meta data fields
1768
1769   RMD_FLAGS           = DSDB_RMD_FLAG_* bits
1770   RMD_ADDTIME         = originating_add_time
1771   RMD_INVOCID         = originating_invocation_id
1772   RMD_CHANGETIME      = originating_change_time
1773   RMD_ORIGINATING_USN = originating_usn
1774   RMD_LOCAL_USN       = local_usn
1775   RMD_VERSION         = version
1776  */
1777 static int replmd_build_la_val(TALLOC_CTX *mem_ctx, struct ldb_val *v, struct dsdb_dn *dsdb_dn,
1778                                const struct GUID *invocation_id, uint64_t seq_num,
1779                                uint64_t local_usn, NTTIME nttime, uint32_t version, bool deleted)
1780 {
1781         struct ldb_dn *dn = dsdb_dn->dn;
1782         const char *tstring, *usn_string, *flags_string;
1783         struct ldb_val tval;
1784         struct ldb_val iid;
1785         struct ldb_val usnv, local_usnv;
1786         struct ldb_val vers, flagsv;
1787         NTSTATUS status;
1788         int ret;
1789         const char *dnstring;
1790         char *vstring;
1791         uint32_t rmd_flags = deleted?DSDB_RMD_FLAG_DELETED:0;
1792
1793         tstring = talloc_asprintf(mem_ctx, "%llu", (unsigned long long)nttime);
1794         if (!tstring) {
1795                 return LDB_ERR_OPERATIONS_ERROR;
1796         }
1797         tval = data_blob_string_const(tstring);
1798
1799         usn_string = talloc_asprintf(mem_ctx, "%llu", (unsigned long long)seq_num);
1800         if (!usn_string) {
1801                 return LDB_ERR_OPERATIONS_ERROR;
1802         }
1803         usnv = data_blob_string_const(usn_string);
1804
1805         usn_string = talloc_asprintf(mem_ctx, "%llu", (unsigned long long)local_usn);
1806         if (!usn_string) {
1807                 return LDB_ERR_OPERATIONS_ERROR;
1808         }
1809         local_usnv = data_blob_string_const(usn_string);
1810
1811         vstring = talloc_asprintf(mem_ctx, "%lu", (unsigned long)version);
1812         if (!vstring) {
1813                 return LDB_ERR_OPERATIONS_ERROR;
1814         }
1815         vers = data_blob_string_const(vstring);
1816
1817         status = GUID_to_ndr_blob(invocation_id, dn, &iid);
1818         if (!NT_STATUS_IS_OK(status)) {
1819                 return LDB_ERR_OPERATIONS_ERROR;
1820         }
1821
1822         flags_string = talloc_asprintf(mem_ctx, "%u", rmd_flags);
1823         if (!flags_string) {
1824                 return LDB_ERR_OPERATIONS_ERROR;
1825         }
1826         flagsv = data_blob_string_const(flags_string);
1827
1828         ret = ldb_dn_set_extended_component(dn, "RMD_FLAGS", &flagsv);
1829         if (ret != LDB_SUCCESS) return ret;
1830         ret = ldb_dn_set_extended_component(dn, "RMD_ADDTIME", &tval);
1831         if (ret != LDB_SUCCESS) return ret;
1832         ret = ldb_dn_set_extended_component(dn, "RMD_INVOCID", &iid);
1833         if (ret != LDB_SUCCESS) return ret;
1834         ret = ldb_dn_set_extended_component(dn, "RMD_CHANGETIME", &tval);
1835         if (ret != LDB_SUCCESS) return ret;
1836         ret = ldb_dn_set_extended_component(dn, "RMD_LOCAL_USN", &local_usnv);
1837         if (ret != LDB_SUCCESS) return ret;
1838         ret = ldb_dn_set_extended_component(dn, "RMD_ORIGINATING_USN", &usnv);
1839         if (ret != LDB_SUCCESS) return ret;
1840         ret = ldb_dn_set_extended_component(dn, "RMD_VERSION", &vers);
1841         if (ret != LDB_SUCCESS) return ret;
1842
1843         dnstring = dsdb_dn_get_extended_linearized(mem_ctx, dsdb_dn, 1);
1844         if (dnstring == NULL) {
1845                 return LDB_ERR_OPERATIONS_ERROR;
1846         }
1847         *v = data_blob_string_const(dnstring);
1848
1849         return LDB_SUCCESS;
1850 }
1851
1852 static int replmd_update_la_val(TALLOC_CTX *mem_ctx, struct ldb_val *v, struct dsdb_dn *dsdb_dn,
1853                                 struct dsdb_dn *old_dsdb_dn, const struct GUID *invocation_id,
1854                                 uint64_t seq_num, uint64_t local_usn, NTTIME nttime,
1855                                 uint32_t version, bool deleted);
1856
1857 /*
1858   check if any links need upgrading from w2k format
1859
1860   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.
1861  */
1862 static int replmd_check_upgrade_links(struct parsed_dn *dns, uint32_t count, struct ldb_message_element *parent_ctx, const struct GUID *invocation_id)
1863 {
1864         uint32_t i;
1865         for (i=0; i<count; i++) {
1866                 NTSTATUS status;
1867                 uint32_t version;
1868                 int ret;
1869
1870                 status = dsdb_get_extended_dn_uint32(dns[i].dsdb_dn->dn, &version, "RMD_VERSION");
1871                 if (!NT_STATUS_EQUAL(status, NT_STATUS_OBJECT_NAME_NOT_FOUND)) {
1872                         continue;
1873                 }
1874
1875                 /* it's an old one that needs upgrading */
1876                 ret = replmd_update_la_val(parent_ctx->values, dns[i].v, dns[i].dsdb_dn, dns[i].dsdb_dn, invocation_id,
1877                                            1, 1, 0, 0, false);
1878                 if (ret != LDB_SUCCESS) {
1879                         return ret;
1880                 }
1881         }
1882         return LDB_SUCCESS;
1883 }
1884
1885 /*
1886   update an extended DN, including all meta data fields
1887
1888   see replmd_build_la_val for value names
1889  */
1890 static int replmd_update_la_val(TALLOC_CTX *mem_ctx, struct ldb_val *v, struct dsdb_dn *dsdb_dn,
1891                                 struct dsdb_dn *old_dsdb_dn, const struct GUID *invocation_id,
1892                                 uint64_t usn, uint64_t local_usn, NTTIME nttime,
1893                                 uint32_t version, bool deleted)
1894 {
1895         struct ldb_dn *dn = dsdb_dn->dn;
1896         const char *tstring, *usn_string, *flags_string;
1897         struct ldb_val tval;
1898         struct ldb_val iid;
1899         struct ldb_val usnv, local_usnv;
1900         struct ldb_val vers, flagsv;
1901         const struct ldb_val *old_addtime;
1902         uint32_t old_version;
1903         NTSTATUS status;
1904         int ret;
1905         const char *dnstring;
1906         char *vstring;
1907         uint32_t rmd_flags = deleted?DSDB_RMD_FLAG_DELETED:0;
1908
1909         tstring = talloc_asprintf(mem_ctx, "%llu", (unsigned long long)nttime);
1910         if (!tstring) {
1911                 return LDB_ERR_OPERATIONS_ERROR;
1912         }
1913         tval = data_blob_string_const(tstring);
1914
1915         usn_string = talloc_asprintf(mem_ctx, "%llu", (unsigned long long)usn);
1916         if (!usn_string) {
1917                 return LDB_ERR_OPERATIONS_ERROR;
1918         }
1919         usnv = data_blob_string_const(usn_string);
1920
1921         usn_string = talloc_asprintf(mem_ctx, "%llu", (unsigned long long)local_usn);
1922         if (!usn_string) {
1923                 return LDB_ERR_OPERATIONS_ERROR;
1924         }
1925         local_usnv = data_blob_string_const(usn_string);
1926
1927         status = GUID_to_ndr_blob(invocation_id, dn, &iid);
1928         if (!NT_STATUS_IS_OK(status)) {
1929                 return LDB_ERR_OPERATIONS_ERROR;
1930         }
1931
1932         flags_string = talloc_asprintf(mem_ctx, "%u", rmd_flags);
1933         if (!flags_string) {
1934                 return LDB_ERR_OPERATIONS_ERROR;
1935         }
1936         flagsv = data_blob_string_const(flags_string);
1937
1938         ret = ldb_dn_set_extended_component(dn, "RMD_FLAGS", &flagsv);
1939         if (ret != LDB_SUCCESS) return ret;
1940
1941         /* get the ADDTIME from the original */
1942         old_addtime = ldb_dn_get_extended_component(old_dsdb_dn->dn, "RMD_ADDTIME");
1943         if (old_addtime == NULL) {
1944                 old_addtime = &tval;
1945         }
1946         if (dsdb_dn != old_dsdb_dn ||
1947             ldb_dn_get_extended_component(dn, "RMD_ADDTIME") == NULL) {
1948                 ret = ldb_dn_set_extended_component(dn, "RMD_ADDTIME", old_addtime);
1949                 if (ret != LDB_SUCCESS) return ret;
1950         }
1951
1952         /* use our invocation id */
1953         ret = ldb_dn_set_extended_component(dn, "RMD_INVOCID", &iid);
1954         if (ret != LDB_SUCCESS) return ret;
1955
1956         /* changetime is the current time */
1957         ret = ldb_dn_set_extended_component(dn, "RMD_CHANGETIME", &tval);
1958         if (ret != LDB_SUCCESS) return ret;
1959
1960         /* update the USN */
1961         ret = ldb_dn_set_extended_component(dn, "RMD_ORIGINATING_USN", &usnv);
1962         if (ret != LDB_SUCCESS) return ret;
1963
1964         ret = ldb_dn_set_extended_component(dn, "RMD_LOCAL_USN", &local_usnv);
1965         if (ret != LDB_SUCCESS) return ret;
1966
1967         /* increase the version by 1 */
1968         status = dsdb_get_extended_dn_uint32(old_dsdb_dn->dn, &old_version, "RMD_VERSION");
1969         if (NT_STATUS_IS_OK(status) && old_version >= version) {
1970                 version = old_version+1;
1971         }
1972         vstring = talloc_asprintf(dn, "%lu", (unsigned long)version);
1973         vers = data_blob_string_const(vstring);
1974         ret = ldb_dn_set_extended_component(dn, "RMD_VERSION", &vers);
1975         if (ret != LDB_SUCCESS) return ret;
1976
1977         dnstring = dsdb_dn_get_extended_linearized(mem_ctx, dsdb_dn, 1);
1978         if (dnstring == NULL) {
1979                 return LDB_ERR_OPERATIONS_ERROR;
1980         }
1981         *v = data_blob_string_const(dnstring);
1982
1983         return LDB_SUCCESS;
1984 }
1985
1986 /*
1987   handle adding a linked attribute
1988  */
1989 static int replmd_modify_la_add(struct ldb_module *module,
1990                                 const struct dsdb_schema *schema,
1991                                 struct ldb_message *msg,
1992                                 struct ldb_message_element *el,
1993                                 struct ldb_message_element *old_el,
1994                                 const struct dsdb_attribute *schema_attr,
1995                                 uint64_t seq_num,
1996                                 time_t t,
1997                                 struct GUID *msg_guid,
1998                                 struct ldb_request *parent)
1999 {
2000         unsigned int i;
2001         struct parsed_dn *dns, *old_dns;
2002         TALLOC_CTX *tmp_ctx = talloc_new(msg);
2003         int ret;
2004         struct ldb_val *new_values = NULL;
2005         unsigned int num_new_values = 0;
2006         unsigned old_num_values = old_el?old_el->num_values:0;
2007         const struct GUID *invocation_id;
2008         struct ldb_context *ldb = ldb_module_get_ctx(module);
2009         NTTIME now;
2010
2011         unix_to_nt_time(&now, t);
2012
2013         ret = get_parsed_dns(module, tmp_ctx, el, &dns, schema_attr->syntax->ldap_oid, parent);
2014         if (ret != LDB_SUCCESS) {
2015                 talloc_free(tmp_ctx);
2016                 return ret;
2017         }
2018
2019         ret = get_parsed_dns(module, tmp_ctx, old_el, &old_dns, schema_attr->syntax->ldap_oid, parent);
2020         if (ret != LDB_SUCCESS) {
2021                 talloc_free(tmp_ctx);
2022                 return ret;
2023         }
2024
2025         invocation_id = samdb_ntds_invocation_id(ldb);
2026         if (!invocation_id) {
2027                 talloc_free(tmp_ctx);
2028                 return LDB_ERR_OPERATIONS_ERROR;
2029         }
2030
2031         ret = replmd_check_upgrade_links(old_dns, old_num_values, old_el, invocation_id);
2032         if (ret != LDB_SUCCESS) {
2033                 talloc_free(tmp_ctx);
2034                 return ret;
2035         }
2036
2037         /* for each new value, see if it exists already with the same GUID */
2038         for (i=0; i<el->num_values; i++) {
2039                 struct parsed_dn *p = parsed_dn_find(old_dns, old_num_values, &dns[i].guid, NULL);
2040                 if (p == NULL) {
2041                         /* this is a new linked attribute value */
2042                         new_values = talloc_realloc(tmp_ctx, new_values, struct ldb_val, num_new_values+1);
2043                         if (new_values == NULL) {
2044                                 ldb_module_oom(module);
2045                                 talloc_free(tmp_ctx);
2046                                 return LDB_ERR_OPERATIONS_ERROR;
2047                         }
2048                         ret = replmd_build_la_val(new_values, &new_values[num_new_values], dns[i].dsdb_dn,
2049                                                   invocation_id, seq_num, seq_num, now, 0, false);
2050                         if (ret != LDB_SUCCESS) {
2051                                 talloc_free(tmp_ctx);
2052                                 return ret;
2053                         }
2054                         num_new_values++;
2055                 } else {
2056                         /* this is only allowed if the GUID was
2057                            previously deleted. */
2058                         uint32_t rmd_flags = dsdb_dn_rmd_flags(p->dsdb_dn->dn);
2059
2060                         if (!(rmd_flags & DSDB_RMD_FLAG_DELETED)) {
2061                                 struct GUID_txt_buf guid_str;
2062                                 ldb_asprintf_errstring(ldb, "Attribute %s already exists for target GUID %s",
2063                                                        el->name, GUID_buf_string(&p->guid, &guid_str));
2064                                 talloc_free(tmp_ctx);
2065                                 /* error codes for 'member' need to be
2066                                    special cased */
2067                                 if (ldb_attr_cmp(el->name, "member") == 0) {
2068                                         return LDB_ERR_ENTRY_ALREADY_EXISTS;
2069                                 } else {
2070                                         return LDB_ERR_ATTRIBUTE_OR_VALUE_EXISTS;
2071                                 }
2072                         }
2073                         ret = replmd_update_la_val(old_el->values, p->v, dns[i].dsdb_dn, p->dsdb_dn,
2074                                                    invocation_id, seq_num, seq_num, now, 0, false);
2075                         if (ret != LDB_SUCCESS) {
2076                                 talloc_free(tmp_ctx);
2077                                 return ret;
2078                         }
2079                 }
2080
2081                 ret = replmd_add_backlink(module, schema, msg_guid, &dns[i].guid, true, schema_attr, true);
2082                 if (ret != LDB_SUCCESS) {
2083                         talloc_free(tmp_ctx);
2084                         return ret;
2085                 }
2086         }
2087
2088         /* add the new ones on to the end of the old values, constructing a new el->values */
2089         el->values = talloc_realloc(msg->elements, old_el?old_el->values:NULL,
2090                                     struct ldb_val,
2091                                     old_num_values+num_new_values);
2092         if (el->values == NULL) {
2093                 ldb_module_oom(module);
2094                 return LDB_ERR_OPERATIONS_ERROR;
2095         }
2096
2097         memcpy(&el->values[old_num_values], new_values, num_new_values*sizeof(struct ldb_val));
2098         el->num_values = old_num_values + num_new_values;
2099
2100         talloc_steal(msg->elements, el->values);
2101         talloc_steal(el->values, new_values);
2102
2103         talloc_free(tmp_ctx);
2104
2105         /* we now tell the backend to replace all existing values
2106            with the one we have constructed */
2107         el->flags = LDB_FLAG_MOD_REPLACE;
2108
2109         return LDB_SUCCESS;
2110 }
2111
2112
2113 /*
2114   handle deleting all active linked attributes
2115  */
2116 static int replmd_modify_la_delete(struct ldb_module *module,
2117                                    const struct dsdb_schema *schema,
2118                                    struct ldb_message *msg,
2119                                    struct ldb_message_element *el,
2120                                    struct ldb_message_element *old_el,
2121                                    const struct dsdb_attribute *schema_attr,
2122                                    uint64_t seq_num,
2123                                    time_t t,
2124                                    struct GUID *msg_guid,
2125                                    struct ldb_request *parent)
2126 {
2127         unsigned int i;
2128         struct parsed_dn *dns, *old_dns;
2129         TALLOC_CTX *tmp_ctx = talloc_new(msg);
2130         int ret;
2131         const struct GUID *invocation_id;
2132         struct ldb_context *ldb = ldb_module_get_ctx(module);
2133         NTTIME now;
2134
2135         unix_to_nt_time(&now, t);
2136
2137         /* check if there is nothing to delete */
2138         if ((!old_el || old_el->num_values == 0) &&
2139             el->num_values == 0) {
2140                 return LDB_SUCCESS;
2141         }
2142
2143         if (!old_el || old_el->num_values == 0) {
2144                 return LDB_ERR_NO_SUCH_ATTRIBUTE;
2145         }
2146
2147         ret = get_parsed_dns(module, tmp_ctx, el, &dns, schema_attr->syntax->ldap_oid, parent);
2148         if (ret != LDB_SUCCESS) {
2149                 talloc_free(tmp_ctx);
2150                 return ret;
2151         }
2152
2153         ret = get_parsed_dns(module, tmp_ctx, old_el, &old_dns, schema_attr->syntax->ldap_oid, parent);
2154         if (ret != LDB_SUCCESS) {
2155                 talloc_free(tmp_ctx);
2156                 return ret;
2157         }
2158
2159         invocation_id = samdb_ntds_invocation_id(ldb);
2160         if (!invocation_id) {
2161                 return LDB_ERR_OPERATIONS_ERROR;
2162         }
2163
2164         ret = replmd_check_upgrade_links(old_dns, old_el->num_values, old_el, invocation_id);
2165         if (ret != LDB_SUCCESS) {
2166                 talloc_free(tmp_ctx);
2167                 return ret;
2168         }
2169
2170         el->values = NULL;
2171
2172         /* see if we are being asked to delete any links that
2173            don't exist or are already deleted */
2174         for (i=0; i<el->num_values; i++) {
2175                 struct parsed_dn *p = &dns[i];
2176                 struct parsed_dn *p2;
2177                 uint32_t rmd_flags;
2178
2179                 p2 = parsed_dn_find(old_dns, old_el->num_values, &p->guid, NULL);
2180                 if (!p2) {
2181                         struct GUID_txt_buf buf;
2182                         ldb_asprintf_errstring(ldb, "Attribute %s doesn't exist for target GUID %s",
2183                                                el->name, GUID_buf_string(&p->guid, &buf));
2184                         if (ldb_attr_cmp(el->name, "member") == 0) {
2185                                 return LDB_ERR_UNWILLING_TO_PERFORM;
2186                         } else {
2187                                 return LDB_ERR_NO_SUCH_ATTRIBUTE;
2188                         }
2189                 }
2190                 rmd_flags = dsdb_dn_rmd_flags(p2->dsdb_dn->dn);
2191                 if (rmd_flags & DSDB_RMD_FLAG_DELETED) {
2192                         struct GUID_txt_buf buf;
2193                         ldb_asprintf_errstring(ldb, "Attribute %s already deleted for target GUID %s",
2194                                                el->name, GUID_buf_string(&p->guid, &buf));
2195                         if (ldb_attr_cmp(el->name, "member") == 0) {
2196                                 return LDB_ERR_UNWILLING_TO_PERFORM;
2197                         } else {
2198                                 return LDB_ERR_NO_SUCH_ATTRIBUTE;
2199                         }
2200                 }
2201         }
2202
2203         /* for each new value, see if it exists already with the same GUID
2204            if it is not already deleted and matches the delete list then delete it
2205         */
2206         for (i=0; i<old_el->num_values; i++) {
2207                 struct parsed_dn *p = &old_dns[i];
2208                 uint32_t rmd_flags;
2209
2210                 if (el->num_values && parsed_dn_find(dns, el->num_values, &p->guid, NULL) == NULL) {
2211                         continue;
2212                 }
2213
2214                 rmd_flags = dsdb_dn_rmd_flags(p->dsdb_dn->dn);
2215                 if (rmd_flags & DSDB_RMD_FLAG_DELETED) continue;
2216
2217                 ret = replmd_update_la_val(old_el->values, p->v, p->dsdb_dn, p->dsdb_dn,
2218                                            invocation_id, seq_num, seq_num, now, 0, true);
2219                 if (ret != LDB_SUCCESS) {
2220                         talloc_free(tmp_ctx);
2221                         return ret;
2222                 }
2223
2224                 ret = replmd_add_backlink(module, schema, msg_guid, &old_dns[i].guid, false, schema_attr, true);
2225                 if (ret != LDB_SUCCESS) {
2226                         talloc_free(tmp_ctx);
2227                         return ret;
2228                 }
2229         }
2230
2231         el->values = talloc_steal(msg->elements, old_el->values);
2232         el->num_values = old_el->num_values;
2233
2234         talloc_free(tmp_ctx);
2235
2236         /* we now tell the backend to replace all existing values
2237            with the one we have constructed */
2238         el->flags = LDB_FLAG_MOD_REPLACE;
2239
2240         return LDB_SUCCESS;
2241 }
2242
2243 /*
2244   handle replacing a linked attribute
2245  */
2246 static int replmd_modify_la_replace(struct ldb_module *module,
2247                                     const struct dsdb_schema *schema,
2248                                     struct ldb_message *msg,
2249                                     struct ldb_message_element *el,
2250                                     struct ldb_message_element *old_el,
2251                                     const struct dsdb_attribute *schema_attr,
2252                                     uint64_t seq_num,
2253                                     time_t t,
2254                                     struct GUID *msg_guid,
2255                                     struct ldb_request *parent)
2256 {
2257         unsigned int i;
2258         struct parsed_dn *dns, *old_dns;
2259         TALLOC_CTX *tmp_ctx = talloc_new(msg);
2260         int ret;
2261         const struct GUID *invocation_id;
2262         struct ldb_context *ldb = ldb_module_get_ctx(module);
2263         struct ldb_val *new_values = NULL;
2264         unsigned int num_new_values = 0;
2265         unsigned int old_num_values = old_el?old_el->num_values:0;
2266         NTTIME now;
2267
2268         unix_to_nt_time(&now, t);
2269
2270         /* check if there is nothing to replace */
2271         if ((!old_el || old_el->num_values == 0) &&
2272             el->num_values == 0) {
2273                 return LDB_SUCCESS;
2274         }
2275
2276         ret = get_parsed_dns(module, tmp_ctx, el, &dns, schema_attr->syntax->ldap_oid, parent);
2277         if (ret != LDB_SUCCESS) {
2278                 talloc_free(tmp_ctx);
2279                 return ret;
2280         }
2281
2282         ret = get_parsed_dns(module, tmp_ctx, old_el, &old_dns, schema_attr->syntax->ldap_oid, parent);
2283         if (ret != LDB_SUCCESS) {
2284                 talloc_free(tmp_ctx);
2285                 return ret;
2286         }
2287
2288         invocation_id = samdb_ntds_invocation_id(ldb);
2289         if (!invocation_id) {
2290                 return LDB_ERR_OPERATIONS_ERROR;
2291         }
2292
2293         ret = replmd_check_upgrade_links(old_dns, old_num_values, old_el, invocation_id);
2294         if (ret != LDB_SUCCESS) {
2295                 talloc_free(tmp_ctx);
2296                 return ret;
2297         }
2298
2299         /* mark all the old ones as deleted */
2300         for (i=0; i<old_num_values; i++) {
2301                 struct parsed_dn *old_p = &old_dns[i];
2302                 struct parsed_dn *p;
2303                 uint32_t rmd_flags = dsdb_dn_rmd_flags(old_p->dsdb_dn->dn);
2304
2305                 if (rmd_flags & DSDB_RMD_FLAG_DELETED) continue;
2306
2307                 ret = replmd_add_backlink(module, schema, msg_guid, &old_dns[i].guid, false, schema_attr, false);
2308                 if (ret != LDB_SUCCESS) {
2309                         talloc_free(tmp_ctx);
2310                         return ret;
2311                 }
2312
2313                 p = parsed_dn_find(dns, el->num_values, &old_p->guid, NULL);
2314                 if (p) {
2315                         /* we don't delete it if we are re-adding it */
2316                         continue;
2317                 }
2318
2319                 ret = replmd_update_la_val(old_el->values, old_p->v, old_p->dsdb_dn, old_p->dsdb_dn,
2320                                            invocation_id, seq_num, seq_num, now, 0, true);
2321                 if (ret != LDB_SUCCESS) {
2322                         talloc_free(tmp_ctx);
2323                         return ret;
2324                 }
2325         }
2326
2327         /* for each new value, either update its meta-data, or add it
2328          * to old_el
2329         */
2330         for (i=0; i<el->num_values; i++) {
2331                 struct parsed_dn *p = &dns[i], *old_p;
2332
2333                 if (old_dns &&
2334                     (old_p = parsed_dn_find(old_dns,
2335                                             old_num_values, &p->guid, NULL)) != NULL) {
2336                         /* update in place */
2337                         ret = replmd_update_la_val(old_el->values, old_p->v, p->dsdb_dn,
2338                                                    old_p->dsdb_dn, invocation_id,
2339                                                    seq_num, seq_num, now, 0, false);
2340                         if (ret != LDB_SUCCESS) {
2341                                 talloc_free(tmp_ctx);
2342                                 return ret;
2343                         }
2344                 } else {
2345                         /* add a new one */
2346                         new_values = talloc_realloc(tmp_ctx, new_values, struct ldb_val,
2347                                                     num_new_values+1);
2348                         if (new_values == NULL) {
2349                                 ldb_module_oom(module);
2350                                 talloc_free(tmp_ctx);
2351                                 return LDB_ERR_OPERATIONS_ERROR;
2352                         }
2353                         ret = replmd_build_la_val(new_values, &new_values[num_new_values], dns[i].dsdb_dn,
2354                                                   invocation_id, seq_num, seq_num, now, 0, false);
2355                         if (ret != LDB_SUCCESS) {
2356                                 talloc_free(tmp_ctx);
2357                                 return ret;
2358                         }
2359                         num_new_values++;
2360                 }
2361
2362                 ret = replmd_add_backlink(module, schema, msg_guid, &dns[i].guid, true, schema_attr, false);
2363                 if (ret != LDB_SUCCESS) {
2364                         talloc_free(tmp_ctx);
2365                         return ret;
2366                 }
2367         }
2368
2369         /* add the new values to the end of old_el */
2370         if (num_new_values != 0) {
2371                 el->values = talloc_realloc(msg->elements, old_el?old_el->values:NULL,
2372                                             struct ldb_val, old_num_values+num_new_values);
2373                 if (el->values == NULL) {
2374                         ldb_module_oom(module);
2375                         return LDB_ERR_OPERATIONS_ERROR;
2376                 }
2377                 memcpy(&el->values[old_num_values], &new_values[0],
2378                        sizeof(struct ldb_val)*num_new_values);
2379                 el->num_values = old_num_values + num_new_values;
2380                 talloc_steal(msg->elements, new_values);
2381         } else {
2382                 el->values = old_el->values;
2383                 el->num_values = old_el->num_values;
2384                 talloc_steal(msg->elements, el->values);
2385         }
2386
2387         talloc_free(tmp_ctx);
2388
2389         /* we now tell the backend to replace all existing values
2390            with the one we have constructed */
2391         el->flags = LDB_FLAG_MOD_REPLACE;
2392
2393         return LDB_SUCCESS;
2394 }
2395
2396
2397 /*
2398   handle linked attributes in modify requests
2399  */
2400 static int replmd_modify_handle_linked_attribs(struct ldb_module *module,
2401                                                struct ldb_message *msg,
2402                                                uint64_t seq_num, time_t t,
2403                                                struct ldb_request *parent)
2404 {
2405         struct ldb_result *res;
2406         unsigned int i;
2407         int ret;
2408         struct ldb_context *ldb = ldb_module_get_ctx(module);
2409         struct ldb_message *old_msg;
2410
2411         const struct dsdb_schema *schema;
2412         struct GUID old_guid;
2413
2414         if (seq_num == 0) {
2415                 /* there the replmd_update_rpmd code has already
2416                  * checked and saw that there are no linked
2417                  * attributes */
2418                 return LDB_SUCCESS;
2419         }
2420
2421         if (dsdb_functional_level(ldb) == DS_DOMAIN_FUNCTION_2000) {
2422                 /* don't do anything special for linked attributes */
2423                 return LDB_SUCCESS;
2424         }
2425
2426         ret = dsdb_module_search_dn(module, msg, &res, msg->dn, NULL,
2427                                     DSDB_FLAG_NEXT_MODULE |
2428                                     DSDB_SEARCH_SHOW_RECYCLED |
2429                                     DSDB_SEARCH_REVEAL_INTERNALS |
2430                                     DSDB_SEARCH_SHOW_DN_IN_STORAGE_FORMAT,
2431                                     parent);
2432         if (ret != LDB_SUCCESS) {
2433                 return ret;
2434         }
2435         schema = dsdb_get_schema(ldb, res);
2436         if (!schema) {
2437                 return LDB_ERR_OPERATIONS_ERROR;
2438         }
2439
2440         old_msg = res->msgs[0];
2441
2442         old_guid = samdb_result_guid(old_msg, "objectGUID");
2443
2444         for (i=0; i<msg->num_elements; i++) {
2445                 struct ldb_message_element *el = &msg->elements[i];
2446                 struct ldb_message_element *old_el, *new_el;
2447                 const struct dsdb_attribute *schema_attr
2448                         = dsdb_attribute_by_lDAPDisplayName(schema, el->name);
2449                 if (!schema_attr) {
2450                         ldb_asprintf_errstring(ldb,
2451                                                "%s: attribute %s is not a valid attribute in schema",
2452                                                __FUNCTION__, el->name);
2453                         return LDB_ERR_OBJECT_CLASS_VIOLATION;
2454                 }
2455                 if (schema_attr->linkID == 0) {
2456                         continue;
2457                 }
2458                 if ((schema_attr->linkID & 1) == 1) {
2459                         if (parent && ldb_request_get_control(parent, DSDB_CONTROL_DBCHECK)) {
2460                                 continue;
2461                         }
2462                         /* Odd is for the target.  Illegal to modify */
2463                         ldb_asprintf_errstring(ldb,
2464                                                "attribute %s must not be modified directly, it is a linked attribute", el->name);
2465                         return LDB_ERR_UNWILLING_TO_PERFORM;
2466                 }
2467                 old_el = ldb_msg_find_element(old_msg, el->name);
2468                 switch (el->flags & LDB_FLAG_MOD_MASK) {
2469                 case LDB_FLAG_MOD_REPLACE:
2470                         ret = replmd_modify_la_replace(module, schema, msg, el, old_el, schema_attr, seq_num, t, &old_guid, parent);
2471                         break;
2472                 case LDB_FLAG_MOD_DELETE:
2473                         ret = replmd_modify_la_delete(module, schema, msg, el, old_el, schema_attr, seq_num, t, &old_guid, parent);
2474                         break;
2475                 case LDB_FLAG_MOD_ADD:
2476                         ret = replmd_modify_la_add(module, schema, msg, el, old_el, schema_attr, seq_num, t, &old_guid, parent);
2477                         break;
2478                 default:
2479                         ldb_asprintf_errstring(ldb,
2480                                                "invalid flags 0x%x for %s linked attribute",
2481                                                el->flags, el->name);
2482                         return LDB_ERR_UNWILLING_TO_PERFORM;
2483                 }
2484                 if (dsdb_check_single_valued_link(schema_attr, el) != LDB_SUCCESS) {
2485                         ldb_asprintf_errstring(ldb,
2486                                                "Attribute %s is single valued but more than one value has been supplied",
2487                                                el->name);
2488                         return LDB_ERR_ATTRIBUTE_OR_VALUE_EXISTS;
2489                 } else {
2490                         el->flags |= LDB_FLAG_INTERNAL_DISABLE_SINGLE_VALUE_CHECK;
2491                 }
2492
2493
2494
2495                 if (ret != LDB_SUCCESS) {
2496                         return ret;
2497                 }
2498                 if (old_el) {
2499                         ldb_msg_remove_attr(old_msg, el->name);
2500                 }
2501                 ldb_msg_add_empty(old_msg, el->name, 0, &new_el);
2502                 new_el->num_values = el->num_values;
2503                 new_el->values = talloc_steal(msg->elements, el->values);
2504
2505                 /* TODO: this relises a bit too heavily on the exact
2506                    behaviour of ldb_msg_find_element and
2507                    ldb_msg_remove_element */
2508                 old_el = ldb_msg_find_element(msg, el->name);
2509                 if (old_el != el) {
2510                         ldb_msg_remove_element(msg, old_el);
2511                         i--;
2512                 }
2513         }
2514
2515         talloc_free(res);
2516         return ret;
2517 }
2518
2519
2520
2521 static int replmd_modify(struct ldb_module *module, struct ldb_request *req)
2522 {
2523         struct samldb_msds_intid_persistant *msds_intid_struct;
2524         struct ldb_context *ldb;
2525         struct replmd_replicated_request *ac;
2526         struct ldb_request *down_req;
2527         struct ldb_message *msg;
2528         time_t t = time(NULL);
2529         int ret;
2530         bool is_urgent = false, rodc = false;
2531         bool is_schema_nc = false;
2532         unsigned int functional_level;
2533         const struct ldb_message_element *guid_el = NULL;
2534         struct ldb_control *sd_propagation_control;
2535         struct replmd_private *replmd_private =
2536                 talloc_get_type(ldb_module_get_private(module), struct replmd_private);
2537
2538         /* do not manipulate our control entries */
2539         if (ldb_dn_is_special(req->op.mod.message->dn)) {
2540                 return ldb_next_request(module, req);
2541         }
2542
2543         sd_propagation_control = ldb_request_get_control(req,
2544                                         DSDB_CONTROL_SEC_DESC_PROPAGATION_OID);
2545         if (sd_propagation_control != NULL) {
2546                 if (req->op.mod.message->num_elements != 1) {
2547                         return ldb_module_operr(module);
2548                 }
2549                 ret = strcmp(req->op.mod.message->elements[0].name,
2550                              "nTSecurityDescriptor");
2551                 if (ret != 0) {
2552                         return ldb_module_operr(module);
2553                 }
2554
2555                 return ldb_next_request(module, req);
2556         }
2557
2558         ldb = ldb_module_get_ctx(module);
2559
2560         ldb_debug(ldb, LDB_DEBUG_TRACE, "replmd_modify\n");
2561
2562         guid_el = ldb_msg_find_element(req->op.mod.message, "objectGUID");
2563         if (guid_el != NULL) {
2564                 ldb_set_errstring(ldb,
2565                                   "replmd_modify: it's not allowed to change the objectGUID!");
2566                 return LDB_ERR_CONSTRAINT_VIOLATION;
2567         }
2568
2569         ac = replmd_ctx_init(module, req);
2570         if (ac == NULL) {
2571                 return ldb_module_oom(module);
2572         }
2573
2574         functional_level = dsdb_functional_level(ldb);
2575
2576         /* we have to copy the message as the caller might have it as a const */
2577         msg = ldb_msg_copy_shallow(ac, req->op.mod.message);
2578         if (msg == NULL) {
2579                 ldb_oom(ldb);
2580                 talloc_free(ac);
2581                 return LDB_ERR_OPERATIONS_ERROR;
2582         }
2583
2584         ldb_msg_remove_attr(msg, "whenChanged");
2585         ldb_msg_remove_attr(msg, "uSNChanged");
2586
2587         is_schema_nc = ldb_dn_compare_base(replmd_private->schema_dn, msg->dn) == 0;
2588
2589         ret = replmd_update_rpmd(module, ac->schema, req, NULL,
2590                                  msg, &ac->seq_num, t, is_schema_nc,
2591                                  &is_urgent, &rodc);
2592         if (rodc && (ret == LDB_ERR_REFERRAL)) {
2593                 struct loadparm_context *lp_ctx;
2594                 char *referral;
2595
2596                 lp_ctx = talloc_get_type(ldb_get_opaque(ldb, "loadparm"),
2597                                          struct loadparm_context);
2598
2599                 referral = talloc_asprintf(req,
2600                                            "ldap://%s/%s",
2601                                            lpcfg_dnsdomain(lp_ctx),
2602                                            ldb_dn_get_linearized(msg->dn));
2603                 ret = ldb_module_send_referral(req, referral);
2604                 talloc_free(ac);
2605                 return ret;
2606         }
2607
2608         if (ret != LDB_SUCCESS) {
2609                 talloc_free(ac);
2610                 return ret;
2611         }
2612
2613         ret = replmd_modify_handle_linked_attribs(module, msg, ac->seq_num, t, req);
2614         if (ret != LDB_SUCCESS) {
2615                 talloc_free(ac);
2616                 return ret;
2617         }
2618
2619         /* TODO:
2620          * - replace the old object with the newly constructed one
2621          */
2622
2623         ac->is_urgent = is_urgent;
2624
2625         ret = ldb_build_mod_req(&down_req, ldb, ac,
2626                                 msg,
2627                                 req->controls,
2628                                 ac, replmd_op_callback,
2629                                 req);
2630         LDB_REQ_SET_LOCATION(down_req);
2631         if (ret != LDB_SUCCESS) {
2632                 talloc_free(ac);
2633                 return ret;
2634         }
2635
2636         /* current partition control is needed by "replmd_op_callback" */
2637         if (ldb_request_get_control(req, DSDB_CONTROL_CURRENT_PARTITION_OID) == NULL) {
2638                 ret = ldb_request_add_control(down_req,
2639                                               DSDB_CONTROL_CURRENT_PARTITION_OID,
2640                                               false, NULL);
2641                 if (ret != LDB_SUCCESS) {
2642                         talloc_free(ac);
2643                         return ret;
2644                 }
2645         }
2646
2647         /* If we are in functional level 2000, then
2648          * replmd_modify_handle_linked_attribs will have done
2649          * nothing */
2650         if (functional_level == DS_DOMAIN_FUNCTION_2000) {
2651                 ret = ldb_request_add_control(down_req, DSDB_CONTROL_APPLY_LINKS, false, NULL);
2652                 if (ret != LDB_SUCCESS) {
2653                         talloc_free(ac);
2654                         return ret;
2655                 }
2656         }
2657
2658         talloc_steal(down_req, msg);
2659
2660         /* we only change whenChanged and uSNChanged if the seq_num
2661            has changed */
2662         if (ac->seq_num != 0) {
2663                 ret = add_time_element(msg, "whenChanged", t);
2664                 if (ret != LDB_SUCCESS) {
2665                         talloc_free(ac);
2666                         ldb_operr(ldb);
2667                         return ret;
2668                 }
2669
2670                 ret = add_uint64_element(ldb, msg, "uSNChanged", ac->seq_num);
2671                 if (ret != LDB_SUCCESS) {
2672                         talloc_free(ac);
2673                         ldb_operr(ldb);
2674                         return ret;
2675                 }
2676         }
2677
2678         if (!ldb_dn_compare_base(replmd_private->schema_dn, msg->dn)) {
2679                 /* Update the usn in the SAMLDB_MSDS_INTID_OPAQUE opaque */
2680                 msds_intid_struct = (struct samldb_msds_intid_persistant *) ldb_get_opaque(ldb, SAMLDB_MSDS_INTID_OPAQUE);
2681                 if (msds_intid_struct) {
2682                         msds_intid_struct->usn = ac->seq_num;
2683                 }
2684         }
2685
2686         /* go on with the call chain */
2687         return ldb_next_request(module, down_req);
2688 }
2689
2690 static int replmd_rename_callback(struct ldb_request *req, struct ldb_reply *ares);
2691
2692 /*
2693   handle a rename request
2694
2695   On a rename we need to do an extra ldb_modify which sets the
2696   whenChanged and uSNChanged attributes.  We do this in a callback after the success.
2697  */
2698 static int replmd_rename(struct ldb_module *module, struct ldb_request *req)
2699 {
2700         struct ldb_context *ldb;
2701         struct replmd_replicated_request *ac;
2702         int ret;
2703         struct ldb_request *down_req;
2704
2705         /* do not manipulate our control entries */
2706         if (ldb_dn_is_special(req->op.mod.message->dn)) {
2707                 return ldb_next_request(module, req);
2708         }
2709
2710         ldb = ldb_module_get_ctx(module);
2711
2712         ldb_debug(ldb, LDB_DEBUG_TRACE, "replmd_rename\n");
2713
2714         ac = replmd_ctx_init(module, req);
2715         if (ac == NULL) {
2716                 return ldb_module_oom(module);
2717         }
2718
2719         ret = ldb_build_rename_req(&down_req, ldb, ac,
2720                                    ac->req->op.rename.olddn,
2721                                    ac->req->op.rename.newdn,
2722                                    ac->req->controls,
2723                                    ac, replmd_rename_callback,
2724                                    ac->req);
2725         LDB_REQ_SET_LOCATION(down_req);
2726         if (ret != LDB_SUCCESS) {
2727                 talloc_free(ac);
2728                 return ret;
2729         }
2730
2731         /* go on with the call chain */
2732         return ldb_next_request(module, down_req);
2733 }
2734
2735 /* After the rename is compleated, update the whenchanged etc */
2736 static int replmd_rename_callback(struct ldb_request *req, struct ldb_reply *ares)
2737 {
2738         struct ldb_context *ldb;
2739         struct ldb_request *down_req;
2740         struct ldb_message *msg;
2741         const struct dsdb_attribute *rdn_attr;
2742         const char *rdn_name;
2743         const struct ldb_val *rdn_val;
2744         const char *attrs[5] = { NULL, };
2745         time_t t = time(NULL);
2746         int ret;
2747         bool is_urgent = false, rodc = false;
2748         bool is_schema_nc;
2749         struct replmd_replicated_request *ac =
2750                 talloc_get_type(req->context, struct replmd_replicated_request);
2751         struct replmd_private *replmd_private =
2752                 talloc_get_type(ldb_module_get_private(ac->module),
2753                                 struct replmd_private);
2754
2755         ldb = ldb_module_get_ctx(ac->module);
2756
2757         if (ares->error != LDB_SUCCESS) {
2758                 return ldb_module_done(ac->req, ares->controls,
2759                                         ares->response, ares->error);
2760         }
2761
2762         if (ares->type != LDB_REPLY_DONE) {
2763                 ldb_set_errstring(ldb,
2764                                   "invalid ldb_reply_type in callback");
2765                 talloc_free(ares);
2766                 return ldb_module_done(ac->req, NULL, NULL,
2767                                         LDB_ERR_OPERATIONS_ERROR);
2768         }
2769
2770         /* TODO:
2771          * - replace the old object with the newly constructed one
2772          */
2773
2774         msg = ldb_msg_new(ac);
2775         if (msg == NULL) {
2776                 ldb_oom(ldb);
2777                 return LDB_ERR_OPERATIONS_ERROR;
2778         }
2779
2780         msg->dn = ac->req->op.rename.newdn;
2781
2782         is_schema_nc = ldb_dn_compare_base(replmd_private->schema_dn, msg->dn) == 0;
2783
2784         rdn_name = ldb_dn_get_rdn_name(msg->dn);
2785         if (rdn_name == NULL) {
2786                 talloc_free(ares);
2787                 return ldb_module_done(ac->req, NULL, NULL,
2788                                        ldb_operr(ldb));
2789         }
2790
2791         /* normalize the rdn attribute name */
2792         rdn_attr = dsdb_attribute_by_lDAPDisplayName(ac->schema, rdn_name);
2793         if (rdn_attr == NULL) {
2794                 talloc_free(ares);
2795                 return ldb_module_done(ac->req, NULL, NULL,
2796                                        ldb_operr(ldb));
2797         }
2798         rdn_name = rdn_attr->lDAPDisplayName;
2799
2800         rdn_val = ldb_dn_get_rdn_val(msg->dn);
2801         if (rdn_val == NULL) {
2802                 talloc_free(ares);
2803                 return ldb_module_done(ac->req, NULL, NULL,
2804                                        ldb_operr(ldb));
2805         }
2806
2807         if (ldb_msg_add_empty(msg, rdn_name, LDB_FLAG_MOD_REPLACE, NULL) != 0) {
2808                 talloc_free(ares);
2809                 return ldb_module_done(ac->req, NULL, NULL,
2810                                        ldb_oom(ldb));
2811         }
2812         if (ldb_msg_add_value(msg, rdn_name, rdn_val, NULL) != 0) {
2813                 talloc_free(ares);
2814                 return ldb_module_done(ac->req, NULL, NULL,
2815                                        ldb_oom(ldb));
2816         }
2817         if (ldb_msg_add_empty(msg, "name", LDB_FLAG_MOD_REPLACE, NULL) != 0) {
2818                 talloc_free(ares);
2819                 return ldb_module_done(ac->req, NULL, NULL,
2820                                        ldb_oom(ldb));
2821         }
2822         if (ldb_msg_add_value(msg, "name", rdn_val, NULL) != 0) {
2823                 talloc_free(ares);
2824                 return ldb_module_done(ac->req, NULL, NULL,
2825                                        ldb_oom(ldb));
2826         }
2827
2828         /*
2829          * here we let replmd_update_rpmd() only search for
2830          * the existing "replPropertyMetaData" and rdn_name attributes.
2831          *
2832          * We do not want the existing "name" attribute as
2833          * the "name" attribute needs to get the version
2834          * updated on rename even if the rdn value hasn't changed.
2835          *
2836          * This is the diff of the meta data, for a moved user
2837          * on a w2k8r2 server:
2838          *
2839          * # record 1
2840          * -dn: CN=sdf df,CN=Users,DC=bla,DC=base
2841          * +dn: CN=sdf df,OU=TestOU,DC=bla,DC=base
2842          *  replPropertyMetaData:     NDR: struct replPropertyMetaDataBlob
2843          *         version                  : 0x00000001 (1)
2844          *         reserved                 : 0x00000000 (0)
2845          * @@ -66,11 +66,11 @@ replPropertyMetaData:     NDR: struct re
2846          *                      local_usn                : 0x00000000000037a5 (14245)
2847          *                 array: struct replPropertyMetaData1
2848          *                      attid                    : DRSUAPI_ATTID_name (0x90001)
2849          * -                    version                  : 0x00000001 (1)
2850          * -                    originating_change_time  : Wed Feb  9 17:20:49 2011 CET
2851          * +                    version                  : 0x00000002 (2)
2852          * +                    originating_change_time  : Wed Apr  6 15:21:01 2011 CEST
2853          *                      originating_invocation_id: 0d36ca05-5507-4e62-aca3-354bab0d39e1
2854          * -                    originating_usn          : 0x00000000000037a5 (14245)
2855          * -                    local_usn                : 0x00000000000037a5 (14245)
2856          * +                    originating_usn          : 0x0000000000003834 (14388)
2857          * +                    local_usn                : 0x0000000000003834 (14388)
2858          *                 array: struct replPropertyMetaData1
2859          *                      attid                    : DRSUAPI_ATTID_userAccountControl (0x90008)
2860          *                      version                  : 0x00000004 (4)
2861          */
2862         attrs[0] = "replPropertyMetaData";
2863         attrs[1] = "objectClass";
2864         attrs[2] = "instanceType";
2865         attrs[3] = rdn_name;
2866         attrs[4] = NULL;
2867
2868         ret = replmd_update_rpmd(ac->module, ac->schema, req, attrs,
2869                                  msg, &ac->seq_num, t,
2870                                  is_schema_nc, &is_urgent, &rodc);
2871         if (rodc && (ret == LDB_ERR_REFERRAL)) {
2872                 struct ldb_dn *olddn = ac->req->op.rename.olddn;
2873                 struct loadparm_context *lp_ctx;
2874                 char *referral;
2875
2876                 lp_ctx = talloc_get_type(ldb_get_opaque(ldb, "loadparm"),
2877                                          struct loadparm_context);
2878
2879                 referral = talloc_asprintf(req,
2880                                            "ldap://%s/%s",
2881                                            lpcfg_dnsdomain(lp_ctx),
2882                                            ldb_dn_get_linearized(olddn));
2883                 ret = ldb_module_send_referral(req, referral);
2884                 talloc_free(ares);
2885                 return ldb_module_done(req, NULL, NULL, ret);
2886         }
2887
2888         if (ret != LDB_SUCCESS) {
2889                 talloc_free(ares);
2890                 return ldb_module_done(ac->req, NULL, NULL, ret);
2891         }
2892
2893         if (ac->seq_num == 0) {
2894                 talloc_free(ares);
2895                 return ldb_module_done(ac->req, NULL, NULL,
2896                                        ldb_error(ldb, ret,
2897                                         "internal error seq_num == 0"));
2898         }
2899         ac->is_urgent = is_urgent;
2900
2901         ret = ldb_build_mod_req(&down_req, ldb, ac,
2902                                 msg,
2903                                 req->controls,
2904                                 ac, replmd_op_callback,
2905                                 req);
2906         LDB_REQ_SET_LOCATION(down_req);
2907         if (ret != LDB_SUCCESS) {
2908                 talloc_free(ac);
2909                 return ret;
2910         }
2911
2912         /* current partition control is needed by "replmd_op_callback" */
2913         if (ldb_request_get_control(req, DSDB_CONTROL_CURRENT_PARTITION_OID) == NULL) {
2914                 ret = ldb_request_add_control(down_req,
2915                                               DSDB_CONTROL_CURRENT_PARTITION_OID,
2916                                               false, NULL);
2917                 if (ret != LDB_SUCCESS) {
2918                         talloc_free(ac);
2919                         return ret;
2920                 }
2921         }
2922
2923         talloc_steal(down_req, msg);
2924
2925         ret = add_time_element(msg, "whenChanged", t);
2926         if (ret != LDB_SUCCESS) {
2927                 talloc_free(ac);
2928                 ldb_operr(ldb);
2929                 return ret;
2930         }
2931
2932         ret = add_uint64_element(ldb, msg, "uSNChanged", ac->seq_num);
2933         if (ret != LDB_SUCCESS) {
2934                 talloc_free(ac);
2935                 ldb_operr(ldb);
2936                 return ret;
2937         }
2938
2939         /* go on with the call chain - do the modify after the rename */
2940         return ldb_next_request(ac->module, down_req);
2941 }
2942
2943 /*
2944  * remove links from objects that point at this object when an object
2945  * is deleted.  We remove it from the NEXT module per MS-DRSR 5.160
2946  * RemoveObj which states that link removal due to the object being
2947  * deleted is NOT an originating update - they just go away!
2948  *
2949  */
2950 static int replmd_delete_remove_link(struct ldb_module *module,
2951                                      const struct dsdb_schema *schema,
2952                                      struct ldb_dn *dn,
2953                                      struct ldb_message_element *el,
2954                                      const struct dsdb_attribute *sa,
2955                                      struct ldb_request *parent)
2956 {
2957         unsigned int i;
2958         TALLOC_CTX *tmp_ctx = talloc_new(module);
2959         struct ldb_context *ldb = ldb_module_get_ctx(module);
2960
2961         for (i=0; i<el->num_values; i++) {
2962                 struct dsdb_dn *dsdb_dn;
2963                 NTSTATUS status;
2964                 int ret;
2965                 struct GUID guid2;
2966                 struct ldb_message *msg;
2967                 const struct dsdb_attribute *target_attr;
2968                 struct ldb_message_element *el2;
2969                 struct ldb_val dn_val;
2970
2971                 if (dsdb_dn_is_deleted_val(&el->values[i])) {
2972                         continue;
2973                 }
2974
2975                 dsdb_dn = dsdb_dn_parse(tmp_ctx, ldb, &el->values[i], sa->syntax->ldap_oid);
2976                 if (!dsdb_dn) {
2977                         talloc_free(tmp_ctx);
2978                         return LDB_ERR_OPERATIONS_ERROR;
2979                 }
2980
2981                 status = dsdb_get_extended_dn_guid(dsdb_dn->dn, &guid2, "GUID");
2982                 if (!NT_STATUS_IS_OK(status)) {
2983                         talloc_free(tmp_ctx);
2984                         return LDB_ERR_OPERATIONS_ERROR;
2985                 }
2986
2987                 /* remove the link */
2988                 msg = ldb_msg_new(tmp_ctx);
2989                 if (!msg) {
2990                         ldb_module_oom(module);
2991                         talloc_free(tmp_ctx);
2992                         return LDB_ERR_OPERATIONS_ERROR;
2993                 }
2994
2995
2996                 msg->dn = dsdb_dn->dn;
2997
2998                 target_attr = dsdb_attribute_by_linkID(schema, sa->linkID ^ 1);
2999                 if (target_attr == NULL) {
3000                         continue;
3001                 }
3002
3003                 ret = ldb_msg_add_empty(msg, target_attr->lDAPDisplayName, LDB_FLAG_MOD_DELETE, &el2);
3004                 if (ret != LDB_SUCCESS) {
3005                         ldb_module_oom(module);
3006                         talloc_free(tmp_ctx);
3007                         return LDB_ERR_OPERATIONS_ERROR;
3008                 }
3009                 dn_val = data_blob_string_const(ldb_dn_get_linearized(dn));
3010                 el2->values = &dn_val;
3011                 el2->num_values = 1;
3012
3013                 ret = dsdb_module_modify(module, msg, DSDB_FLAG_OWN_MODULE, parent);
3014                 if (ret != LDB_SUCCESS) {
3015                         talloc_free(tmp_ctx);
3016                         return ret;
3017                 }
3018         }
3019         talloc_free(tmp_ctx);
3020         return LDB_SUCCESS;
3021 }
3022
3023
3024 /*
3025   handle update of replication meta data for deletion of objects
3026
3027   This also handles the mapping of delete to a rename operation
3028   to allow deletes to be replicated.
3029
3030   It also handles the incoming deleted objects, to ensure they are
3031   fully deleted here.  In that case re_delete is true, and we do not
3032   use this as a signal to change the deleted state, just reinforce it.
3033
3034  */
3035 static int replmd_delete_internals(struct ldb_module *module, struct ldb_request *req, bool re_delete)
3036 {
3037         int ret = LDB_ERR_OTHER;
3038         bool retb, disallow_move_on_delete;
3039         struct ldb_dn *old_dn, *new_dn;
3040         const char *rdn_name;
3041         const struct ldb_val *rdn_value, *new_rdn_value;
3042         struct GUID guid;
3043         struct ldb_context *ldb = ldb_module_get_ctx(module);
3044         const struct dsdb_schema *schema;
3045         struct ldb_message *msg, *old_msg;
3046         struct ldb_message_element *el;
3047         TALLOC_CTX *tmp_ctx;
3048         struct ldb_result *res, *parent_res;
3049         const char *preserved_attrs[] = {
3050                 /* yes, this really is a hard coded list. See MS-ADTS
3051                    section 3.1.1.5.5.1.1 */
3052                 "nTSecurityDescriptor", "attributeID", "attributeSyntax", "dNReferenceUpdate", "dNSHostName",
3053                 "flatName", "governsID", "groupType", "instanceType", "lDAPDisplayName", "legacyExchangeDN",
3054                 "isDeleted", "isRecycled", "lastKnownParent", "msDS-LastKnownRDN", "mS-DS-CreatorSID",
3055                 "mSMQOwnerID", "nCName", "objectClass", "distinguishedName", "objectGUID", "objectSid",
3056                 "oMSyntax", "proxiedObjectName", "name", "replPropertyMetaData", "sAMAccountName",
3057                 "securityIdentifier", "sIDHistory", "subClassOf", "systemFlags", "trustPartner", "trustDirection",
3058                 "trustType", "trustAttributes", "userAccountControl", "uSNChanged", "uSNCreated", "whenCreated",
3059                 "whenChanged", NULL};
3060         unsigned int i, el_count = 0;
3061         enum deletion_state deletion_state, next_deletion_state;
3062
3063         if (ldb_dn_is_special(req->op.del.dn)) {
3064                 return ldb_next_request(module, req);
3065         }
3066
3067         /*
3068          * We have to allow dbcheck to remove an object that
3069          * is beyond repair, and to do so totally.  This could
3070          * mean we we can get a partial object from the other
3071          * DC, causing havoc, so dbcheck suggests
3072          * re-replication first.  dbcheck sets both DBCHECK
3073          * and RELAX in this situation.
3074          */
3075         if (ldb_request_get_control(req, LDB_CONTROL_RELAX_OID)
3076             && ldb_request_get_control(req, DSDB_CONTROL_DBCHECK)) {
3077                 /* really, really remove it */
3078                 return ldb_next_request(module, req);
3079         }
3080
3081         tmp_ctx = talloc_new(ldb);
3082         if (!tmp_ctx) {
3083                 ldb_oom(ldb);
3084                 return LDB_ERR_OPERATIONS_ERROR;
3085         }
3086
3087         schema = dsdb_get_schema(ldb, tmp_ctx);
3088         if (!schema) {
3089                 talloc_free(tmp_ctx);
3090                 return LDB_ERR_OPERATIONS_ERROR;
3091         }
3092
3093         old_dn = ldb_dn_copy(tmp_ctx, req->op.del.dn);
3094
3095         /* we need the complete msg off disk, so we can work out which
3096            attributes need to be removed */
3097         ret = dsdb_module_search_dn(module, tmp_ctx, &res, old_dn, NULL,
3098                                     DSDB_FLAG_NEXT_MODULE |
3099                                     DSDB_SEARCH_SHOW_RECYCLED |
3100                                     DSDB_SEARCH_REVEAL_INTERNALS |
3101                                     DSDB_SEARCH_SHOW_DN_IN_STORAGE_FORMAT, req);
3102         if (ret != LDB_SUCCESS) {
3103                 ldb_asprintf_errstring(ldb_module_get_ctx(module),
3104                                        "repmd_delete: Failed to %s %s, because we failed to find it: %s",
3105                                        re_delete ? "re-delete" : "delete",
3106                                        ldb_dn_get_linearized(old_dn),
3107                                        ldb_errstring(ldb_module_get_ctx(module)));
3108                 talloc_free(tmp_ctx);
3109                 return ret;
3110         }
3111         old_msg = res->msgs[0];
3112
3113         replmd_deletion_state(module, old_msg,
3114                               &deletion_state,
3115                               &next_deletion_state);
3116
3117         /* This supports us noticing an incoming isDeleted and acting on it */
3118         if (re_delete) {
3119                 SMB_ASSERT(deletion_state > OBJECT_NOT_DELETED);
3120                 next_deletion_state = deletion_state;
3121         }
3122
3123         if (next_deletion_state == OBJECT_REMOVED) {
3124                 /*
3125                  * We have to prevent objects being deleted, even if
3126                  * the administrator really wants them gone, as
3127                  * without the tombstone, we can get a partial object
3128                  * from the other DC, causing havoc.
3129                  *
3130                  * The only other valid case is when the 180 day
3131                  * timeout has expired, when relax is specified.
3132                  */
3133                 if (ldb_request_get_control(req, LDB_CONTROL_RELAX_OID)) {
3134                         /* it is already deleted - really remove it this time */
3135                         talloc_free(tmp_ctx);
3136                         return ldb_next_request(module, req);
3137                 }
3138
3139                 ldb_asprintf_errstring(ldb, "Refusing to delete tombstone object %s.  "
3140                                        "This check is to prevent corruption of the replicated state.",
3141                                        ldb_dn_get_linearized(old_msg->dn));
3142                 return LDB_ERR_UNWILLING_TO_PERFORM;
3143         }
3144
3145         rdn_name = ldb_dn_get_rdn_name(old_dn);
3146         rdn_value = ldb_dn_get_rdn_val(old_dn);
3147         if ((rdn_name == NULL) || (rdn_value == NULL)) {
3148                 talloc_free(tmp_ctx);
3149                 return ldb_operr(ldb);
3150         }
3151
3152         msg = ldb_msg_new(tmp_ctx);
3153         if (msg == NULL) {
3154                 ldb_module_oom(module);
3155                 talloc_free(tmp_ctx);
3156                 return LDB_ERR_OPERATIONS_ERROR;
3157         }
3158
3159         msg->dn = old_dn;
3160
3161         /* consider the SYSTEM_FLAG_DISALLOW_MOVE_ON_DELETE flag */
3162         disallow_move_on_delete =
3163                 (ldb_msg_find_attr_as_int(old_msg, "systemFlags", 0)
3164                  & SYSTEM_FLAG_DISALLOW_MOVE_ON_DELETE);
3165
3166         /* work out where we will be renaming this object to */
3167         if (!disallow_move_on_delete) {
3168                 struct ldb_dn *deleted_objects_dn;
3169                 ret = dsdb_get_deleted_objects_dn(ldb, tmp_ctx, old_dn,
3170                                                   &deleted_objects_dn);
3171
3172                 /*
3173                  * We should not move objects if we can't find the
3174                  * deleted objects DN.  Not moving (or otherwise
3175                  * harming) the Deleted Objects DN itself is handled
3176                  * in the caller.
3177                  */
3178                 if (re_delete && (ret != LDB_SUCCESS)) {
3179                         new_dn = ldb_dn_get_parent(tmp_ctx, old_dn);
3180                         if (new_dn == NULL) {
3181                                 ldb_module_oom(module);
3182                                 talloc_free(tmp_ctx);
3183                                 return LDB_ERR_OPERATIONS_ERROR;
3184                         }
3185                 } else if (ret != LDB_SUCCESS) {
3186                         /* this is probably an attempted delete on a partition
3187                          * that doesn't allow delete operations, such as the
3188                          * schema partition */
3189                         ldb_asprintf_errstring(ldb, "No Deleted Objects container for DN %s",
3190                                                ldb_dn_get_linearized(old_dn));
3191                         talloc_free(tmp_ctx);
3192                         return LDB_ERR_UNWILLING_TO_PERFORM;
3193                 } else {
3194                         new_dn = deleted_objects_dn;
3195                 }
3196         } else {
3197                 new_dn = ldb_dn_get_parent(tmp_ctx, old_dn);
3198                 if (new_dn == NULL) {
3199                         ldb_module_oom(module);
3200                         talloc_free(tmp_ctx);
3201                         return LDB_ERR_OPERATIONS_ERROR;
3202                 }
3203         }
3204
3205         if (deletion_state == OBJECT_NOT_DELETED) {
3206                 /* get the objects GUID from the search we just did */
3207                 guid = samdb_result_guid(old_msg, "objectGUID");
3208
3209                 /* Add a formatted child */
3210                 retb = ldb_dn_add_child_fmt(new_dn, "%s=%s\\0ADEL:%s",
3211                                             rdn_name,
3212                                             ldb_dn_escape_value(tmp_ctx, *rdn_value),
3213                                             GUID_string(tmp_ctx, &guid));
3214                 if (!retb) {
3215                         ldb_asprintf_errstring(ldb, __location__
3216                                                ": Unable to add a formatted child to dn: %s",
3217                                                ldb_dn_get_linearized(new_dn));
3218                         talloc_free(tmp_ctx);
3219                         return LDB_ERR_OPERATIONS_ERROR;
3220                 }
3221
3222                 ret = ldb_msg_add_string(msg, "isDeleted", "TRUE");
3223                 if (ret != LDB_SUCCESS) {
3224                         ldb_asprintf_errstring(ldb, __location__
3225                                                ": Failed to add isDeleted string to the msg");
3226                         talloc_free(tmp_ctx);
3227                         return ret;
3228                 }
3229                 msg->elements[el_count++].flags = LDB_FLAG_MOD_REPLACE;
3230         } else {
3231                 /*
3232                  * No matter what has happened with other renames etc, try again to
3233                  * get this to be under the deleted DN. See MS-DRSR 5.160 RemoveObj
3234                  */
3235
3236                 struct ldb_dn *rdn = ldb_dn_copy(tmp_ctx, old_dn);
3237                 retb = ldb_dn_remove_base_components(rdn, ldb_dn_get_comp_num(rdn) - 1);
3238                 if (!retb) {
3239                         ldb_asprintf_errstring(ldb, __location__
3240                                                ": Unable to add a prepare rdn of %s",
3241                                                ldb_dn_get_linearized(rdn));
3242                         talloc_free(tmp_ctx);
3243                         return LDB_ERR_OPERATIONS_ERROR;
3244                 }
3245                 SMB_ASSERT(ldb_dn_get_comp_num(rdn) == 1);
3246
3247                 retb = ldb_dn_add_child(new_dn, rdn);
3248                 if (!retb) {
3249                         ldb_asprintf_errstring(ldb, __location__
3250                                                ": Unable to add rdn %s to base dn: %s",
3251                                                ldb_dn_get_linearized(rdn),
3252                                                ldb_dn_get_linearized(new_dn));
3253                         talloc_free(tmp_ctx);
3254                         return LDB_ERR_OPERATIONS_ERROR;
3255                 }
3256         }
3257
3258         /*
3259           now we need to modify the object in the following ways:
3260
3261           - add isDeleted=TRUE
3262           - update rDN and name, with new rDN
3263           - remove linked attributes
3264           - remove objectCategory and sAMAccountType
3265           - remove attribs not on the preserved list
3266              - preserved if in above list, or is rDN
3267           - remove all linked attribs from this object
3268           - remove all links from other objects to this object
3269           - add lastKnownParent
3270           - update replPropertyMetaData?
3271
3272           see MS-ADTS "Tombstone Requirements" section 3.1.1.5.5.1.1
3273          */
3274
3275         if (deletion_state == OBJECT_NOT_DELETED) {
3276                 struct ldb_dn *parent_dn = ldb_dn_get_parent(tmp_ctx, old_dn);
3277                 char *parent_dn_str = NULL;
3278
3279                 /* we need the storage form of the parent GUID */
3280                 ret = dsdb_module_search_dn(module, tmp_ctx, &parent_res,
3281                                             parent_dn, NULL,
3282                                             DSDB_FLAG_NEXT_MODULE |
3283                                             DSDB_SEARCH_SHOW_DN_IN_STORAGE_FORMAT |
3284                                             DSDB_SEARCH_REVEAL_INTERNALS|
3285                                             DSDB_SEARCH_SHOW_RECYCLED, req);
3286                 if (ret != LDB_SUCCESS) {
3287                         ldb_asprintf_errstring(ldb_module_get_ctx(module),
3288                                                "repmd_delete: Failed to %s %s, "
3289                                                "because we failed to find it's parent (%s): %s",
3290                                                re_delete ? "re-delete" : "delete",
3291                                                ldb_dn_get_linearized(old_dn),
3292                                                ldb_dn_get_linearized(parent_dn),
3293                                                ldb_errstring(ldb_module_get_ctx(module)));
3294                         talloc_free(tmp_ctx);
3295                         return ret;
3296                 }
3297
3298                 /*
3299                  * Now we can use the DB version,
3300                  * it will have the extended DN info in it
3301                  */
3302                 parent_dn = parent_res->msgs[0]->dn;
3303                 parent_dn_str = ldb_dn_get_extended_linearized(tmp_ctx,
3304                                                                parent_dn,
3305                                                                1);
3306                 if (parent_dn_str == NULL) {
3307                         talloc_free(tmp_ctx);
3308                         return ldb_module_oom(module);
3309                 }
3310
3311                 ret = ldb_msg_add_steal_string(msg, "lastKnownParent",
3312                                                parent_dn_str);
3313                 if (ret != LDB_SUCCESS) {
3314                         ldb_asprintf_errstring(ldb, __location__
3315                                                ": Failed to add lastKnownParent "
3316                                                "string when deleting %s",
3317                                                ldb_dn_get_linearized(old_dn));
3318                         talloc_free(tmp_ctx);
3319                         return ret;
3320                 }
3321                 msg->elements[el_count++].flags = LDB_FLAG_MOD_REPLACE;
3322
3323                 if (next_deletion_state == OBJECT_DELETED) {
3324                         ret = ldb_msg_add_value(msg, "msDS-LastKnownRDN", rdn_value, NULL);
3325                         if (ret != LDB_SUCCESS) {
3326                                 ldb_asprintf_errstring(ldb, __location__
3327                                                        ": Failed to add msDS-LastKnownRDN "
3328                                                        "string when deleting %s",
3329                                                        ldb_dn_get_linearized(old_dn));
3330                                 talloc_free(tmp_ctx);
3331                                 return ret;
3332                         }
3333                         msg->elements[el_count++].flags = LDB_FLAG_MOD_ADD;
3334                 }
3335         }
3336
3337         switch (next_deletion_state) {
3338
3339         case OBJECT_RECYCLED:
3340         case OBJECT_TOMBSTONE:
3341
3342                 /*
3343                  * MS-ADTS 3.1.1.5.5.1.1 Tombstone Requirements
3344                  * describes what must be removed from a tombstone
3345                  * object
3346                  *
3347                  * MS-ADTS 3.1.1.5.5.1.3 Recycled-Object Requirements
3348                  * describes what must be removed from a recycled
3349                  * object
3350                  *
3351                  */
3352
3353                 /*
3354                  * we also mark it as recycled, meaning this object can't be
3355                  * recovered (we are stripping its attributes).
3356                  * This is done only if we have this schema object of course ...
3357                  * This behavior is identical to the one of Windows 2008R2 which
3358                  * always set the isRecycled attribute, even if the recycle-bin is
3359                  * not activated and what ever the forest level is.
3360                  */
3361                 if (dsdb_attribute_by_lDAPDisplayName(schema, "isRecycled") != NULL) {
3362                         ret = ldb_msg_add_string(msg, "isRecycled", "TRUE");
3363                         if (ret != LDB_SUCCESS) {
3364                                 DEBUG(0,(__location__ ": Failed to add isRecycled string to the msg\n"));
3365                                 ldb_module_oom(module);
3366                                 talloc_free(tmp_ctx);
3367                                 return ret;
3368                         }
3369                         msg->elements[el_count++].flags = LDB_FLAG_MOD_REPLACE;
3370                 }
3371
3372                 /* work out which of the old attributes we will be removing */
3373                 for (i=0; i<old_msg->num_elements; i++) {
3374                         const struct dsdb_attribute *sa;
3375                         el = &old_msg->elements[i];
3376                         sa = dsdb_attribute_by_lDAPDisplayName(schema, el->name);
3377                         if (!sa) {
3378                                 talloc_free(tmp_ctx);
3379                                 return LDB_ERR_OPERATIONS_ERROR;
3380                         }
3381                         if (ldb_attr_cmp(el->name, rdn_name) == 0) {
3382                                 /* don't remove the rDN */
3383                                 continue;
3384                         }
3385                         if (sa->linkID && (sa->linkID & 1)) {
3386                                 /*
3387                                   we have a backlink in this object
3388                                   that needs to be removed. We're not
3389                                   allowed to remove it directly
3390                                   however, so we instead setup a
3391                                   modify to delete the corresponding
3392                                   forward link
3393                                  */
3394                                 ret = replmd_delete_remove_link(module, schema, old_dn, el, sa, req);
3395                                 if (ret != LDB_SUCCESS) {
3396                                         const char *old_dn_str
3397                                                 = ldb_dn_get_linearized(old_dn);
3398                                         ldb_asprintf_errstring(ldb,
3399                                                                __location__
3400                                                                ": Failed to remove backlink of "
3401                                                                "%s when deleting %s",
3402                                                                el->name,
3403                                                                old_dn_str);
3404                                         talloc_free(tmp_ctx);
3405                                         return LDB_ERR_OPERATIONS_ERROR;
3406                                 }
3407                                 /* now we continue, which means we
3408                                    won't remove this backlink
3409                                    directly
3410                                 */
3411                                 continue;
3412                         }
3413                         if (!sa->linkID) {
3414                                 if (ldb_attr_in_list(preserved_attrs, el->name)) {
3415                                         continue;
3416                                 }
3417                                 if (sa->searchFlags & SEARCH_FLAG_PRESERVEONDELETE) {
3418                                         continue;
3419                                 }
3420                         }
3421                         ret = ldb_msg_add_empty(msg, el->name, LDB_FLAG_MOD_DELETE, &el);
3422                         if (ret != LDB_SUCCESS) {
3423                                 talloc_free(tmp_ctx);
3424                                 ldb_module_oom(module);
3425                                 return ret;
3426                         }
3427                 }
3428
3429                 break;
3430
3431         case OBJECT_DELETED:
3432                 /*
3433                  * MS-ADTS 3.1.1.5.5.1.2 Deleted-Object Requirements
3434                  * describes what must be removed from a deleted
3435                  * object
3436                  */
3437
3438                 ret = ldb_msg_add_empty(msg, "objectCategory", LDB_FLAG_MOD_REPLACE, NULL);
3439                 if (ret != LDB_SUCCESS) {
3440                         talloc_free(tmp_ctx);
3441                         ldb_module_oom(module);
3442                         return ret;
3443                 }
3444
3445                 ret = ldb_msg_add_empty(msg, "sAMAccountType", LDB_FLAG_MOD_REPLACE, NULL);
3446                 if (ret != LDB_SUCCESS) {
3447                         talloc_free(tmp_ctx);
3448                         ldb_module_oom(module);
3449                         return ret;
3450                 }
3451
3452                 break;
3453
3454         default:
3455                 break;
3456         }
3457
3458         if (deletion_state == OBJECT_NOT_DELETED) {
3459                 const struct dsdb_attribute *sa;
3460
3461                 /* work out what the new rdn value is, for updating the
3462                    rDN and name fields */
3463                 new_rdn_value = ldb_dn_get_rdn_val(new_dn);
3464                 if (new_rdn_value == NULL) {
3465                         talloc_free(tmp_ctx);
3466                         return ldb_operr(ldb);
3467                 }
3468
3469                 sa = dsdb_attribute_by_lDAPDisplayName(schema, rdn_name);
3470                 if (!sa) {
3471                         talloc_free(tmp_ctx);
3472                         return LDB_ERR_OPERATIONS_ERROR;
3473                 }
3474
3475                 ret = ldb_msg_add_value(msg, sa->lDAPDisplayName, new_rdn_value,
3476                                         &el);
3477                 if (ret != LDB_SUCCESS) {
3478                         talloc_free(tmp_ctx);
3479                         return ret;
3480                 }
3481                 el->flags = LDB_FLAG_MOD_REPLACE;
3482
3483                 el = ldb_msg_find_element(old_msg, "name");
3484                 if (el) {
3485                         ret = ldb_msg_add_value(msg, "name", new_rdn_value, &el);
3486                         if (ret != LDB_SUCCESS) {
3487                                 talloc_free(tmp_ctx);
3488                                 return ret;
3489                         }
3490                         el->flags = LDB_FLAG_MOD_REPLACE;
3491                 }
3492         }
3493
3494         /*
3495          * TODO: Per MS-DRSR 5.160 RemoveObj we should remove links directly, not as an originating update!
3496          *
3497          */
3498
3499         /*
3500          * No matter what has happned with other renames, try again to
3501          * get this to be under the deleted DN.
3502          */
3503         if (strcmp(ldb_dn_get_linearized(old_dn), ldb_dn_get_linearized(new_dn)) != 0) {
3504                 /* now rename onto the new DN */
3505                 ret = dsdb_module_rename(module, old_dn, new_dn, DSDB_FLAG_NEXT_MODULE, req);
3506                 if (ret != LDB_SUCCESS){
3507                         DEBUG(0,(__location__ ": Failed to rename object from '%s' to '%s' - %s\n",
3508                                  ldb_dn_get_linearized(old_dn),
3509                                  ldb_dn_get_linearized(new_dn),
3510                                  ldb_errstring(ldb)));
3511                         talloc_free(tmp_ctx);
3512                         return ret;
3513                 }
3514                 msg->dn = new_dn;
3515         }
3516
3517         ret = dsdb_module_modify(module, msg, DSDB_FLAG_OWN_MODULE, req);
3518         if (ret != LDB_SUCCESS) {
3519                 ldb_asprintf_errstring(ldb, "replmd_delete: Failed to modify object %s in delete - %s",
3520                                        ldb_dn_get_linearized(old_dn), ldb_errstring(ldb));
3521                 talloc_free(tmp_ctx);
3522                 return ret;
3523         }
3524
3525         talloc_free(tmp_ctx);
3526
3527         return ldb_module_done(req, NULL, NULL, LDB_SUCCESS);
3528 }
3529
3530 static int replmd_delete(struct ldb_module *module, struct ldb_request *req)
3531 {
3532         return replmd_delete_internals(module, req, false);
3533 }
3534
3535
3536 static int replmd_replicated_request_error(struct replmd_replicated_request *ar, int ret)
3537 {
3538         return ret;
3539 }
3540
3541 static int replmd_replicated_request_werror(struct replmd_replicated_request *ar, WERROR status)
3542 {
3543         int ret = LDB_ERR_OTHER;
3544         /* TODO: do some error mapping */
3545
3546         /* Let the caller know the full WERROR */
3547         ar->objs->error = status;
3548
3549         return ret;
3550 }
3551
3552
3553 static struct replPropertyMetaData1 *
3554 replmd_replPropertyMetaData1_find_attid(struct replPropertyMetaDataBlob *md_blob,
3555                                         enum drsuapi_DsAttributeId attid)
3556 {
3557         uint32_t i;
3558         struct replPropertyMetaDataCtr1 *rpmd_ctr = &md_blob->ctr.ctr1;
3559
3560         for (i = 0; i < rpmd_ctr->count; i++) {
3561                 if (rpmd_ctr->array[i].attid == attid) {
3562                         return &rpmd_ctr->array[i];
3563                 }
3564         }
3565         return NULL;
3566 }
3567
3568
3569 /*
3570    return true if an update is newer than an existing entry
3571    see section 5.11 of MS-ADTS
3572 */
3573 static bool replmd_update_is_newer(const struct GUID *current_invocation_id,
3574                                    const struct GUID *update_invocation_id,
3575                                    uint32_t current_version,
3576                                    uint32_t update_version,
3577                                    NTTIME current_change_time,
3578                                    NTTIME update_change_time)
3579 {
3580         if (update_version != current_version) {
3581                 return update_version > current_version;
3582         }
3583         if (update_change_time != current_change_time) {
3584                 return update_change_time > current_change_time;
3585         }
3586         return GUID_compare(update_invocation_id, current_invocation_id) > 0;
3587 }
3588
3589 static bool replmd_replPropertyMetaData1_is_newer(struct replPropertyMetaData1 *cur_m,
3590                                                   struct replPropertyMetaData1 *new_m)
3591 {
3592         return replmd_update_is_newer(&cur_m->originating_invocation_id,
3593                                       &new_m->originating_invocation_id,
3594                                       cur_m->version,
3595                                       new_m->version,
3596                                       cur_m->originating_change_time,
3597                                       new_m->originating_change_time);
3598 }
3599
3600 static bool replmd_replPropertyMetaData1_new_should_be_taken(uint32_t dsdb_repl_flags,
3601                                                              struct replPropertyMetaData1 *cur_m,
3602                                                              struct replPropertyMetaData1 *new_m)
3603 {
3604         bool cmp;
3605
3606         /*
3607          * If the new replPropertyMetaData entry for this attribute is
3608          * not provided (this happens in the case where we look for
3609          * ATTID_name, but the name was not changed), then the local
3610          * state is clearly still current, as the remote
3611          * server didn't send it due to being older the high watermark
3612          * USN we sent.
3613          */
3614         if (new_m == NULL) {
3615                 return false;
3616         }
3617
3618         if (dsdb_repl_flags & DSDB_REPL_FLAG_PRIORITISE_INCOMING) {
3619                 /*
3620                  * if we compare equal then do an
3621                  * update. This is used when a client
3622                  * asks for a FULL_SYNC, and can be
3623                  * used to recover a corrupt
3624                  * replica.
3625                  *
3626                  * This call is a bit tricky, what we
3627                  * are doing it turning the 'is_newer'
3628                  * call into a 'not is older' by
3629                  * swapping cur_m and new_m, and negating the
3630                  * outcome.
3631                  */
3632                 cmp = !replmd_replPropertyMetaData1_is_newer(new_m,
3633                                                              cur_m);
3634         } else {
3635                 cmp = replmd_replPropertyMetaData1_is_newer(cur_m,
3636                                                             new_m);
3637         }
3638         return cmp;
3639 }
3640
3641
3642 /*
3643   form a conflict DN
3644  */
3645 static struct ldb_dn *replmd_conflict_dn(TALLOC_CTX *mem_ctx, struct ldb_dn *dn, struct GUID *guid)
3646 {
3647         const struct ldb_val *rdn_val;
3648         const char *rdn_name;
3649         struct ldb_dn *new_dn;
3650
3651         rdn_val = ldb_dn_get_rdn_val(dn);
3652         rdn_name = ldb_dn_get_rdn_name(dn);
3653         if (!rdn_val || !rdn_name) {
3654                 return NULL;
3655         }
3656
3657         new_dn = ldb_dn_copy(mem_ctx, dn);
3658         if (!new_dn) {
3659                 return NULL;
3660         }
3661
3662         if (!ldb_dn_remove_child_components(new_dn, 1)) {
3663                 return NULL;
3664         }
3665
3666         if (!ldb_dn_add_child_fmt(new_dn, "%s=%s\\0ACNF:%s",
3667                                   rdn_name,
3668                                   ldb_dn_escape_value(new_dn, *rdn_val),
3669                                   GUID_string(new_dn, guid))) {
3670                 return NULL;
3671         }
3672
3673         return new_dn;
3674 }
3675
3676
3677 /*
3678   perform a modify operation which sets the rDN and name attributes to
3679   their current values. This has the effect of changing these
3680   attributes to have been last updated by the current DC. This is
3681   needed to ensure that renames performed as part of conflict
3682   resolution are propogated to other DCs
3683  */
3684 static int replmd_name_modify(struct replmd_replicated_request *ar,
3685                               struct ldb_request *req, struct ldb_dn *dn)
3686 {
3687         struct ldb_message *msg;
3688         const char *rdn_name;
3689         const struct ldb_val *rdn_val;
3690         const struct dsdb_attribute *rdn_attr;
3691         int ret;
3692
3693         msg = ldb_msg_new(req);
3694         if (msg == NULL) {
3695                 goto failed;
3696         }
3697         msg->dn = dn;
3698
3699         rdn_name = ldb_dn_get_rdn_name(dn);
3700         if (rdn_name == NULL) {
3701                 goto failed;
3702         }
3703
3704         /* normalize the rdn attribute name */
3705         rdn_attr = dsdb_attribute_by_lDAPDisplayName(ar->schema, rdn_name);
3706         if (rdn_attr == NULL) {
3707                 goto failed;
3708         }
3709         rdn_name = rdn_attr->lDAPDisplayName;
3710
3711         rdn_val = ldb_dn_get_rdn_val(dn);
3712         if (rdn_val == NULL) {
3713                 goto failed;
3714         }
3715
3716         if (ldb_msg_add_empty(msg, rdn_name, LDB_FLAG_MOD_REPLACE, NULL) != 0) {
3717                 goto failed;
3718         }
3719         if (ldb_msg_add_value(msg, rdn_name, rdn_val, NULL) != 0) {
3720                 goto failed;
3721         }
3722         if (ldb_msg_add_empty(msg, "name", LDB_FLAG_MOD_REPLACE, NULL) != 0) {
3723                 goto failed;
3724         }
3725         if (ldb_msg_add_value(msg, "name", rdn_val, NULL) != 0) {
3726                 goto failed;
3727         }
3728
3729         ret = dsdb_module_modify(ar->module, msg, DSDB_FLAG_OWN_MODULE, req);
3730         if (ret != LDB_SUCCESS) {
3731                 DEBUG(0,(__location__ ": Failed to modify rDN/name of conflict DN '%s' - %s",
3732                          ldb_dn_get_linearized(dn),
3733                          ldb_errstring(ldb_module_get_ctx(ar->module))));
3734                 return ret;
3735         }
3736
3737         talloc_free(msg);
3738
3739         return LDB_SUCCESS;
3740
3741 failed:
3742         talloc_free(msg);
3743         DEBUG(0,(__location__ ": Failed to setup modify rDN/name of conflict DN '%s'",
3744                  ldb_dn_get_linearized(dn)));
3745         return LDB_ERR_OPERATIONS_ERROR;
3746 }
3747
3748
3749 /*
3750   callback for conflict DN handling where we have renamed the incoming
3751   record. After renaming it, we need to ensure the change of name and
3752   rDN for the incoming record is seen as an originating update by this DC.
3753
3754   This also handles updating lastKnownParent for entries sent to lostAndFound
3755  */
3756 static int replmd_op_name_modify_callback(struct ldb_request *req, struct ldb_reply *ares)
3757 {
3758         struct replmd_replicated_request *ar =
3759                 talloc_get_type_abort(req->context, struct replmd_replicated_request);
3760         struct ldb_dn *conflict_dn = NULL;
3761         int ret;
3762
3763         if (ares->error != LDB_SUCCESS) {
3764                 /* call the normal callback for everything except success */
3765                 return replmd_op_callback(req, ares);
3766         }
3767
3768         switch (req->operation) {
3769         case LDB_ADD:
3770                 conflict_dn = req->op.add.message->dn;
3771                 break;
3772         case LDB_MODIFY:
3773                 conflict_dn = req->op.mod.message->dn;
3774                 break;
3775         default:
3776                 smb_panic("replmd_op_name_modify_callback called in unknown circumstances");
3777         }
3778
3779         /* perform a modify of the rDN and name of the record */
3780         ret = replmd_name_modify(ar, req, conflict_dn);
3781         if (ret != LDB_SUCCESS) {
3782                 ares->error = ret;
3783                 return replmd_op_callback(req, ares);
3784         }
3785
3786         if (ar->objs->objects[ar->index_current].last_known_parent) {
3787                 struct ldb_message *msg = ldb_msg_new(req);
3788                 if (msg == NULL) {
3789                         ldb_module_oom(ar->module);
3790                         return LDB_ERR_OPERATIONS_ERROR;
3791                 }
3792
3793                 msg->dn = req->op.add.message->dn;
3794
3795                 ret = ldb_msg_add_steal_string(msg, "lastKnownParent",
3796                                                ldb_dn_get_extended_linearized(msg, ar->objs->objects[ar->index_current].last_known_parent, 1));
3797                 if (ret != LDB_SUCCESS) {
3798                         DEBUG(0,(__location__ ": Failed to add lastKnownParent string to the msg\n"));
3799                         ldb_module_oom(ar->module);
3800                         return ret;
3801                 }
3802                 msg->elements[0].flags = LDB_FLAG_MOD_REPLACE;
3803
3804                 ret = dsdb_module_modify(ar->module, msg, DSDB_FLAG_OWN_MODULE, req);
3805                 if (ret != LDB_SUCCESS) {
3806                         DEBUG(0,(__location__ ": Failed to modify lastKnownParent of lostAndFound DN '%s' - %s",
3807                                  ldb_dn_get_linearized(msg->dn),
3808                                  ldb_errstring(ldb_module_get_ctx(ar->module))));
3809                         return ret;
3810                 }
3811                 TALLOC_FREE(msg);
3812         }
3813
3814         return replmd_op_callback(req, ares);
3815 }
3816
3817 /*
3818   callback for replmd_replicated_apply_add()
3819   This copes with the creation of conflict records in the case where
3820   the DN exists, but with a different objectGUID
3821  */
3822 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))
3823 {
3824         struct ldb_dn *conflict_dn;
3825         struct replmd_replicated_request *ar =
3826                 talloc_get_type_abort(req->context, struct replmd_replicated_request);
3827         struct ldb_result *res;
3828         const char *attrs[] = { "replPropertyMetaData", "objectGUID", NULL };
3829         int ret;
3830         const struct ldb_val *omd_value;
3831         struct replPropertyMetaDataBlob omd, *rmd;
3832         enum ndr_err_code ndr_err;
3833         bool rename_incoming_record, rodc;
3834         struct replPropertyMetaData1 *rmd_name, *omd_name;
3835         struct ldb_message *msg;
3836         struct ldb_request *down_req = NULL;
3837
3838         /* call the normal callback for success */
3839         if (ares->error == LDB_SUCCESS) {
3840                 return callback(req, ares);
3841         }
3842
3843         /*
3844          * we have a conflict, and need to decide if we will keep the
3845          * new record or the old record
3846          */
3847
3848         msg = ar->objs->objects[ar->index_current].msg;
3849         conflict_dn = msg->dn;
3850
3851         /* For failures other than conflicts, fail the whole operation here */
3852         if (ares->error != LDB_ERR_ENTRY_ALREADY_EXISTS) {
3853                 ldb_asprintf_errstring(ldb_module_get_ctx(ar->module), "Failed to locally apply remote add of %s: %s",
3854                                        ldb_dn_get_linearized(conflict_dn),
3855                                        ldb_errstring(ldb_module_get_ctx(ar->module)));
3856
3857                 return ldb_module_done(ar->req, NULL, NULL,
3858                                        LDB_ERR_OPERATIONS_ERROR);
3859         }
3860
3861         ret = samdb_rodc(ldb_module_get_ctx(ar->module), &rodc);
3862         if (ret != LDB_SUCCESS) {
3863                 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)));
3864                 return ldb_module_done(ar->req, NULL, NULL,
3865                                        LDB_ERR_OPERATIONS_ERROR);
3866
3867         }
3868
3869         if (rodc) {
3870                 /*
3871                  * We are on an RODC, or were a GC for this
3872                  * partition, so we have to fail this until
3873                  * someone who owns the partition sorts it
3874                  * out 
3875                  */
3876                 ldb_asprintf_errstring(ldb_module_get_ctx(ar->module), 
3877                                        "Conflict adding object '%s' from incoming replication as we are read only for the partition.  \n"
3878                                        " - We must fail the operation until a master for this partition resolves the conflict",
3879                                        ldb_dn_get_linearized(conflict_dn));
3880                 goto failed;
3881         }
3882
3883         /*
3884          * first we need the replPropertyMetaData attribute from the
3885          * local, conflicting record
3886          */
3887         ret = dsdb_module_search_dn(ar->module, req, &res, conflict_dn,
3888                                     attrs,
3889                                     DSDB_FLAG_NEXT_MODULE |
3890                                     DSDB_SEARCH_SHOW_DELETED |
3891                                     DSDB_SEARCH_SHOW_RECYCLED, req);
3892         if (ret != LDB_SUCCESS) {
3893                 DEBUG(0,(__location__ ": Unable to find object for conflicting record '%s'\n",
3894                          ldb_dn_get_linearized(conflict_dn)));
3895                 goto failed;
3896         }
3897
3898         omd_value = ldb_msg_find_ldb_val(res->msgs[0], "replPropertyMetaData");
3899         if (omd_value == NULL) {
3900                 DEBUG(0,(__location__ ": Unable to find replPropertyMetaData for conflicting record '%s'\n",
3901                          ldb_dn_get_linearized(conflict_dn)));
3902                 goto failed;
3903         }
3904
3905         ndr_err = ndr_pull_struct_blob(omd_value, res->msgs[0], &omd,
3906                                        (ndr_pull_flags_fn_t)ndr_pull_replPropertyMetaDataBlob);
3907         if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
3908                 DEBUG(0,(__location__ ": Failed to parse old replPropertyMetaData for %s\n",
3909                          ldb_dn_get_linearized(conflict_dn)));
3910                 goto failed;
3911         }
3912
3913         rmd = ar->objs->objects[ar->index_current].meta_data;
3914
3915         /*
3916          * we decide which is newer based on the RPMD on the name
3917          * attribute.  See [MS-DRSR] ResolveNameConflict.
3918          *
3919          * We expect omd_name to be present, as this is from a local
3920          * search, but while rmd_name should have been given to us by
3921          * the remote server, if it is missing we just prefer the
3922          * local name in
3923          * replmd_replPropertyMetaData1_new_should_be_taken()
3924          */
3925         rmd_name = replmd_replPropertyMetaData1_find_attid(rmd, DRSUAPI_ATTID_name);
3926         omd_name = replmd_replPropertyMetaData1_find_attid(&omd, DRSUAPI_ATTID_name);
3927         if (!omd_name) {
3928                 DEBUG(0,(__location__ ": Failed to find name attribute in local LDB replPropertyMetaData for %s\n",
3929                          ldb_dn_get_linearized(conflict_dn)));
3930                 goto failed;
3931         }
3932
3933         /*
3934          * Should we preserve the current record, and so rename the
3935          * incoming record to be a conflict?
3936          */
3937         rename_incoming_record
3938                 = !replmd_replPropertyMetaData1_new_should_be_taken(ar->objs->dsdb_repl_flags & DSDB_REPL_FLAG_PRIORITISE_INCOMING,
3939                                                                     omd_name, rmd_name);
3940
3941         if (rename_incoming_record) {
3942                 struct GUID guid;
3943                 struct ldb_dn *new_dn;
3944
3945                 guid = samdb_result_guid(msg, "objectGUID");
3946                 if (GUID_all_zero(&guid)) {
3947                         DEBUG(0,(__location__ ": Failed to find objectGUID for conflicting incoming record %s\n",
3948                                  ldb_dn_get_linearized(conflict_dn)));
3949                         goto failed;
3950                 }
3951                 new_dn = replmd_conflict_dn(req, conflict_dn, &guid);
3952                 if (new_dn == NULL) {
3953                         DEBUG(0,(__location__ ": Failed to form conflict DN for %s\n",
3954                                  ldb_dn_get_linearized(conflict_dn)));
3955                         goto failed;
3956                 }
3957
3958                 DEBUG(2,(__location__ ": Resolving conflict record via incoming rename '%s' -> '%s'\n",
3959                          ldb_dn_get_linearized(conflict_dn), ldb_dn_get_linearized(new_dn)));
3960
3961                 /* re-submit the request, but with the new DN */
3962                 callback = replmd_op_name_modify_callback;
3963                 msg->dn = new_dn;
3964         } else {
3965                 /* we are renaming the existing record */
3966                 struct GUID guid;
3967                 struct ldb_dn *new_dn;
3968
3969                 guid = samdb_result_guid(res->msgs[0], "objectGUID");
3970                 if (GUID_all_zero(&guid)) {
3971                         DEBUG(0,(__location__ ": Failed to find objectGUID for existing conflict record %s\n",
3972                                  ldb_dn_get_linearized(conflict_dn)));
3973                         goto failed;
3974                 }
3975
3976                 new_dn = replmd_conflict_dn(req, conflict_dn, &guid);
3977                 if (new_dn == NULL) {
3978                         DEBUG(0,(__location__ ": Failed to form conflict DN for %s\n",
3979                                  ldb_dn_get_linearized(conflict_dn)));
3980                         goto failed;
3981                 }
3982
3983                 DEBUG(2,(__location__ ": Resolving conflict record via existing-record rename '%s' -> '%s'\n",
3984                          ldb_dn_get_linearized(conflict_dn), ldb_dn_get_linearized(new_dn)));
3985
3986                 ret = dsdb_module_rename(ar->module, conflict_dn, new_dn,
3987                                          DSDB_FLAG_OWN_MODULE, req);
3988                 if (ret != LDB_SUCCESS) {
3989                         DEBUG(0,(__location__ ": Failed to rename conflict dn '%s' to '%s' - %s\n",
3990                                  ldb_dn_get_linearized(conflict_dn),
3991                                  ldb_dn_get_linearized(new_dn),
3992                                  ldb_errstring(ldb_module_get_ctx(ar->module))));
3993                         goto failed;
3994                 }
3995
3996                 /*
3997                  * now we need to ensure that the rename is seen as an
3998                  * originating update. We do that with a modify.
3999                  */
4000                 ret = replmd_name_modify(ar, req, new_dn);
4001                 if (ret != LDB_SUCCESS) {
4002                         goto failed;
4003                 }
4004
4005                 DEBUG(2,(__location__ ": With conflicting record renamed, re-apply replicated creation of '%s'\n",
4006                          ldb_dn_get_linearized(req->op.add.message->dn)));
4007         }
4008
4009         ret = ldb_build_add_req(&down_req,
4010                                 ldb_module_get_ctx(ar->module),
4011                                 req,
4012                                 msg,
4013                                 ar->controls,
4014                                 ar,
4015                                 callback,
4016                                 req);
4017         if (ret != LDB_SUCCESS) {
4018                 goto failed;
4019         }
4020         LDB_REQ_SET_LOCATION(down_req);
4021
4022         /* current partition control needed by "repmd_op_callback" */
4023         ret = ldb_request_add_control(down_req,
4024                                       DSDB_CONTROL_CURRENT_PARTITION_OID,
4025                                       false, NULL);
4026         if (ret != LDB_SUCCESS) {
4027                 return replmd_replicated_request_error(ar, ret);
4028         }
4029
4030         if (ar->objs->dsdb_repl_flags & DSDB_REPL_FLAG_PARTIAL_REPLICA) {
4031                 /* this tells the partition module to make it a
4032                    partial replica if creating an NC */
4033                 ret = ldb_request_add_control(down_req,
4034                                               DSDB_CONTROL_PARTIAL_REPLICA,
4035                                               false, NULL);
4036                 if (ret != LDB_SUCCESS) {
4037                         return replmd_replicated_request_error(ar, ret);
4038                 }
4039         }
4040
4041         /*
4042          * Finally we re-run the add, otherwise the new record won't
4043          * exist, as we are here because of that exact failure!
4044          */
4045         return ldb_next_request(ar->module, down_req);
4046 failed:
4047
4048         /* on failure make the caller get the error. This means
4049          * replication will stop with an error, but there is not much
4050          * else we can do.
4051          */
4052         return ldb_module_done(ar->req, NULL, NULL,
4053                                ret);
4054 }
4055
4056 /*
4057   callback for replmd_replicated_apply_add()
4058   This copes with the creation of conflict records in the case where
4059   the DN exists, but with a different objectGUID
4060  */
4061 static int replmd_op_add_callback(struct ldb_request *req, struct ldb_reply *ares)
4062 {
4063         struct replmd_replicated_request *ar =
4064                 talloc_get_type_abort(req->context, struct replmd_replicated_request);
4065
4066         if (ar->objs->objects[ar->index_current].last_known_parent) {
4067                 /* This is like a conflict DN, where we put the object in LostAndFound
4068                    see MS-DRSR 4.1.10.6.10 FindBestParentObject */
4069                 return replmd_op_possible_conflict_callback(req, ares, replmd_op_name_modify_callback);
4070         }
4071
4072         return replmd_op_possible_conflict_callback(req, ares, replmd_op_callback);
4073 }
4074
4075 /*
4076   this is called when a new object comes in over DRS
4077  */
4078 static int replmd_replicated_apply_add(struct replmd_replicated_request *ar)
4079 {
4080         struct ldb_context *ldb;
4081         struct ldb_request *change_req;
4082         enum ndr_err_code ndr_err;
4083         struct ldb_message *msg;
4084         struct replPropertyMetaDataBlob *md;
4085         struct ldb_val md_value;
4086         unsigned int i;
4087         int ret;
4088         bool remote_isDeleted = false;
4089         bool is_schema_nc;
4090         NTTIME now;
4091         time_t t = time(NULL);
4092         const struct ldb_val *rdn_val;
4093         struct replmd_private *replmd_private =
4094                 talloc_get_type(ldb_module_get_private(ar->module),
4095                                 struct replmd_private);
4096         unix_to_nt_time(&now, t);
4097
4098         ldb = ldb_module_get_ctx(ar->module);
4099         msg = ar->objs->objects[ar->index_current].msg;
4100         md = ar->objs->objects[ar->index_current].meta_data;
4101         is_schema_nc = ldb_dn_compare_base(replmd_private->schema_dn, msg->dn) == 0;
4102
4103         ret = ldb_sequence_number(ldb, LDB_SEQ_NEXT, &ar->seq_num);
4104         if (ret != LDB_SUCCESS) {
4105                 return replmd_replicated_request_error(ar, ret);
4106         }
4107
4108         ret = dsdb_msg_add_guid(msg,
4109                                 &ar->objs->objects[ar->index_current].object_guid,
4110                                 "objectGUID");
4111         if (ret != LDB_SUCCESS) {
4112                 return replmd_replicated_request_error(ar, ret);
4113         }
4114
4115         ret = ldb_msg_add_string(msg, "whenChanged", ar->objs->objects[ar->index_current].when_changed);
4116         if (ret != LDB_SUCCESS) {
4117                 return replmd_replicated_request_error(ar, ret);
4118         }
4119
4120         ret = samdb_msg_add_uint64(ldb, msg, msg, "uSNCreated", ar->seq_num);
4121         if (ret != LDB_SUCCESS) {
4122                 return replmd_replicated_request_error(ar, ret);
4123         }
4124
4125         ret = samdb_msg_add_uint64(ldb, msg, msg, "uSNChanged", ar->seq_num);
4126         if (ret != LDB_SUCCESS) {
4127                 return replmd_replicated_request_error(ar, ret);
4128         }
4129
4130         /* remove any message elements that have zero values */
4131         for (i=0; i<msg->num_elements; i++) {
4132                 struct ldb_message_element *el = &msg->elements[i];
4133
4134                 if (el->num_values == 0) {
4135                         if (ldb_attr_cmp(msg->elements[i].name, "objectClass") == 0) {
4136                                 ldb_asprintf_errstring(ldb, __location__
4137                                                        ": empty objectClass sent on %s, aborting replication\n",
4138                                                        ldb_dn_get_linearized(msg->dn));
4139                                 return replmd_replicated_request_error(ar, LDB_ERR_OBJECT_CLASS_VIOLATION);
4140                         }
4141
4142                         DEBUG(4,(__location__ ": Removing attribute %s with num_values==0\n",
4143                                  el->name));
4144                         memmove(el, el+1, sizeof(*el)*(msg->num_elements - (i+1)));
4145                         msg->num_elements--;
4146                         i--;
4147                         continue;
4148                 }
4149         }
4150
4151         if (DEBUGLVL(4)) {
4152                 struct GUID_txt_buf guid_txt;
4153
4154                 char *s = ldb_ldif_message_string(ldb, ar, LDB_CHANGETYPE_ADD, msg);
4155                 DEBUG(4, ("DRS replication add message of %s:\n%s\n",
4156                           GUID_buf_string(&ar->objs->objects[ar->index_current].object_guid, &guid_txt),
4157                           s));
4158                 talloc_free(s);
4159         }
4160
4161         remote_isDeleted = ldb_msg_find_attr_as_bool(msg,
4162                                                      "isDeleted", false);
4163
4164         /*
4165          * the meta data array is already sorted by the caller, except
4166          * for the RDN, which needs to be added.
4167          */
4168
4169
4170         rdn_val = ldb_dn_get_rdn_val(msg->dn);
4171         ret = replmd_update_rpmd_rdn_attr(ldb, msg, rdn_val, NULL,
4172                                      md, ar, now, is_schema_nc);
4173         if (ret != LDB_SUCCESS) {
4174                 ldb_asprintf_errstring(ldb, "%s: error during DRS repl ADD: %s", __func__, ldb_errstring(ldb));
4175                 return replmd_replicated_request_error(ar, ret);
4176         }
4177
4178         ret = replmd_replPropertyMetaDataCtr1_sort_and_verify(ldb, &md->ctr.ctr1, msg->dn);
4179         if (ret != LDB_SUCCESS) {
4180                 ldb_asprintf_errstring(ldb, "%s: error during DRS repl ADD: %s", __func__, ldb_errstring(ldb));
4181                 return replmd_replicated_request_error(ar, ret);
4182         }
4183
4184         for (i=0; i < md->ctr.ctr1.count; i++) {
4185                 md->ctr.ctr1.array[i].local_usn = ar->seq_num;
4186         }
4187         ndr_err = ndr_push_struct_blob(&md_value, msg, md,
4188                                        (ndr_push_flags_fn_t)ndr_push_replPropertyMetaDataBlob);
4189         if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
4190                 NTSTATUS nt_status = ndr_map_error2ntstatus(ndr_err);
4191                 return replmd_replicated_request_werror(ar, ntstatus_to_werror(nt_status));
4192         }
4193         ret = ldb_msg_add_value(msg, "replPropertyMetaData", &md_value, NULL);
4194         if (ret != LDB_SUCCESS) {
4195                 return replmd_replicated_request_error(ar, ret);
4196         }
4197
4198         replmd_ldb_message_sort(msg, ar->schema);
4199
4200         if (!remote_isDeleted) {
4201                 ret = dsdb_module_schedule_sd_propagation(ar->module,
4202                                                           ar->objs->partition_dn,
4203                                                           msg->dn, true);
4204                 if (ret != LDB_SUCCESS) {
4205                         return replmd_replicated_request_error(ar, ret);
4206                 }
4207         }
4208
4209         ar->isDeleted = remote_isDeleted;
4210
4211         ret = ldb_build_add_req(&change_req,
4212                                 ldb,
4213                                 ar,
4214                                 msg,
4215                                 ar->controls,
4216                                 ar,
4217                                 replmd_op_add_callback,
4218                                 ar->req);
4219         LDB_REQ_SET_LOCATION(change_req);
4220         if (ret != LDB_SUCCESS) return replmd_replicated_request_error(ar, ret);
4221
4222         /* current partition control needed by "repmd_op_callback" */
4223         ret = ldb_request_add_control(change_req,
4224                                       DSDB_CONTROL_CURRENT_PARTITION_OID,
4225                                       false, NULL);
4226         if (ret != LDB_SUCCESS) return replmd_replicated_request_error(ar, ret);
4227
4228         if (ar->objs->dsdb_repl_flags & DSDB_REPL_FLAG_PARTIAL_REPLICA) {
4229                 /* this tells the partition module to make it a
4230                    partial replica if creating an NC */
4231                 ret = ldb_request_add_control(change_req,
4232                                               DSDB_CONTROL_PARTIAL_REPLICA,
4233                                               false, NULL);
4234                 if (ret != LDB_SUCCESS) return replmd_replicated_request_error(ar, ret);
4235         }
4236
4237         return ldb_next_request(ar->module, change_req);
4238 }
4239
4240 static int replmd_replicated_apply_search_for_parent_callback(struct ldb_request *req,
4241                                                               struct ldb_reply *ares)
4242 {
4243         struct replmd_replicated_request *ar = talloc_get_type(req->context,
4244                                                struct replmd_replicated_request);
4245         int ret;
4246
4247         if (!ares) {
4248                 return ldb_module_done(ar->req, NULL, NULL,
4249                                         LDB_ERR_OPERATIONS_ERROR);
4250         }
4251
4252         /*
4253          * The error NO_SUCH_OBJECT is not expected, unless the search
4254          * base is the partition DN, and that case doesn't happen here
4255          * because then we wouldn't get a parent_guid_value in any
4256          * case.
4257          */
4258         if (ares->error != LDB_SUCCESS) {
4259                 return ldb_module_done(ar->req, ares->controls,
4260                                         ares->response, ares->error);
4261         }
4262
4263         switch (ares->type) {
4264         case LDB_REPLY_ENTRY:
4265         {
4266                 struct ldb_message *parent_msg = ares->message;
4267                 struct ldb_message *msg = ar->objs->objects[ar->index_current].msg;
4268                 struct ldb_dn *parent_dn;
4269                 int comp_num;
4270
4271                 if (!ldb_msg_check_string_attribute(msg, "isDeleted", "TRUE")
4272                     && ldb_msg_check_string_attribute(parent_msg, "isDeleted", "TRUE")) {
4273                         /* Per MS-DRSR 4.1.10.6.10
4274                          * FindBestParentObject we need to move this
4275                          * new object under a deleted object to
4276                          * lost-and-found */
4277                         struct ldb_dn *nc_root;
4278
4279                         ret = dsdb_find_nc_root(ldb_module_get_ctx(ar->module), msg, msg->dn, &nc_root);
4280                         if (ret == LDB_ERR_NO_SUCH_OBJECT) {
4281                                 ldb_asprintf_errstring(ldb_module_get_ctx(ar->module),
4282                                                        "No suitable NC root found for %s.  "
4283                                                        "We need to move this object because parent object %s "
4284                                                        "is deleted, but this object is not.",
4285                                                        ldb_dn_get_linearized(msg->dn),
4286                                                        ldb_dn_get_linearized(parent_msg->dn));
4287                                 return ldb_module_done(ar->req, NULL, NULL, LDB_ERR_OPERATIONS_ERROR);
4288                         } else if (ret != LDB_SUCCESS) {
4289                                 ldb_asprintf_errstring(ldb_module_get_ctx(ar->module),
4290                                                        "Unable to find NC root for %s: %s. "
4291                                                        "We need to move this object because parent object %s "
4292                                                        "is deleted, but this object is not.",
4293                                                        ldb_dn_get_linearized(msg->dn),
4294                                                        ldb_errstring(ldb_module_get_ctx(ar->module)),
4295                                                        ldb_dn_get_linearized(parent_msg->dn));
4296                                 return ldb_module_done(ar->req, NULL, NULL, LDB_ERR_OPERATIONS_ERROR);
4297                         }
4298                         
4299                         ret = dsdb_wellknown_dn(ldb_module_get_ctx(ar->module), msg,
4300                                                 nc_root,
4301                                                 DS_GUID_LOSTANDFOUND_CONTAINER,
4302                                                 &parent_dn);
4303                         if (ret != LDB_SUCCESS) {
4304                                 ldb_asprintf_errstring(ldb_module_get_ctx(ar->module),
4305                                                        "Unable to find LostAndFound Container for %s "
4306                                                        "in partition %s: %s. "
4307                                                        "We need to move this object because parent object %s "
4308                                                        "is deleted, but this object is not.",
4309                                                        ldb_dn_get_linearized(msg->dn), ldb_dn_get_linearized(nc_root),
4310                                                        ldb_errstring(ldb_module_get_ctx(ar->module)),
4311                                                        ldb_dn_get_linearized(parent_msg->dn));
4312                                 return ldb_module_done(ar->req, NULL, NULL, LDB_ERR_OPERATIONS_ERROR);
4313                         }
4314                         ar->objs->objects[ar->index_current].last_known_parent
4315                                 = talloc_steal(ar->objs->objects[ar->index_current].msg, parent_msg->dn);
4316
4317                 } else {
4318                         parent_dn
4319                                 = talloc_steal(ar->objs->objects[ar->index_current].msg, parent_msg->dn);
4320
4321                 }
4322                 ar->objs->objects[ar->index_current].local_parent_dn = parent_dn;
4323
4324                 comp_num = ldb_dn_get_comp_num(msg->dn);
4325                 if (comp_num > 1) {
4326                         if (!ldb_dn_remove_base_components(msg->dn, comp_num - 1)) {
4327                                 talloc_free(ares);
4328                                 return ldb_module_done(ar->req, NULL, NULL, ldb_module_operr(ar->module));
4329                         }
4330                 }
4331                 if (!ldb_dn_add_base(msg->dn, parent_dn)) {
4332                         talloc_free(ares);
4333                         return ldb_module_done(ar->req, NULL, NULL, ldb_module_operr(ar->module));
4334                 }
4335                 break;
4336         }
4337         case LDB_REPLY_REFERRAL:
4338                 /* we ignore referrals */
4339                 break;
4340
4341         case LDB_REPLY_DONE:
4342
4343                 if (ar->objs->objects[ar->index_current].local_parent_dn == NULL) {
4344                         struct GUID_txt_buf str_buf;
4345                         if (ar->search_msg != NULL) {
4346                                 ldb_asprintf_errstring(ldb_module_get_ctx(ar->module),
4347                                                        "No parent with GUID %s found for object locally known as %s",
4348                                                        GUID_buf_string(ar->objs->objects[ar->index_current].parent_guid, &str_buf),
4349                                                        ldb_dn_get_linearized(ar->search_msg->dn));
4350                         } else {
4351                                 ldb_asprintf_errstring(ldb_module_get_ctx(ar->module),
4352                                                        "No parent with GUID %s found for object remotely known as %s",
4353                                                        GUID_buf_string(ar->objs->objects[ar->index_current].parent_guid, &str_buf),
4354                                                        ldb_dn_get_linearized(ar->objs->objects[ar->index_current].msg->dn));
4355                         }
4356
4357                         /*
4358                          * This error code is really important, as it
4359                          * is the flag back to the callers to retry
4360                          * this with DRSUAPI_DRS_GET_ANC, and so get
4361                          * the parent objects before the child
4362                          * objects
4363                          */
4364                         return ldb_module_done(ar->req, NULL, NULL,
4365                                                replmd_replicated_request_werror(ar, WERR_DS_DRA_MISSING_PARENT));
4366                 }
4367
4368                 if (ar->search_msg != NULL) {
4369                         ret = replmd_replicated_apply_merge(ar);
4370                 } else {
4371                         ret = replmd_replicated_apply_add(ar);
4372                 }
4373                 if (ret != LDB_SUCCESS) {
4374                         return ldb_module_done(ar->req, NULL, NULL, ret);
4375                 }
4376         }
4377
4378         talloc_free(ares);
4379         return LDB_SUCCESS;
4380 }
4381
4382 /*
4383  * Look for the parent object, so we put the new object in the right
4384  * place This is akin to NameObject in MS-DRSR - this routine and the
4385  * callbacks find the right parent name, and correct name for this
4386  * object
4387  */
4388
4389 static int replmd_replicated_apply_search_for_parent(struct replmd_replicated_request *ar)
4390 {
4391         struct ldb_context *ldb;
4392         int ret;
4393         char *tmp_str;
4394         char *filter;
4395         struct ldb_request *search_req;
4396         static const char *attrs[] = {"isDeleted", NULL};
4397         struct GUID_txt_buf guid_str_buf;
4398
4399         ldb = ldb_module_get_ctx(ar->module);
4400
4401         if (ar->objs->objects[ar->index_current].parent_guid == NULL) {
4402                 if (ar->search_msg != NULL) {
4403                         return replmd_replicated_apply_merge(ar);
4404                 } else {
4405                         return replmd_replicated_apply_add(ar);
4406                 }
4407         }
4408
4409         tmp_str = GUID_buf_string(ar->objs->objects[ar->index_current].parent_guid,
4410                                   &guid_str_buf);
4411
4412         filter = talloc_asprintf(ar, "(objectGUID=%s)", tmp_str);
4413         if (!filter) return replmd_replicated_request_werror(ar, WERR_NOMEM);
4414
4415         ret = ldb_build_search_req(&search_req,
4416                                    ldb,
4417                                    ar,
4418                                    ar->objs->partition_dn,
4419                                    LDB_SCOPE_SUBTREE,
4420                                    filter,
4421                                    attrs,
4422                                    NULL,
4423                                    ar,
4424                                    replmd_replicated_apply_search_for_parent_callback,
4425                                    ar->req);
4426         LDB_REQ_SET_LOCATION(search_req);
4427
4428         ret = dsdb_request_add_controls(search_req, 
4429                                         DSDB_SEARCH_SHOW_RECYCLED|
4430                                         DSDB_SEARCH_SHOW_DELETED|
4431                                         DSDB_SEARCH_SHOW_EXTENDED_DN);
4432         if (ret != LDB_SUCCESS) {
4433                 return ret;
4434         }
4435
4436         return ldb_next_request(ar->module, search_req);
4437 }
4438
4439 /*
4440   handle renames that come in over DRS replication
4441  */
4442 static int replmd_replicated_handle_rename(struct replmd_replicated_request *ar,
4443                                            struct ldb_message *msg,
4444                                            struct ldb_request *parent,
4445                                            bool *renamed)
4446 {
4447         int ret;
4448         TALLOC_CTX *tmp_ctx = talloc_new(msg);
4449         struct ldb_result *res;
4450         struct ldb_dn *conflict_dn;
4451         const char *attrs[] = { "replPropertyMetaData", "objectGUID", NULL };
4452         const struct ldb_val *omd_value;
4453         struct replPropertyMetaDataBlob omd, *rmd;
4454         enum ndr_err_code ndr_err;
4455         bool rename_incoming_record, rodc;
4456         struct replPropertyMetaData1 *rmd_name, *omd_name;
4457         struct ldb_dn *new_dn;
4458         struct GUID guid;
4459
4460         DEBUG(4,("replmd_replicated_request rename %s => %s\n",
4461                  ldb_dn_get_linearized(ar->search_msg->dn),
4462                  ldb_dn_get_linearized(msg->dn)));
4463
4464
4465         ret = dsdb_module_rename(ar->module, ar->search_msg->dn, msg->dn,
4466                                  DSDB_FLAG_NEXT_MODULE, ar->req);
4467         if (ret == LDB_SUCCESS) {
4468                 talloc_free(tmp_ctx);
4469                 *renamed = true;
4470                 return ret;
4471         }
4472
4473         if (ret != LDB_ERR_ENTRY_ALREADY_EXISTS) {
4474                 talloc_free(tmp_ctx);
4475                 ldb_asprintf_errstring(ldb_module_get_ctx(ar->module), "Failed to locally apply remote rename from %s to %s: %s",
4476                                        ldb_dn_get_linearized(ar->search_msg->dn),
4477                                        ldb_dn_get_linearized(msg->dn),
4478                                        ldb_errstring(ldb_module_get_ctx(ar->module)));
4479                 return ret;
4480         }
4481
4482         ret = samdb_rodc(ldb_module_get_ctx(ar->module), &rodc);
4483         if (ret != LDB_SUCCESS) {
4484                 ldb_asprintf_errstring(ldb_module_get_ctx(ar->module),
4485                                        "Failed to determine if we are an RODC when attempting to form conflict DN: %s",
4486                                        ldb_errstring(ldb_module_get_ctx(ar->module)));
4487                 return LDB_ERR_OPERATIONS_ERROR;
4488         }
4489         /*
4490          * we have a conflict, and need to decide if we will keep the
4491          * new record or the old record
4492          */
4493
4494         conflict_dn = msg->dn;
4495
4496         if (rodc) {
4497                 /*
4498                  * We are on an RODC, or were a GC for this
4499                  * partition, so we have to fail this until
4500                  * someone who owns the partition sorts it
4501                  * out
4502                  */
4503                 ldb_asprintf_errstring(ldb_module_get_ctx(ar->module),
4504                                        "Conflict adding object '%s' from incoming replication but we are read only for the partition.  \n"
4505                                        " - We must fail the operation until a master for this partition resolves the conflict",
4506                                        ldb_dn_get_linearized(conflict_dn));
4507                 goto failed;
4508         }
4509
4510         /*
4511          * first we need the replPropertyMetaData attribute from the
4512          * old record
4513          */
4514         ret = dsdb_module_search_dn(ar->module, tmp_ctx, &res, conflict_dn,
4515                                     attrs,
4516                                     DSDB_FLAG_NEXT_MODULE |
4517                                     DSDB_SEARCH_SHOW_DELETED |
4518                                     DSDB_SEARCH_SHOW_RECYCLED, ar->req);
4519         if (ret != LDB_SUCCESS) {
4520                 DEBUG(0,(__location__ ": Unable to find object for conflicting record '%s'\n",
4521                          ldb_dn_get_linearized(conflict_dn)));
4522                 goto failed;
4523         }
4524
4525         omd_value = ldb_msg_find_ldb_val(res->msgs[0], "replPropertyMetaData");
4526         if (omd_value == NULL) {
4527                 DEBUG(0,(__location__ ": Unable to find replPropertyMetaData for conflicting record '%s'\n",
4528                          ldb_dn_get_linearized(conflict_dn)));
4529                 goto failed;
4530         }
4531
4532         ndr_err = ndr_pull_struct_blob(omd_value, res->msgs[0], &omd,
4533                                        (ndr_pull_flags_fn_t)ndr_pull_replPropertyMetaDataBlob);
4534         if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
4535                 DEBUG(0,(__location__ ": Failed to parse old replPropertyMetaData for %s\n",
4536                          ldb_dn_get_linearized(conflict_dn)));
4537                 goto failed;
4538         }
4539
4540         rmd = ar->objs->objects[ar->index_current].meta_data;
4541
4542         /*
4543          * we decide which is newer based on the RPMD on the name
4544          * attribute.  See [MS-DRSR] ResolveNameConflict.
4545          *
4546          * We expect omd_name to be present, as this is from a local
4547          * search, but while rmd_name should have been given to us by
4548          * the remote server, if it is missing we just prefer the
4549          * local name in
4550          * replmd_replPropertyMetaData1_new_should_be_taken()
4551          */
4552         rmd_name = replmd_replPropertyMetaData1_find_attid(rmd, DRSUAPI_ATTID_name);
4553         omd_name = replmd_replPropertyMetaData1_find_attid(&omd, DRSUAPI_ATTID_name);
4554         if (!omd_name) {
4555                 DEBUG(0,(__location__ ": Failed to find name attribute in local LDB replPropertyMetaData for %s\n",
4556                          ldb_dn_get_linearized(conflict_dn)));
4557                 goto failed;
4558         }
4559
4560         /*
4561          * Should we preserve the current record, and so rename the
4562          * incoming record to be a conflict?
4563          */
4564         rename_incoming_record =
4565                 !replmd_replPropertyMetaData1_new_should_be_taken(
4566                         ar->objs->dsdb_repl_flags & DSDB_REPL_FLAG_PRIORITISE_INCOMING,
4567                         omd_name, rmd_name);
4568
4569         if (rename_incoming_record) {
4570
4571                 new_dn = replmd_conflict_dn(msg, msg->dn,
4572                                             &ar->objs->objects[ar->index_current].object_guid);
4573                 if (new_dn == NULL) {
4574                         ldb_asprintf_errstring(ldb_module_get_ctx(ar->module),
4575                                                                   "Failed to form conflict DN for %s\n",
4576                                                                   ldb_dn_get_linearized(msg->dn));
4577
4578                         return replmd_replicated_request_werror(ar, WERR_NOMEM);
4579                 }
4580
4581                 ret = dsdb_module_rename(ar->module, ar->search_msg->dn, new_dn,
4582                                          DSDB_FLAG_NEXT_MODULE, ar->req);
4583                 if (ret != LDB_SUCCESS) {
4584                         ldb_asprintf_errstring(ldb_module_get_ctx(ar->module),
4585                                                "Failed to rename incoming conflicting dn '%s' (was '%s') to '%s' - %s\n",
4586                                                ldb_dn_get_linearized(conflict_dn),
4587                                                ldb_dn_get_linearized(ar->search_msg->dn),
4588                                                ldb_dn_get_linearized(new_dn),
4589                                                ldb_errstring(ldb_module_get_ctx(ar->module)));
4590                         return replmd_replicated_request_werror(ar, WERR_DS_DRA_DB_ERROR);
4591                 }
4592
4593                 msg->dn = new_dn;
4594                 *renamed = true;
4595                 return LDB_SUCCESS;
4596         }
4597
4598         /* we are renaming the existing record */
4599
4600         guid = samdb_result_guid(res->msgs[0], "objectGUID");
4601         if (GUID_all_zero(&guid)) {
4602                 DEBUG(0,(__location__ ": Failed to find objectGUID for existing conflict record %s\n",
4603                          ldb_dn_get_linearized(conflict_dn)));
4604                 goto failed;
4605         }
4606
4607         new_dn = replmd_conflict_dn(tmp_ctx, conflict_dn, &guid);
4608         if (new_dn == NULL) {
4609                 DEBUG(0,(__location__ ": Failed to form conflict DN for %s\n",
4610                          ldb_dn_get_linearized(conflict_dn)));
4611                 goto failed;
4612         }
4613
4614         DEBUG(2,(__location__ ": Resolving conflict record via existing-record rename '%s' -> '%s'\n",
4615                  ldb_dn_get_linearized(conflict_dn), ldb_dn_get_linearized(new_dn)));
4616
4617         ret = dsdb_module_rename(ar->module, conflict_dn, new_dn,
4618                                  DSDB_FLAG_OWN_MODULE, ar->req);
4619         if (ret != LDB_SUCCESS) {
4620                 DEBUG(0,(__location__ ": Failed to rename conflict dn '%s' to '%s' - %s\n",
4621                          ldb_dn_get_linearized(conflict_dn),
4622                          ldb_dn_get_linearized(new_dn),
4623                          ldb_errstring(ldb_module_get_ctx(ar->module))));
4624                 goto failed;
4625         }
4626
4627         /*
4628          * now we need to ensure that the rename is seen as an
4629          * originating update. We do that with a modify.
4630          */
4631         ret = replmd_name_modify(ar, ar->req, new_dn);
4632         if (ret != LDB_SUCCESS) {
4633                 goto failed;
4634         }
4635
4636         DEBUG(2,(__location__ ": With conflicting record renamed, re-apply replicated rename '%s' -> '%s'\n",
4637                  ldb_dn_get_linearized(ar->search_msg->dn),
4638                  ldb_dn_get_linearized(msg->dn)));
4639
4640
4641         ret = dsdb_module_rename(ar->module, ar->search_msg->dn, msg->dn,
4642                                  DSDB_FLAG_NEXT_MODULE, ar->req);
4643         if (ret != LDB_SUCCESS) {
4644                 DEBUG(0,(__location__ ": After conflict resolution, failed to rename dn '%s' to '%s' - %s\n",
4645                          ldb_dn_get_linearized(ar->search_msg->dn),
4646                          ldb_dn_get_linearized(msg->dn),
4647                          ldb_errstring(ldb_module_get_ctx(ar->module))));
4648                         goto failed;
4649         }
4650 failed:
4651
4652         /*
4653          * On failure make the caller get the error
4654          * This means replication will stop with an error,
4655          * but there is not much else we can do.  In the
4656          * LDB_ERR_ENTRY_ALREADY_EXISTS case this is exactly what is
4657          * needed.
4658          */
4659
4660         talloc_free(tmp_ctx);
4661         return ret;
4662 }
4663
4664
4665 static int replmd_replicated_apply_merge(struct replmd_replicated_request *ar)
4666 {
4667         struct ldb_context *ldb;
4668         struct ldb_request *change_req;
4669         enum ndr_err_code ndr_err;
4670         struct ldb_message *msg;
4671         struct replPropertyMetaDataBlob *rmd;
4672         struct replPropertyMetaDataBlob omd;
4673         const struct ldb_val *omd_value;
4674         struct replPropertyMetaDataBlob nmd;
4675         struct ldb_val nmd_value;
4676         struct GUID remote_parent_guid;
4677         unsigned int i;
4678         uint32_t j,ni=0;
4679         unsigned int removed_attrs = 0;
4680         int ret;
4681         int (*callback)(struct ldb_request *req, struct ldb_reply *ares) = replmd_op_callback;
4682         bool isDeleted = false;
4683         bool local_isDeleted = false;
4684         bool remote_isDeleted = false;
4685         bool take_remote_isDeleted = false;
4686         bool sd_updated = false;
4687         bool renamed = false;
4688         bool is_schema_nc = false;
4689         NTSTATUS nt_status;
4690         const struct ldb_val *old_rdn, *new_rdn;
4691         struct replmd_private *replmd_private =
4692                 talloc_get_type(ldb_module_get_private(ar->module),
4693                                 struct replmd_private);
4694         NTTIME now;
4695         time_t t = time(NULL);
4696         unix_to_nt_time(&now, t);
4697
4698         ldb = ldb_module_get_ctx(ar->module);
4699         msg = ar->objs->objects[ar->index_current].msg;
4700
4701         is_schema_nc = ldb_dn_compare_base(replmd_private->schema_dn, msg->dn) == 0;
4702
4703         rmd = ar->objs->objects[ar->index_current].meta_data;
4704         ZERO_STRUCT(omd);
4705         omd.version = 1;
4706
4707         /* find existing meta data */
4708         omd_value = ldb_msg_find_ldb_val(ar->search_msg, "replPropertyMetaData");
4709         if (omd_value) {
4710                 ndr_err = ndr_pull_struct_blob(omd_value, ar, &omd,
4711                                                (ndr_pull_flags_fn_t)ndr_pull_replPropertyMetaDataBlob);
4712                 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
4713                         nt_status = ndr_map_error2ntstatus(ndr_err);
4714                         return replmd_replicated_request_werror(ar, ntstatus_to_werror(nt_status));
4715                 }
4716
4717                 if (omd.version != 1) {
4718                         return replmd_replicated_request_werror(ar, WERR_DS_DRA_INTERNAL_ERROR);
4719                 }
4720         }
4721
4722         if (DEBUGLVL(5)) {
4723                 struct GUID_txt_buf guid_txt;
4724
4725                 char *s = ldb_ldif_message_string(ldb, ar, LDB_CHANGETYPE_MODIFY, msg);
4726                 DEBUG(5, ("Initial DRS replication modify message of %s is:\n%s\n"
4727                           "%s\n"
4728                           "%s\n",
4729                           GUID_buf_string(&ar->objs->objects[ar->index_current].object_guid, &guid_txt),
4730                           s,
4731                           ndr_print_struct_string(s,
4732                                                   (ndr_print_fn_t)ndr_print_replPropertyMetaDataBlob,
4733                                                   "existing replPropertyMetaData",
4734                                                   &omd),
4735                           ndr_print_struct_string(s,
4736                                                   (ndr_print_fn_t)ndr_print_replPropertyMetaDataBlob,
4737                                                   "incoming replPropertyMetaData",
4738                                                   rmd)));
4739                 talloc_free(s);
4740         }
4741
4742         local_isDeleted = ldb_msg_find_attr_as_bool(ar->search_msg,
4743                                                     "isDeleted", false);
4744         remote_isDeleted = ldb_msg_find_attr_as_bool(msg,
4745                                                      "isDeleted", false);
4746
4747         /*
4748          * Fill in the remote_parent_guid with the GUID or an all-zero
4749          * GUID.
4750          */
4751         if (ar->objs->objects[ar->index_current].parent_guid != NULL) {
4752                 remote_parent_guid = *ar->objs->objects[ar->index_current].parent_guid;
4753         } else {
4754                 remote_parent_guid = GUID_zero();
4755         }
4756
4757         /*
4758          * To ensure we follow a complex rename chain around, we have
4759          * to confirm that the DN is the same (mostly to confirm the
4760          * RDN) and the parentGUID is the same.
4761          *
4762          * This ensures we keep things under the correct parent, which
4763          * replmd_replicated_handle_rename() will do.
4764          */
4765
4766         if (strcmp(ldb_dn_get_linearized(msg->dn), ldb_dn_get_linearized(ar->search_msg->dn)) == 0
4767             && GUID_equal(&remote_parent_guid, &ar->local_parent_guid)) {
4768                 ret = LDB_SUCCESS;
4769         } else {
4770                 /*
4771                  * handle renames, even just by case that come in over
4772                  * DRS.  Changes in the parent DN don't hit us here,
4773                  * because the search for a parent will clean up those
4774                  * components.
4775                  *
4776                  * We also have already filtered out the case where
4777                  * the peer has an older name to what we have (see
4778                  * replmd_replicated_apply_search_callback())
4779                  */
4780                 ret = replmd_replicated_handle_rename(ar, msg, ar->req, &renamed);
4781         }
4782
4783         if (ret != LDB_SUCCESS) {
4784                 ldb_debug(ldb, LDB_DEBUG_FATAL,
4785                           "replmd_replicated_request rename %s => %s failed - %s\n",
4786                           ldb_dn_get_linearized(ar->search_msg->dn),
4787                           ldb_dn_get_linearized(msg->dn),
4788                           ldb_errstring(ldb));
4789                 return replmd_replicated_request_werror(ar, WERR_DS_DRA_DB_ERROR);
4790         }
4791
4792         if (renamed == true) {
4793                 /*
4794                  * Set the callback to one that will fix up the name
4795                  * metadata on the new conflict DN
4796                  */
4797                 callback = replmd_op_name_modify_callback;
4798         }
4799
4800         ZERO_STRUCT(nmd);
4801         nmd.version = 1;
4802         nmd.ctr.ctr1.count = omd.ctr.ctr1.count + rmd->ctr.ctr1.count;
4803         nmd.ctr.ctr1.array = talloc_array(ar,
4804                                           struct replPropertyMetaData1,
4805                                           nmd.ctr.ctr1.count);
4806         if (!nmd.ctr.ctr1.array) return replmd_replicated_request_werror(ar, WERR_NOMEM);
4807
4808         /* first copy the old meta data */
4809         for (i=0; i < omd.ctr.ctr1.count; i++) {
4810                 nmd.ctr.ctr1.array[ni]  = omd.ctr.ctr1.array[i];
4811                 ni++;
4812         }
4813
4814         ar->seq_num = 0;
4815         /* now merge in the new meta data */
4816         for (i=0; i < rmd->ctr.ctr1.count; i++) {
4817                 bool found = false;
4818
4819                 for (j=0; j < ni; j++) {
4820                         bool cmp;
4821
4822                         if (rmd->ctr.ctr1.array[i].attid != nmd.ctr.ctr1.array[j].attid) {
4823                                 continue;
4824                         }
4825
4826                         cmp = replmd_replPropertyMetaData1_new_should_be_taken(
4827                                 ar->objs->dsdb_repl_flags,
4828                                 &nmd.ctr.ctr1.array[j],
4829                                 &rmd->ctr.ctr1.array[i]);
4830                         if (cmp) {
4831                                 /* replace the entry */
4832                                 nmd.ctr.ctr1.array[j] = rmd->ctr.ctr1.array[i];
4833                                 if (ar->seq_num == 0) {
4834                                         ret = ldb_sequence_number(ldb, LDB_SEQ_NEXT, &ar->seq_num);
4835                                         if (ret != LDB_SUCCESS) {
4836                                                 return replmd_replicated_request_error(ar, ret);
4837                                         }
4838                                 }
4839                                 nmd.ctr.ctr1.array[j].local_usn = ar->seq_num;
4840                                 switch (nmd.ctr.ctr1.array[j].attid) {
4841                                 case DRSUAPI_ATTID_ntSecurityDescriptor:
4842                                         sd_updated = true;
4843                                         break;
4844                                 case DRSUAPI_ATTID_isDeleted:
4845                                         take_remote_isDeleted = true;
4846                                         break;
4847                                 default:
4848                                         break;
4849                                 }
4850                                 found = true;
4851                                 break;
4852                         }
4853
4854                         if (rmd->ctr.ctr1.array[i].attid != DRSUAPI_ATTID_instanceType) {
4855                                 DEBUG(3,("Discarding older DRS attribute update to %s on %s from %s\n",
4856                                          msg->elements[i-removed_attrs].name,
4857                                          ldb_dn_get_linearized(msg->dn),
4858                                          GUID_string(ar, &rmd->ctr.ctr1.array[i].originating_invocation_id)));
4859                         }
4860
4861                         /* we don't want to apply this change so remove the attribute */
4862                         ldb_msg_remove_element(msg, &msg->elements[i-removed_attrs]);
4863                         removed_attrs++;
4864
4865                         found = true;
4866                         break;
4867                 }
4868
4869                 if (found) continue;
4870
4871                 nmd.ctr.ctr1.array[ni] = rmd->ctr.ctr1.array[i];
4872                 if (ar->seq_num == 0) {
4873                         ret = ldb_sequence_number(ldb, LDB_SEQ_NEXT, &ar->seq_num);
4874                         if (ret != LDB_SUCCESS) {
4875                                 return replmd_replicated_request_error(ar, ret);
4876                         }
4877                 }
4878                 nmd.ctr.ctr1.array[ni].local_usn = ar->seq_num;
4879                 switch (nmd.ctr.ctr1.array[ni].attid) {
4880                 case DRSUAPI_ATTID_ntSecurityDescriptor:
4881                         sd_updated = true;
4882                         break;
4883                 case DRSUAPI_ATTID_isDeleted:
4884                         take_remote_isDeleted = true;
4885                         break;
4886                 default:
4887                         break;
4888                 }
4889                 ni++;
4890         }
4891
4892         /*
4893          * finally correct the size of the meta_data array
4894          */
4895         nmd.ctr.ctr1.count = ni;
4896
4897         new_rdn = ldb_dn_get_rdn_val(msg->dn);
4898         old_rdn = ldb_dn_get_rdn_val(ar->search_msg->dn);
4899
4900         if (renamed) {
4901                 ret = replmd_update_rpmd_rdn_attr(ldb, msg, new_rdn, old_rdn,
4902                                                   &nmd, ar, now, is_schema_nc);
4903                 if (ret != LDB_SUCCESS) {
4904                         ldb_asprintf_errstring(ldb, "%s: error during DRS repl merge: %s", __func__, ldb_errstring(ldb));
4905                         return replmd_replicated_request_error(ar, ret);
4906                 }
4907         }
4908         /*
4909          * sort the new meta data array
4910          */
4911         ret = replmd_replPropertyMetaDataCtr1_sort_and_verify(ldb, &nmd.ctr.ctr1, msg->dn);
4912         if (ret != LDB_SUCCESS) {
4913                 ldb_asprintf_errstring(ldb, "%s: error during DRS repl merge: %s", __func__, ldb_errstring(ldb));
4914                 return ret;
4915         }
4916
4917         /*
4918          * Work out if this object is deleted, so we can prune any extra attributes.  See MS-DRSR 4.1.10.6.9
4919          * UpdateObject.
4920          *
4921          * This also controls SD propagation below
4922          */
4923         if (take_remote_isDeleted) {
4924                 isDeleted = remote_isDeleted;
4925         } else {
4926                 isDeleted = local_isDeleted;
4927         }
4928
4929         ar->isDeleted = isDeleted;
4930
4931         /*
4932          * check if some replicated attributes left, otherwise skip the ldb_modify() call
4933          */
4934         if (msg->num_elements == 0) {
4935                 ldb_debug(ldb, LDB_DEBUG_TRACE, "replmd_replicated_apply_merge[%u]: skip replace\n",
4936                           ar->index_current);
4937
4938                 return replmd_replicated_apply_isDeleted(ar);
4939         }
4940
4941         ldb_debug(ldb, LDB_DEBUG_TRACE, "replmd_replicated_apply_merge[%u]: replace %u attributes\n",
4942                   ar->index_current, msg->num_elements);
4943
4944         if (renamed) {
4945                 sd_updated = true;
4946         }
4947
4948         if (sd_updated && !isDeleted) {
4949                 ret = dsdb_module_schedule_sd_propagation(ar->module,
4950                                                           ar->objs->partition_dn,
4951                                                           msg->dn, true);
4952                 if (ret != LDB_SUCCESS) {
4953                         return ldb_operr(ldb);
4954                 }
4955         }
4956
4957         /* create the meta data value */
4958         ndr_err = ndr_push_struct_blob(&nmd_value, msg, &nmd,
4959                                        (ndr_push_flags_fn_t)ndr_push_replPropertyMetaDataBlob);
4960         if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
4961                 nt_status = ndr_map_error2ntstatus(ndr_err);
4962                 return replmd_replicated_request_werror(ar, ntstatus_to_werror(nt_status));
4963         }
4964
4965         /*
4966          * when we know that we'll modify the record, add the whenChanged, uSNChanged
4967          * and replPopertyMetaData attributes
4968          */
4969         ret = ldb_msg_add_string(msg, "whenChanged", ar->objs->objects[ar->index_current].when_changed);
4970         if (ret != LDB_SUCCESS) {
4971                 return replmd_replicated_request_error(ar, ret);
4972         }
4973         ret = samdb_msg_add_uint64(ldb, msg, msg, "uSNChanged", ar->seq_num);
4974         if (ret != LDB_SUCCESS) {
4975                 return replmd_replicated_request_error(ar, ret);
4976         }
4977         ret = ldb_msg_add_value(msg, "replPropertyMetaData", &nmd_value, NULL);
4978         if (ret != LDB_SUCCESS) {
4979                 return replmd_replicated_request_error(ar, ret);
4980         }
4981
4982         replmd_ldb_message_sort(msg, ar->schema);
4983
4984         /* we want to replace the old values */
4985         for (i=0; i < msg->num_elements; i++) {
4986                 msg->elements[i].flags = LDB_FLAG_MOD_REPLACE;
4987                 if (ldb_attr_cmp(msg->elements[i].name, "objectClass") == 0) {
4988                         if (msg->elements[i].num_values == 0) {
4989                                 ldb_asprintf_errstring(ldb, __location__
4990                                                        ": objectClass removed on %s, aborting replication\n",
4991                                                        ldb_dn_get_linearized(msg->dn));
4992                                 return replmd_replicated_request_error(ar, LDB_ERR_OBJECT_CLASS_VIOLATION);
4993                         }
4994                 }
4995         }
4996
4997         if (DEBUGLVL(4)) {
4998                 struct GUID_txt_buf guid_txt;
4999
5000                 char *s = ldb_ldif_message_string(ldb, ar, LDB_CHANGETYPE_MODIFY, msg);
5001                 DEBUG(4, ("Final DRS replication modify message of %s:\n%s\n",
5002                           GUID_buf_string(&ar->objs->objects[ar->index_current].object_guid, &guid_txt),
5003                           s));
5004                 talloc_free(s);
5005         }
5006
5007         ret = ldb_build_mod_req(&change_req,
5008                                 ldb,
5009                                 ar,
5010                                 msg,
5011                                 ar->controls,
5012                                 ar,
5013                                 callback,
5014                                 ar->req);
5015         LDB_REQ_SET_LOCATION(change_req);
5016         if (ret != LDB_SUCCESS) return replmd_replicated_request_error(ar, ret);
5017
5018         /* current partition control needed by "repmd_op_callback" */
5019         ret = ldb_request_add_control(change_req,
5020                                       DSDB_CONTROL_CURRENT_PARTITION_OID,
5021                                       false, NULL);
5022         if (ret != LDB_SUCCESS) return replmd_replicated_request_error(ar, ret);
5023
5024         return ldb_next_request(ar->module, change_req);
5025 }
5026
5027 static int replmd_replicated_apply_search_callback(struct ldb_request *req,
5028                                                    struct ldb_reply *ares)
5029 {
5030         struct replmd_replicated_request *ar = talloc_get_type(req->context,
5031                                                struct replmd_replicated_request);
5032         int ret;
5033
5034         if (!ares) {
5035                 return ldb_module_done(ar->req, NULL, NULL,
5036                                         LDB_ERR_OPERATIONS_ERROR);
5037         }
5038         if (ares->error != LDB_SUCCESS &&
5039             ares->error != LDB_ERR_NO_SUCH_OBJECT) {
5040                 return ldb_module_done(ar->req, ares->controls,
5041                                         ares->response, ares->error);
5042         }
5043
5044         switch (ares->type) {
5045         case LDB_REPLY_ENTRY:
5046                 ar->search_msg = talloc_steal(ar, ares->message);
5047                 break;
5048
5049         case LDB_REPLY_REFERRAL:
5050                 /* we ignore referrals */
5051                 break;
5052
5053         case LDB_REPLY_DONE:
5054         {
5055                 struct replPropertyMetaData1 *md_remote;
5056                 struct replPropertyMetaData1 *md_local;
5057
5058                 struct replPropertyMetaDataBlob omd;
5059                 const struct ldb_val *omd_value;
5060                 struct replPropertyMetaDataBlob *rmd;
5061                 struct ldb_message *msg;
5062                 int instanceType;
5063                 ar->objs->objects[ar->index_current].local_parent_dn = NULL;
5064                 ar->objs->objects[ar->index_current].last_known_parent = NULL;
5065
5066                 /*
5067                  * This is the ADD case, find the appropriate parent,
5068                  * as this object doesn't exist locally:
5069                  */
5070                 if (ar->search_msg == NULL) {
5071                         ret = replmd_replicated_apply_search_for_parent(ar);
5072                         if (ret != LDB_SUCCESS) {
5073                                 return ldb_module_done(ar->req, NULL, NULL, ret);
5074                         }
5075                         talloc_free(ares);
5076                         return LDB_SUCCESS;
5077                 }
5078
5079                 /*
5080                  * Otherwise, in the MERGE case, work out if we are
5081                  * attempting a rename, and if so find the parent the
5082                  * newly renamed object wants to belong under (which
5083                  * may not be the parent in it's attached string DN
5084                  */
5085                 rmd = ar->objs->objects[ar->index_current].meta_data;
5086                 ZERO_STRUCT(omd);
5087                 omd.version = 1;
5088
5089                 /* find existing meta data */
5090                 omd_value = ldb_msg_find_ldb_val(ar->search_msg, "replPropertyMetaData");
5091                 if (omd_value) {
5092                         enum ndr_err_code ndr_err;
5093                         ndr_err = ndr_pull_struct_blob(omd_value, ar, &omd,
5094                                                        (ndr_pull_flags_fn_t)ndr_pull_replPropertyMetaDataBlob);
5095                         if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
5096                                 NTSTATUS nt_status = ndr_map_error2ntstatus(ndr_err);
5097                                 return replmd_replicated_request_werror(ar, ntstatus_to_werror(nt_status));
5098                         }
5099
5100                         if (omd.version != 1) {
5101                                 return replmd_replicated_request_werror(ar, WERR_DS_DRA_INTERNAL_ERROR);
5102                         }
5103                 }
5104
5105                 ar->local_parent_guid = samdb_result_guid(ar->search_msg, "parentGUID");
5106
5107                 instanceType = ldb_msg_find_attr_as_int(ar->search_msg, "instanceType", 0);
5108                 if (((instanceType & INSTANCE_TYPE_IS_NC_HEAD) == 0)
5109                     && GUID_all_zero(&ar->local_parent_guid)) {
5110                         DEBUG(0, ("Refusing to replicate new version of %s "
5111                                   "as local object has an all-zero parentGUID attribute, "
5112                                   "despite not being an NC root\n",
5113                                   ldb_dn_get_linearized(ar->search_msg->dn)));
5114                         return replmd_replicated_request_werror(ar, WERR_DS_DRA_INTERNAL_ERROR);
5115                 }
5116
5117                 /*
5118                  * now we need to check for double renames. We could have a
5119                  * local rename pending which our replication partner hasn't
5120                  * received yet. We choose which one wins by looking at the
5121                  * attribute stamps on the two objects, the newer one wins.
5122                  *
5123                  * This also simply applies the correct algorithms for
5124                  * determining if a change was made to name at all, or
5125                  * if the object has just been renamed under the same
5126                  * parent.
5127                  */
5128                 md_remote = replmd_replPropertyMetaData1_find_attid(rmd, DRSUAPI_ATTID_name);
5129                 md_local = replmd_replPropertyMetaData1_find_attid(&omd, DRSUAPI_ATTID_name);
5130                 if (!md_local) {
5131                         DEBUG(0,(__location__ ": Failed to find name attribute in local LDB replPropertyMetaData for %s\n",
5132                                  ldb_dn_get_linearized(ar->search_msg->dn)));
5133                         return replmd_replicated_request_werror(ar, WERR_DS_DRA_DB_ERROR);
5134                 }
5135
5136                 /*
5137                  * if there is no name attribute given then we have to assume the
5138                  *  object we've received has the older name
5139                  */
5140                 if (replmd_replPropertyMetaData1_new_should_be_taken(
5141                             ar->objs->dsdb_repl_flags & DSDB_REPL_FLAG_PRIORITISE_INCOMING,
5142                             md_local, md_remote)) {
5143                         struct GUID_txt_buf p_guid_local;
5144                         struct GUID_txt_buf p_guid_remote;
5145                         msg = ar->objs->objects[ar->index_current].msg;
5146
5147                         /* Merge on the existing object, with rename */
5148
5149                         DEBUG(4,(__location__ ": Looking for new parent for object %s currently under %s "
5150                                  "as incoming object changing to %s under %s\n",
5151                                  ldb_dn_get_linearized(ar->search_msg->dn),
5152                                  GUID_buf_string(&ar->local_parent_guid, &p_guid_local),
5153                                  ldb_dn_get_linearized(msg->dn),
5154                                  GUID_buf_string(ar->objs->objects[ar->index_current].parent_guid,
5155                                                  &p_guid_remote)));
5156                         ret = replmd_replicated_apply_search_for_parent(ar);
5157                 } else {
5158                         struct GUID_txt_buf p_guid_local;
5159                         struct GUID_txt_buf p_guid_remote;
5160                         msg = ar->objs->objects[ar->index_current].msg;
5161
5162                         /*
5163                          * Merge on the existing object, force no
5164                          * rename (code below just to explain why in
5165                          * the DEBUG() logs)
5166                          */
5167
5168                         if (strcmp(ldb_dn_get_linearized(ar->search_msg->dn),
5169                                    ldb_dn_get_linearized(msg->dn)) == 0) {
5170                                 if (ar->objs->objects[ar->index_current].parent_guid != NULL &&
5171                                     GUID_equal(&ar->local_parent_guid,
5172                                                ar->objs->objects[ar->index_current].parent_guid)
5173                                     == false) {
5174                                         DEBUG(4,(__location__ ": Keeping object %s at under %s "
5175                                                  "despite incoming object changing parent to %s\n",
5176                                                  ldb_dn_get_linearized(ar->search_msg->dn),
5177                                                  GUID_buf_string(&ar->local_parent_guid, &p_guid_local),
5178                                                  GUID_buf_string(ar->objs->objects[ar->index_current].parent_guid,
5179                                                                  &p_guid_remote)));
5180                                 }
5181                         } else {
5182                                 DEBUG(4,(__location__ ": Keeping object %s at under %s "
5183                                          " and rejecting older rename to %s under %s\n",
5184                                          ldb_dn_get_linearized(ar->search_msg->dn),
5185                                          GUID_buf_string(&ar->local_parent_guid, &p_guid_local),
5186                                          ldb_dn_get_linearized(msg->dn),
5187                                          GUID_buf_string(ar->objs->objects[ar->index_current].parent_guid,
5188                                                          &p_guid_remote)));
5189                         }
5190                         /*
5191                          * This assignment ensures that the strcmp()
5192                          * and GUID_equal() calls in
5193                          * replmd_replicated_apply_merge() avoids the
5194                          * rename call
5195                          */
5196                         ar->objs->objects[ar->index_current].parent_guid =
5197                                 &ar->local_parent_guid;
5198
5199                         msg->dn = ar->search_msg->dn;
5200                         ret = replmd_replicated_apply_merge(ar);
5201                 }
5202                 if (ret != LDB_SUCCESS) {
5203                         return ldb_module_done(ar->req, NULL, NULL, ret);
5204                 }
5205         }
5206         }
5207
5208         talloc_free(ares);
5209         return LDB_SUCCESS;
5210 }
5211
5212 static int replmd_replicated_uptodate_vector(struct replmd_replicated_request *ar);
5213
5214 static int replmd_replicated_apply_next(struct replmd_replicated_request *ar)
5215 {
5216         struct ldb_context *ldb;
5217         int ret;
5218         char *tmp_str;
5219         char *filter;
5220         struct ldb_request *search_req;
5221         static const char *attrs[] = { "*", "parentGUID", "instanceType",
5222                                        "replPropertyMetaData", "nTSecurityDescriptor",
5223                                        NULL };
5224         struct GUID_txt_buf guid_str_buf;
5225
5226         if (ar->index_current >= ar->objs->num_objects) {
5227                 /* done with it, go to next stage */
5228                 return replmd_replicated_uptodate_vector(ar);
5229         }
5230
5231         ldb = ldb_module_get_ctx(ar->module);
5232         ar->search_msg = NULL;
5233         ar->isDeleted = false;
5234
5235         tmp_str = GUID_buf_string(&ar->objs->objects[ar->index_current].object_guid,
5236                                   &guid_str_buf);
5237
5238         filter = talloc_asprintf(ar, "(objectGUID=%s)", tmp_str);
5239         if (!filter) return replmd_replicated_request_werror(ar, WERR_NOMEM);
5240
5241         ret = ldb_build_search_req(&search_req,
5242                                    ldb,
5243                                    ar,
5244                                    ar->objs->partition_dn,
5245                                    LDB_SCOPE_SUBTREE,
5246                                    filter,
5247                                    attrs,
5248                                    NULL,
5249                                    ar,
5250                                    replmd_replicated_apply_search_callback,
5251                                    ar->req);
5252         LDB_REQ_SET_LOCATION(search_req);
5253
5254         ret = dsdb_request_add_controls(search_req, DSDB_SEARCH_SHOW_RECYCLED);
5255
5256         if (ret != LDB_SUCCESS) {
5257                 return ret;
5258         }
5259
5260         return ldb_next_request(ar->module, search_req);
5261 }
5262
5263 /*
5264  * This is essentially a wrapper for replmd_replicated_apply_next()
5265  *
5266  * This is needed to ensure that both codepaths call this handler.
5267  */
5268 static int replmd_replicated_apply_isDeleted(struct replmd_replicated_request *ar)
5269 {
5270         struct ldb_dn *deleted_objects_dn;
5271         struct ldb_message *msg = ar->objs->objects[ar->index_current].msg;
5272         int ret = dsdb_get_deleted_objects_dn(ldb_module_get_ctx(ar->module), msg, msg->dn,
5273                                               &deleted_objects_dn);
5274         if (ar->isDeleted && (ret != LDB_SUCCESS || ldb_dn_compare(msg->dn, deleted_objects_dn) != 0)) {
5275                 /*
5276                  * Do a delete here again, so that if there is
5277                  * anything local that conflicts with this
5278                  * object being deleted, it is removed.  This
5279                  * includes links.  See MS-DRSR 4.1.10.6.9
5280                  * UpdateObject.
5281                  *
5282                  * If the object is already deleted, and there
5283                  * is no more work required, it doesn't do
5284                  * anything.
5285                  */
5286
5287                 /* This has been updated to point to the DN we eventually did the modify on */
5288
5289                 struct ldb_request *del_req;
5290                 struct ldb_result *res;
5291
5292                 TALLOC_CTX *tmp_ctx = talloc_new(ar);
5293                 if (!tmp_ctx) {
5294                         ret = ldb_oom(ldb_module_get_ctx(ar->module));
5295                         return ret;
5296                 }
5297
5298                 res = talloc_zero(tmp_ctx, struct ldb_result);
5299                 if (!res) {
5300                         ret = ldb_oom(ldb_module_get_ctx(ar->module));
5301                         talloc_free(tmp_ctx);
5302                         return ret;
5303                 }
5304
5305                 /* Build a delete request, which hopefully will artually turn into nothing */
5306                 ret = ldb_build_del_req(&del_req, ldb_module_get_ctx(ar->module), tmp_ctx,
5307                                         msg->dn,
5308                                         NULL,
5309                                         res,
5310                                         ldb_modify_default_callback,
5311                                         ar->req);
5312                 LDB_REQ_SET_LOCATION(del_req);
5313                 if (ret != LDB_SUCCESS) {
5314                         talloc_free(tmp_ctx);
5315                         return ret;
5316                 }
5317
5318                 /*
5319                  * This is the guts of the call, call back
5320                  * into our delete code, but setting the
5321                  * re_delete flag so we delete anything that
5322                  * shouldn't be there on a deleted or recycled
5323                  * object
5324                  */
5325                 ret = replmd_delete_internals(ar->module, del_req, true);
5326                 if (ret == LDB_SUCCESS) {
5327                         ret = ldb_wait(del_req->handle, LDB_WAIT_ALL);
5328                 }
5329
5330                 talloc_free(tmp_ctx);
5331                 if (ret != LDB_SUCCESS) {
5332                         return ret;
5333                 }
5334         }
5335
5336         ar->index_current++;
5337         return replmd_replicated_apply_next(ar);
5338 }
5339
5340 static int replmd_replicated_uptodate_modify_callback(struct ldb_request *req,
5341                                                       struct ldb_reply *ares)
5342 {
5343         struct ldb_context *ldb;
5344         struct replmd_replicated_request *ar = talloc_get_type(req->context,
5345                                                struct replmd_replicated_request);
5346         ldb = ldb_module_get_ctx(ar->module);
5347
5348         if (!ares) {
5349                 return ldb_module_done(ar->req, NULL, NULL,
5350                                         LDB_ERR_OPERATIONS_ERROR);
5351         }
5352         if (ares->error != LDB_SUCCESS) {
5353                 return ldb_module_done(ar->req, ares->controls,
5354                                         ares->response, ares->error);
5355         }
5356
5357         if (ares->type != LDB_REPLY_DONE) {
5358                 ldb_asprintf_errstring(ldb, "Invalid LDB reply type %d", ares->type);
5359                 return ldb_module_done(ar->req, NULL, NULL,
5360                                         LDB_ERR_OPERATIONS_ERROR);
5361         }
5362
5363         talloc_free(ares);
5364
5365         return ldb_module_done(ar->req, NULL, NULL, LDB_SUCCESS);
5366 }
5367
5368 static int replmd_replicated_uptodate_modify(struct replmd_replicated_request *ar)
5369 {
5370         struct ldb_context *ldb;
5371         struct ldb_request *change_req;
5372         enum ndr_err_code ndr_err;
5373         struct ldb_message *msg;
5374         struct replUpToDateVectorBlob ouv;
5375         const struct ldb_val *ouv_value;
5376         const struct drsuapi_DsReplicaCursor2CtrEx *ruv;
5377         struct replUpToDateVectorBlob nuv;
5378         struct ldb_val nuv_value;
5379         struct ldb_message_element *nuv_el = NULL;
5380         struct ldb_message_element *orf_el = NULL;
5381         struct repsFromToBlob nrf;
5382         struct ldb_val *nrf_value = NULL;
5383         struct ldb_message_element *nrf_el = NULL;
5384         unsigned int i;
5385         uint32_t j,ni=0;
5386         bool found = false;
5387         time_t t = time(NULL);
5388         NTTIME now;
5389         int ret;
5390         uint32_t instanceType;
5391
5392         ldb = ldb_module_get_ctx(ar->module);
5393         ruv = ar->objs->uptodateness_vector;
5394         ZERO_STRUCT(ouv);
5395         ouv.version = 2;
5396         ZERO_STRUCT(nuv);
5397         nuv.version = 2;
5398
5399         unix_to_nt_time(&now, t);
5400
5401         if (ar->search_msg == NULL) {
5402                 /* this happens for a REPL_OBJ call where we are
5403                    creating the target object by replicating it. The
5404                    subdomain join code does this for the partition DN
5405                 */
5406                 DEBUG(4,(__location__ ": Skipping UDV and repsFrom update as no target DN\n"));
5407                 return ldb_module_done(ar->req, NULL, NULL, LDB_SUCCESS);
5408         }
5409
5410         instanceType = ldb_msg_find_attr_as_uint(ar->search_msg, "instanceType", 0);
5411         if (! (instanceType & INSTANCE_TYPE_IS_NC_HEAD)) {
5412                 DEBUG(4,(__location__ ": Skipping UDV and repsFrom update as not NC root: %s\n",
5413                          ldb_dn_get_linearized(ar->search_msg->dn)));
5414                 return ldb_module_done(ar->req, NULL, NULL, LDB_SUCCESS);
5415         }
5416
5417         /*
5418          * first create the new replUpToDateVector
5419          */
5420         ouv_value = ldb_msg_find_ldb_val(ar->search_msg, "replUpToDateVector");
5421         if (ouv_value) {
5422                 ndr_err = ndr_pull_struct_blob(ouv_value, ar, &ouv,
5423                                                (ndr_pull_flags_fn_t)ndr_pull_replUpToDateVectorBlob);
5424                 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
5425                         NTSTATUS nt_status = ndr_map_error2ntstatus(ndr_err);
5426                         return replmd_replicated_request_werror(ar, ntstatus_to_werror(nt_status));
5427                 }
5428
5429                 if (ouv.version != 2) {
5430                         return replmd_replicated_request_werror(ar, WERR_DS_DRA_INTERNAL_ERROR);
5431                 }
5432         }
5433
5434         /*
5435          * the new uptodateness vector will at least
5436          * contain 1 entry, one for the source_dsa
5437          *
5438          * plus optional values from our old vector and the one from the source_dsa
5439          */
5440         nuv.ctr.ctr2.count = ouv.ctr.ctr2.count;
5441         if (ruv) nuv.ctr.ctr2.count += ruv->count;
5442         nuv.ctr.ctr2.cursors = talloc_array(ar,
5443                                             struct drsuapi_DsReplicaCursor2,
5444                                             nuv.ctr.ctr2.count);
5445         if (!nuv.ctr.ctr2.cursors) return replmd_replicated_request_werror(ar, WERR_NOMEM);
5446
5447         /* first copy the old vector */
5448         for (i=0; i < ouv.ctr.ctr2.count; i++) {
5449                 nuv.ctr.ctr2.cursors[ni] = ouv.ctr.ctr2.cursors[i];
5450                 ni++;
5451         }
5452
5453         /* merge in the source_dsa vector is available */
5454         for (i=0; (ruv && i < ruv->count); i++) {
5455                 found = false;
5456
5457                 if (GUID_equal(&ruv->cursors[i].source_dsa_invocation_id,
5458                                &ar->our_invocation_id)) {
5459                         continue;
5460                 }
5461
5462                 for (j=0; j < ni; j++) {
5463                         if (!GUID_equal(&ruv->cursors[i].source_dsa_invocation_id,
5464                                         &nuv.ctr.ctr2.cursors[j].source_dsa_invocation_id)) {
5465                                 continue;
5466                         }
5467
5468                         found = true;
5469
5470                         if (ruv->cursors[i].highest_usn > nuv.ctr.ctr2.cursors[j].highest_usn) {
5471                                 nuv.ctr.ctr2.cursors[j] = ruv->cursors[i];
5472                         }
5473                         break;
5474                 }
5475
5476                 if (found) continue;
5477
5478                 /* if it's not there yet, add it */
5479                 nuv.ctr.ctr2.cursors[ni] = ruv->cursors[i];
5480                 ni++;
5481         }
5482
5483         /*
5484          * finally correct the size of the cursors array
5485          */
5486         nuv.ctr.ctr2.count = ni;
5487
5488         /*
5489          * sort the cursors
5490          */
5491         TYPESAFE_QSORT(nuv.ctr.ctr2.cursors, nuv.ctr.ctr2.count, drsuapi_DsReplicaCursor2_compare);
5492
5493         /*
5494          * create the change ldb_message
5495          */
5496         msg = ldb_msg_new(ar);
5497         if (!msg) return replmd_replicated_request_werror(ar, WERR_NOMEM);
5498         msg->dn = ar->search_msg->dn;
5499
5500         ndr_err = ndr_push_struct_blob(&nuv_value, msg, &nuv,
5501                                        (ndr_push_flags_fn_t)ndr_push_replUpToDateVectorBlob);
5502         if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
5503                 NTSTATUS nt_status = ndr_map_error2ntstatus(ndr_err);
5504                 return replmd_replicated_request_werror(ar, ntstatus_to_werror(nt_status));
5505         }
5506         ret = ldb_msg_add_value(msg, "replUpToDateVector", &nuv_value, &nuv_el);
5507         if (ret != LDB_SUCCESS) {
5508                 return replmd_replicated_request_error(ar, ret);
5509         }
5510         nuv_el->flags = LDB_FLAG_MOD_REPLACE;
5511
5512         /*
5513          * now create the new repsFrom value from the given repsFromTo1 structure
5514          */
5515         ZERO_STRUCT(nrf);
5516         nrf.version                                     = 1;
5517         nrf.ctr.ctr1                                    = *ar->objs->source_dsa;
5518         nrf.ctr.ctr1.last_attempt                       = now;
5519         nrf.ctr.ctr1.last_success                       = now;
5520         nrf.ctr.ctr1.result_last_attempt                = WERR_OK;
5521
5522         /*
5523          * first see if we already have a repsFrom value for the current source dsa
5524          * if so we'll later replace this value
5525          */
5526         orf_el = ldb_msg_find_element(ar->search_msg, "repsFrom");
5527         if (orf_el) {
5528                 for (i=0; i < orf_el->num_values; i++) {
5529                         struct repsFromToBlob *trf;
5530
5531                         trf = talloc(ar, struct repsFromToBlob);
5532                         if (!trf) return replmd_replicated_request_werror(ar, WERR_NOMEM);
5533
5534                         ndr_err = ndr_pull_struct_blob(&orf_el->values[i], trf, trf,
5535                                                        (ndr_pull_flags_fn_t)ndr_pull_repsFromToBlob);
5536                         if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
5537                                 NTSTATUS nt_status = ndr_map_error2ntstatus(ndr_err);
5538                                 return replmd_replicated_request_werror(ar, ntstatus_to_werror(nt_status));
5539                         }
5540
5541                         if (trf->version != 1) {
5542                                 return replmd_replicated_request_werror(ar, WERR_DS_DRA_INTERNAL_ERROR);
5543                         }
5544
5545                         /*
5546                          * we compare the source dsa objectGUID not the invocation_id
5547                          * because we want only one repsFrom value per source dsa
5548                          * and when the invocation_id of the source dsa has changed we don't need
5549                          * the old repsFrom with the old invocation_id
5550                          */
5551                         if (!GUID_equal(&trf->ctr.ctr1.source_dsa_obj_guid,
5552                                         &ar->objs->source_dsa->source_dsa_obj_guid)) {
5553                                 talloc_free(trf);
5554                                 continue;
5555                         }
5556
5557                         talloc_free(trf);
5558                         nrf_value = &orf_el->values[i];
5559                         break;
5560                 }
5561
5562                 /*
5563                  * copy over all old values to the new ldb_message
5564                  */
5565                 ret = ldb_msg_add_empty(msg, "repsFrom", 0, &nrf_el);
5566                 if (ret != LDB_SUCCESS) return replmd_replicated_request_error(ar, ret);
5567                 *nrf_el = *orf_el;
5568         }
5569
5570         /*
5571          * if we haven't found an old repsFrom value for the current source dsa
5572          * we'll add a new value
5573          */
5574         if (!nrf_value) {
5575                 struct ldb_val zero_value;
5576                 ZERO_STRUCT(zero_value);
5577                 ret = ldb_msg_add_value(msg, "repsFrom", &zero_value, &nrf_el);
5578                 if (ret != LDB_SUCCESS) return replmd_replicated_request_error(ar, ret);
5579
5580                 nrf_value = &nrf_el->values[nrf_el->num_values - 1];
5581         }
5582
5583         /* we now fill the value which is already attached to ldb_message */
5584         ndr_err = ndr_push_struct_blob(nrf_value, msg,
5585                                        &nrf,
5586                                        (ndr_push_flags_fn_t)ndr_push_repsFromToBlob);
5587         if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
5588                 NTSTATUS nt_status = ndr_map_error2ntstatus(ndr_err);
5589                 return replmd_replicated_request_werror(ar, ntstatus_to_werror(nt_status));
5590         }
5591
5592         /*
5593          * the ldb_message_element for the attribute, has all the old values and the new one
5594          * so we'll replace the whole attribute with all values
5595          */
5596         nrf_el->flags = LDB_FLAG_MOD_REPLACE;
5597
5598         if (CHECK_DEBUGLVL(4)) {
5599                 char *s = ldb_ldif_message_string(ldb, ar, LDB_CHANGETYPE_MODIFY, msg);
5600                 DEBUG(4, ("DRS replication uptodate modify message:\n%s\n", s));
5601                 talloc_free(s);
5602         }
5603
5604         /* prepare the ldb_modify() request */
5605         ret = ldb_build_mod_req(&change_req,
5606                                 ldb,
5607                                 ar,
5608                                 msg,
5609                                 ar->controls,
5610                                 ar,
5611                                 replmd_replicated_uptodate_modify_callback,
5612                                 ar->req);
5613         LDB_REQ_SET_LOCATION(change_req);
5614         if (ret != LDB_SUCCESS) return replmd_replicated_request_error(ar, ret);
5615
5616         return ldb_next_request(ar->module, change_req);
5617 }
5618
5619 static int replmd_replicated_uptodate_search_callback(struct ldb_request *req,
5620                                                       struct ldb_reply *ares)
5621 {
5622         struct replmd_replicated_request *ar = talloc_get_type(req->context,
5623                                                struct replmd_replicated_request);
5624         int ret;
5625
5626         if (!ares) {
5627                 return ldb_module_done(ar->req, NULL, NULL,
5628                                         LDB_ERR_OPERATIONS_ERROR);
5629         }
5630         if (ares->error != LDB_SUCCESS &&
5631             ares->error != LDB_ERR_NO_SUCH_OBJECT) {
5632                 return ldb_module_done(ar->req, ares->controls,
5633                                         ares->response, ares->error);
5634         }
5635
5636         switch (ares->type) {
5637         case LDB_REPLY_ENTRY:
5638                 ar->search_msg = talloc_steal(ar, ares->message);
5639                 break;
5640
5641         case LDB_REPLY_REFERRAL:
5642                 /* we ignore referrals */
5643                 break;
5644
5645         case LDB_REPLY_DONE:
5646                 ret = replmd_replicated_uptodate_modify(ar);
5647                 if (ret != LDB_SUCCESS) {
5648                         return ldb_module_done(ar->req, NULL, NULL, ret);
5649                 }
5650         }
5651
5652         talloc_free(ares);
5653         return LDB_SUCCESS;
5654 }
5655
5656
5657 static int replmd_replicated_uptodate_vector(struct replmd_replicated_request *ar)
5658 {
5659         struct ldb_context *ldb;
5660         int ret;
5661         static const char *attrs[] = {
5662                 "replUpToDateVector",
5663                 "repsFrom",
5664                 "instanceType",
5665                 NULL
5666         };
5667         struct ldb_request *search_req;
5668
5669         ldb = ldb_module_get_ctx(ar->module);
5670         ar->search_msg = NULL;
5671
5672         ret = ldb_build_search_req(&search_req,
5673                                    ldb,
5674                                    ar,
5675                                    ar->objs->partition_dn,
5676                                    LDB_SCOPE_BASE,
5677                                    "(objectClass=*)",
5678                                    attrs,
5679                                    NULL,
5680                                    ar,
5681                                    replmd_replicated_uptodate_search_callback,
5682                                    ar->req);
5683         LDB_REQ_SET_LOCATION(search_req);
5684         if (ret != LDB_SUCCESS) return replmd_replicated_request_error(ar, ret);
5685
5686         return ldb_next_request(ar->module, search_req);
5687 }
5688
5689
5690
5691 static int replmd_extended_replicated_objects(struct ldb_module *module, struct ldb_request *req)
5692 {
5693         struct ldb_context *ldb;
5694         struct dsdb_extended_replicated_objects *objs;
5695         struct replmd_replicated_request *ar;
5696         struct ldb_control **ctrls;
5697         int ret;
5698         uint32_t i;
5699         struct replmd_private *replmd_private =
5700                 talloc_get_type(ldb_module_get_private(module), struct replmd_private);
5701         struct dsdb_control_replicated_update *rep_update;
5702
5703         ldb = ldb_module_get_ctx(module);
5704
5705         ldb_debug(ldb, LDB_DEBUG_TRACE, "replmd_extended_replicated_objects\n");
5706
5707         objs = talloc_get_type(req->op.extended.data, struct dsdb_extended_replicated_objects);
5708         if (!objs) {
5709                 ldb_debug(ldb, LDB_DEBUG_FATAL, "replmd_extended_replicated_objects: invalid extended data\n");
5710                 return LDB_ERR_PROTOCOL_ERROR;
5711         }
5712
5713         if (objs->version != DSDB_EXTENDED_REPLICATED_OBJECTS_VERSION) {
5714                 ldb_debug(ldb, LDB_DEBUG_FATAL, "replmd_extended_replicated_objects: extended data invalid version [%u != %u]\n",
5715                           objs->version, DSDB_EXTENDED_REPLICATED_OBJECTS_VERSION);
5716                 return LDB_ERR_PROTOCOL_ERROR;
5717         }
5718
5719         ar = replmd_ctx_init(module, req);
5720         if (!ar)
5721                 return LDB_ERR_OPERATIONS_ERROR;
5722
5723         /* Set the flags to have the replmd_op_callback run over the full set of objects */
5724         ar->apply_mode = true;
5725         ar->objs = objs;
5726         ar->schema = dsdb_get_schema(ldb, ar);
5727         if (!ar->schema) {
5728                 ldb_debug_set(ldb, LDB_DEBUG_FATAL, "replmd_ctx_init: no loaded schema found\n");
5729                 talloc_free(ar);
5730                 DEBUG(0,(__location__ ": %s\n", ldb_errstring(ldb)));
5731                 return LDB_ERR_CONSTRAINT_VIOLATION;
5732         }
5733
5734         ctrls = req->controls;
5735
5736         if (req->controls) {
5737                 req->controls = talloc_memdup(ar, req->controls,
5738                                               talloc_get_size(req->controls));
5739                 if (!req->controls) return replmd_replicated_request_werror(ar, WERR_NOMEM);
5740         }
5741
5742         /* This allows layers further down to know if a change came in
5743            over replication and what the replication flags were */
5744         rep_update = talloc_zero(ar, struct dsdb_control_replicated_update);
5745         if (rep_update == NULL) {
5746                 return ldb_module_oom(module);
5747         }
5748         rep_update->dsdb_repl_flags = objs->dsdb_repl_flags;
5749
5750         ret = ldb_request_add_control(req, DSDB_CONTROL_REPLICATED_UPDATE_OID, false, rep_update);
5751         if (ret != LDB_SUCCESS) {
5752                 return ret;
5753         }
5754
5755         /* If this change contained linked attributes in the body
5756          * (rather than in the links section) we need to update
5757          * backlinks in linked_attributes */
5758         ret = ldb_request_add_control(req, DSDB_CONTROL_APPLY_LINKS, false, NULL);
5759         if (ret != LDB_SUCCESS) {
5760                 return ret;
5761         }
5762
5763         ar->controls = req->controls;
5764         req->controls = ctrls;
5765
5766         DEBUG(4,("linked_attributes_count=%u\n", objs->linked_attributes_count));
5767
5768         /* save away the linked attributes for the end of the
5769            transaction */
5770         for (i=0; i<ar->objs->linked_attributes_count; i++) {
5771                 struct la_entry *la_entry;
5772
5773                 if (replmd_private->la_ctx == NULL) {
5774                         replmd_private->la_ctx = talloc_new(replmd_private);
5775                 }
5776                 la_entry = talloc(replmd_private->la_ctx, struct la_entry);
5777                 if (la_entry == NULL) {
5778                         ldb_oom(ldb);
5779                         return LDB_ERR_OPERATIONS_ERROR;
5780                 }
5781                 la_entry->la = talloc(la_entry, struct drsuapi_DsReplicaLinkedAttribute);
5782                 if (la_entry->la == NULL) {
5783                         talloc_free(la_entry);
5784                         ldb_oom(ldb);
5785                         return LDB_ERR_OPERATIONS_ERROR;
5786                 }
5787                 *la_entry->la = ar->objs->linked_attributes[i];
5788
5789                 /* we need to steal the non-scalars so they stay
5790                    around until the end of the transaction */
5791                 talloc_steal(la_entry->la, la_entry->la->identifier);
5792                 talloc_steal(la_entry->la, la_entry->la->value.blob);
5793
5794                 DLIST_ADD(replmd_private->la_list, la_entry);
5795         }
5796
5797         return replmd_replicated_apply_next(ar);
5798 }
5799
5800 /*
5801   process one linked attribute structure
5802  */
5803 static int replmd_process_linked_attribute(struct ldb_module *module,
5804                                            struct la_entry *la_entry,
5805                                            struct ldb_request *parent)
5806 {
5807         struct drsuapi_DsReplicaLinkedAttribute *la = la_entry->la;
5808         struct ldb_context *ldb = ldb_module_get_ctx(module);
5809         struct ldb_message *msg;
5810         struct ldb_message *target_msg = NULL;
5811         TALLOC_CTX *tmp_ctx = talloc_new(la_entry);
5812         const struct dsdb_schema *schema = dsdb_get_schema(ldb, tmp_ctx);
5813         int ret;
5814         const struct dsdb_attribute *attr;
5815         struct dsdb_dn *dsdb_dn;
5816         uint64_t seq_num = 0;
5817         struct ldb_message_element *old_el;
5818         WERROR status;
5819         time_t t = time(NULL);
5820         struct ldb_result *res;
5821         struct ldb_result *target_res;
5822         const char *attrs[4];
5823         const char *attrs2[] = { "isDeleted", "isRecycled", NULL };
5824         struct parsed_dn *pdn_list, *pdn;
5825         struct GUID guid = GUID_zero();
5826         NTSTATUS ntstatus;
5827         bool active = (la->flags & DRSUAPI_DS_LINKED_ATTRIBUTE_FLAG_ACTIVE)?true:false;
5828         const struct GUID *our_invocation_id;
5829
5830         enum deletion_state deletion_state = OBJECT_NOT_DELETED;
5831         enum deletion_state target_deletion_state = OBJECT_NOT_DELETED;
5832
5833 /*
5834 linked_attributes[0]:
5835      &objs->linked_attributes[i]: struct drsuapi_DsReplicaLinkedAttribute
5836         identifier               : *
5837             identifier: struct drsuapi_DsReplicaObjectIdentifier
5838                 __ndr_size               : 0x0000003a (58)
5839                 __ndr_size_sid           : 0x00000000 (0)
5840                 guid                     : 8e95b6a9-13dd-4158-89db-3220a5be5cc7
5841                 sid                      : S-0-0
5842                 __ndr_size_dn            : 0x00000000 (0)
5843                 dn                       : ''
5844         attid                    : DRSUAPI_ATTID_member (0x1F)
5845         value: struct drsuapi_DsAttributeValue
5846             __ndr_size               : 0x0000007e (126)
5847             blob                     : *
5848                 blob                     : DATA_BLOB length=126
5849         flags                    : 0x00000001 (1)
5850                1: DRSUAPI_DS_LINKED_ATTRIBUTE_FLAG_ACTIVE
5851         originating_add_time     : Wed Sep  2 22:20:01 2009 EST
5852         meta_data: struct drsuapi_DsReplicaMetaData
5853             version                  : 0x00000015 (21)
5854             originating_change_time  : Wed Sep  2 23:39:07 2009 EST
5855             originating_invocation_id: 794640f3-18cf-40ee-a211-a93992b67a64
5856             originating_usn          : 0x000000000001e19c (123292)
5857
5858 (for cases where the link is to a normal DN)
5859      &target: struct drsuapi_DsReplicaObjectIdentifier3
5860         __ndr_size               : 0x0000007e (126)
5861         __ndr_size_sid           : 0x0000001c (28)
5862         guid                     : 7639e594-db75-4086-b0d4-67890ae46031
5863         sid                      : S-1-5-21-2848215498-2472035911-1947525656-19924
5864         __ndr_size_dn            : 0x00000022 (34)
5865         dn                       : 'CN=UOne,OU=TestOU,DC=vsofs8,DC=com'
5866  */
5867
5868         /* find the attribute being modified */
5869         attr = dsdb_attribute_by_attributeID_id(schema, la->attid);
5870         if (attr == NULL) {
5871                 DEBUG(0, (__location__ ": Unable to find attributeID 0x%x\n", la->attid));
5872                 talloc_free(tmp_ctx);
5873                 return LDB_ERR_OPERATIONS_ERROR;
5874         }
5875
5876         attrs[0] = attr->lDAPDisplayName;
5877         attrs[1] = "isDeleted";
5878         attrs[2] = "isRecycled";
5879         attrs[3] = NULL;
5880
5881         /* get the existing message from the db for the object with
5882            this GUID, returning attribute being modified. We will then
5883            use this msg as the basis for a modify call */
5884         ret = dsdb_module_search(module, tmp_ctx, &res, NULL, LDB_SCOPE_SUBTREE, attrs,
5885                                  DSDB_FLAG_NEXT_MODULE |
5886                                  DSDB_SEARCH_SEARCH_ALL_PARTITIONS |
5887                                  DSDB_SEARCH_SHOW_RECYCLED |
5888                                  DSDB_SEARCH_SHOW_DN_IN_STORAGE_FORMAT |
5889                                  DSDB_SEARCH_REVEAL_INTERNALS,
5890                                  parent,
5891                                  "objectGUID=%s", GUID_string(tmp_ctx, &la->identifier->guid));
5892         if (ret != LDB_SUCCESS) {
5893                 talloc_free(tmp_ctx);
5894                 return ret;
5895         }
5896         if (res->count != 1) {
5897                 ldb_asprintf_errstring(ldb, "DRS linked attribute for GUID %s - DN not found",
5898                                        GUID_string(tmp_ctx, &la->identifier->guid));
5899                 talloc_free(tmp_ctx);
5900                 return LDB_ERR_NO_SUCH_OBJECT;
5901         }
5902         msg = res->msgs[0];
5903
5904         /*
5905          * Check for deleted objects per MS-DRSR 4.1.10.6.13
5906          * ProcessLinkValue, because link updates are not applied to
5907          * recycled and tombstone objects.  We don't have to delete
5908          * any existing link, that should have happened when the
5909          * object deletion was replicated or initiated.
5910          */
5911
5912         replmd_deletion_state(module, msg, &deletion_state, NULL);
5913
5914         if (deletion_state >= OBJECT_RECYCLED) {
5915                 talloc_free(tmp_ctx);
5916                 return LDB_SUCCESS;
5917         }
5918
5919         old_el = ldb_msg_find_element(msg, attr->lDAPDisplayName);
5920         if (old_el == NULL) {
5921                 ret = ldb_msg_add_empty(msg, attr->lDAPDisplayName, LDB_FLAG_MOD_REPLACE, &old_el);
5922                 if (ret != LDB_SUCCESS) {
5923                         ldb_module_oom(module);
5924                         talloc_free(tmp_ctx);
5925                         return LDB_ERR_OPERATIONS_ERROR;
5926                 }
5927         } else {
5928                 old_el->flags = LDB_FLAG_MOD_REPLACE;
5929         }
5930
5931         /* parse the existing links */
5932         ret = get_parsed_dns(module, tmp_ctx, old_el, &pdn_list, attr->syntax->ldap_oid, parent);
5933         if (ret != LDB_SUCCESS) {
5934                 talloc_free(tmp_ctx);
5935                 return ret;
5936         }
5937
5938         /* get our invocationId */
5939         our_invocation_id = samdb_ntds_invocation_id(ldb);
5940         if (!our_invocation_id) {
5941                 ldb_debug_set(ldb, LDB_DEBUG_ERROR, __location__ ": unable to find invocationId\n");
5942                 talloc_free(tmp_ctx);
5943                 return LDB_ERR_OPERATIONS_ERROR;
5944         }
5945
5946         ret = replmd_check_upgrade_links(pdn_list, old_el->num_values, old_el, our_invocation_id);
5947         if (ret != LDB_SUCCESS) {
5948                 talloc_free(tmp_ctx);
5949                 return ret;
5950         }
5951
5952         status = dsdb_dn_la_from_blob(ldb, attr, schema, tmp_ctx, la->value.blob, &dsdb_dn);
5953         if (!W_ERROR_IS_OK(status)) {
5954                 ldb_asprintf_errstring(ldb, "Failed to parsed linked attribute blob for %s on %s - %s\n",
5955                                        old_el->name, ldb_dn_get_linearized(msg->dn), win_errstr(status));
5956                 talloc_free(tmp_ctx);
5957                 return LDB_ERR_OPERATIONS_ERROR;
5958         }
5959
5960         ntstatus = dsdb_get_extended_dn_guid(dsdb_dn->dn, &guid, "GUID");
5961         if (!NT_STATUS_IS_OK(ntstatus) && !active) {
5962                 /*
5963                  * This strange behaviour (allowing a NULL/missing
5964                  * GUID) originally comes from:
5965                  *
5966                  * commit e3054ce0fe0f8f62d2f5b2a77893e7a1479128bd
5967                  * Author: Andrew Tridgell <tridge@samba.org>
5968                  * Date:   Mon Dec 21 21:21:55 2009 +1100
5969                  *
5970                  *  s4-drs: cope better with NULL GUIDS from DRS
5971                  *
5972                  *  It is valid to get a NULL GUID over DRS for a deleted forward link. We
5973                  *  need to match by DN if possible when seeing if we should update an
5974                  *  existing link.
5975                  *
5976                  *  Pair-Programmed-With: Andrew Bartlett <abartlet@samba.org>
5977                  */
5978
5979                 ret = dsdb_module_search_dn(module, tmp_ctx, &target_res,
5980                                             dsdb_dn->dn, attrs2,
5981                                             DSDB_FLAG_NEXT_MODULE |
5982                                             DSDB_SEARCH_SHOW_RECYCLED |
5983                                             DSDB_SEARCH_SEARCH_ALL_PARTITIONS |
5984                                             DSDB_SEARCH_SHOW_DN_IN_STORAGE_FORMAT,
5985                                             parent);
5986         } else if (!NT_STATUS_IS_OK(ntstatus)) {
5987                 ldb_asprintf_errstring(ldb, "Failed to find GUID in linked attribute blob for %s on %s from %s",
5988                                        old_el->name,
5989                                        ldb_dn_get_linearized(dsdb_dn->dn),
5990                                        ldb_dn_get_linearized(msg->dn));
5991                 talloc_free(tmp_ctx);
5992                 return LDB_ERR_OPERATIONS_ERROR;
5993         } else {
5994                 ret = dsdb_module_search(module, tmp_ctx, &target_res,
5995                                          NULL, LDB_SCOPE_SUBTREE,
5996                                          attrs2,
5997                                          DSDB_FLAG_NEXT_MODULE |
5998                                          DSDB_SEARCH_SHOW_RECYCLED |
5999                                          DSDB_SEARCH_SEARCH_ALL_PARTITIONS |
6000                                          DSDB_SEARCH_SHOW_DN_IN_STORAGE_FORMAT,
6001                                          parent,
6002                                          "objectGUID=%s",
6003                                          GUID_string(tmp_ctx, &guid));
6004         }
6005
6006         if (ret != LDB_SUCCESS) {
6007                 ldb_asprintf_errstring(ldb_module_get_ctx(module), "Failed to re-resolve GUID %s: %s\n",
6008                                        GUID_string(tmp_ctx, &guid),
6009                                        ldb_errstring(ldb_module_get_ctx(module)));
6010                 talloc_free(tmp_ctx);
6011                 return ret;
6012         }
6013
6014         if (target_res->count == 0) {
6015                 DEBUG(2,(__location__ ": WARNING: Failed to re-resolve GUID %s - using %s\n",
6016                          GUID_string(tmp_ctx, &guid),
6017                          ldb_dn_get_linearized(dsdb_dn->dn)));
6018         } else if (target_res->count != 1) {
6019                 ldb_asprintf_errstring(ldb_module_get_ctx(module), "More than one object found matching objectGUID %s\n",
6020                                        GUID_string(tmp_ctx, &guid));
6021                 talloc_free(tmp_ctx);
6022                 return LDB_ERR_OPERATIONS_ERROR;
6023         } else {
6024                 target_msg = target_res->msgs[0];
6025                 dsdb_dn->dn = talloc_steal(dsdb_dn, target_msg->dn);
6026         }
6027
6028         /*
6029          * Check for deleted objects per MS-DRSR 4.1.10.6.13
6030          * ProcessLinkValue, because link updates are not applied to
6031          * recycled and tombstone objects.  We don't have to delete
6032          * any existing link, that should have happened when the
6033          * object deletion was replicated or initiated.
6034          */
6035         replmd_deletion_state(module, target_msg,
6036                               &target_deletion_state, NULL);
6037
6038         if (target_deletion_state >= OBJECT_RECYCLED) {
6039                 talloc_free(tmp_ctx);
6040                 return LDB_SUCCESS;
6041         }
6042
6043         /* see if this link already exists */
6044         pdn = parsed_dn_find(pdn_list, old_el->num_values, &guid, dsdb_dn->dn);
6045         if (pdn != NULL) {
6046                 /* see if this update is newer than what we have already */
6047                 struct GUID invocation_id = GUID_zero();
6048                 uint32_t version = 0;
6049                 uint32_t originating_usn = 0;
6050                 NTTIME change_time = 0;
6051                 uint32_t rmd_flags = dsdb_dn_rmd_flags(pdn->dsdb_dn->dn);
6052
6053                 dsdb_get_extended_dn_guid(pdn->dsdb_dn->dn, &invocation_id, "RMD_INVOCID");
6054                 dsdb_get_extended_dn_uint32(pdn->dsdb_dn->dn, &version, "RMD_VERSION");
6055                 dsdb_get_extended_dn_uint32(pdn->dsdb_dn->dn, &originating_usn, "RMD_ORIGINATING_USN");
6056                 dsdb_get_extended_dn_nttime(pdn->dsdb_dn->dn, &change_time, "RMD_CHANGETIME");
6057
6058                 if (!replmd_update_is_newer(&invocation_id,
6059                                             &la->meta_data.originating_invocation_id,
6060                                             version,
6061                                             la->meta_data.version,
6062                                             change_time,
6063                                             la->meta_data.originating_change_time)) {
6064                         DEBUG(3,("Discarding older DRS linked attribute update to %s on %s from %s\n",
6065                                  old_el->name, ldb_dn_get_linearized(msg->dn),
6066                                  GUID_string(tmp_ctx, &la->meta_data.originating_invocation_id)));
6067                         talloc_free(tmp_ctx);
6068                         return LDB_SUCCESS;
6069                 }
6070
6071                 /* get a seq_num for this change */
6072                 ret = ldb_sequence_number(ldb, LDB_SEQ_NEXT, &seq_num);
6073                 if (ret != LDB_SUCCESS) {
6074                         talloc_free(tmp_ctx);
6075                         return ret;
6076                 }
6077
6078                 if (!(rmd_flags & DSDB_RMD_FLAG_DELETED)) {
6079                         /* remove the existing backlink */
6080                         ret = replmd_add_backlink(module, schema, &la->identifier->guid, &guid, false, attr, true);
6081                         if (ret != LDB_SUCCESS) {
6082                                 talloc_free(tmp_ctx);
6083                                 return ret;
6084                         }
6085                 }
6086
6087                 ret = replmd_update_la_val(tmp_ctx, pdn->v, dsdb_dn, pdn->dsdb_dn,
6088                                            &la->meta_data.originating_invocation_id,
6089                                            la->meta_data.originating_usn, seq_num,
6090                                            la->meta_data.originating_change_time,
6091                                            la->meta_data.version,
6092                                            !active);
6093                 if (ret != LDB_SUCCESS) {
6094                         talloc_free(tmp_ctx);
6095                         return ret;
6096                 }
6097
6098                 if (active) {
6099                         /* add the new backlink */
6100                         ret = replmd_add_backlink(module, schema, &la->identifier->guid, &guid, true, attr, true);
6101                         if (ret != LDB_SUCCESS) {
6102                                 talloc_free(tmp_ctx);
6103                                 return ret;
6104                         }
6105                 }
6106         } else {
6107                 /* get a seq_num for this change */
6108                 ret = ldb_sequence_number(ldb, LDB_SEQ_NEXT, &seq_num);
6109                 if (ret != LDB_SUCCESS) {
6110                         talloc_free(tmp_ctx);
6111                         return ret;
6112                 }
6113
6114                 old_el->values = talloc_realloc(msg->elements, old_el->values,
6115                                                 struct ldb_val, old_el->num_values+1);
6116                 if (!old_el->values) {
6117                         ldb_module_oom(module);
6118                         return LDB_ERR_OPERATIONS_ERROR;
6119                 }
6120                 old_el->num_values++;
6121
6122                 ret = replmd_build_la_val(tmp_ctx, &old_el->values[old_el->num_values-1], dsdb_dn,
6123                                           &la->meta_data.originating_invocation_id,
6124                                           la->meta_data.originating_usn, seq_num,
6125                                           la->meta_data.originating_change_time,
6126                                           la->meta_data.version,
6127                                           (la->flags & DRSUAPI_DS_LINKED_ATTRIBUTE_FLAG_ACTIVE)?false:true);
6128                 if (ret != LDB_SUCCESS) {
6129                         talloc_free(tmp_ctx);
6130                         return ret;
6131                 }
6132
6133                 if (active) {
6134                         ret = replmd_add_backlink(module, schema, &la->identifier->guid, &guid,
6135                                                   true, attr, true);
6136                         if (ret != LDB_SUCCESS) {
6137                                 talloc_free(tmp_ctx);
6138                                 return ret;
6139                         }
6140                 }
6141         }
6142
6143         /* we only change whenChanged and uSNChanged if the seq_num
6144            has changed */
6145         ret = add_time_element(msg, "whenChanged", t);
6146         if (ret != LDB_SUCCESS) {
6147                 talloc_free(tmp_ctx);
6148                 ldb_operr(ldb);
6149                 return ret;
6150         }
6151
6152         ret = add_uint64_element(ldb, msg, "uSNChanged", seq_num);
6153         if (ret != LDB_SUCCESS) {
6154                 talloc_free(tmp_ctx);
6155                 ldb_operr(ldb);
6156                 return ret;
6157         }
6158
6159         old_el = ldb_msg_find_element(msg, attr->lDAPDisplayName);
6160         if (old_el == NULL) {
6161                 talloc_free(tmp_ctx);
6162                 return ldb_operr(ldb);
6163         }
6164
6165         ret = dsdb_check_single_valued_link(attr, old_el);
6166         if (ret != LDB_SUCCESS) {
6167                 talloc_free(tmp_ctx);
6168                 return ret;
6169         }
6170
6171         old_el->flags |= LDB_FLAG_INTERNAL_DISABLE_SINGLE_VALUE_CHECK;
6172
6173         ret = dsdb_module_modify(module, msg, DSDB_FLAG_NEXT_MODULE, parent);
6174         if (ret != LDB_SUCCESS) {
6175                 ldb_debug(ldb, LDB_DEBUG_WARNING, "Failed to apply linked attribute change '%s'\n%s\n",
6176                           ldb_errstring(ldb),
6177                           ldb_ldif_message_string(ldb, tmp_ctx, LDB_CHANGETYPE_MODIFY, msg));
6178                 talloc_free(tmp_ctx);
6179                 return ret;
6180         }
6181
6182         talloc_free(tmp_ctx);
6183
6184         return ret;
6185 }
6186
6187 static int replmd_extended(struct ldb_module *module, struct ldb_request *req)
6188 {
6189         if (strcmp(req->op.extended.oid, DSDB_EXTENDED_REPLICATED_OBJECTS_OID) == 0) {
6190                 return replmd_extended_replicated_objects(module, req);
6191         }
6192
6193         return ldb_next_request(module, req);
6194 }
6195
6196
6197 /*
6198   we hook into the transaction operations to allow us to
6199   perform the linked attribute updates at the end of the whole
6200   transaction. This allows a forward linked attribute to be created
6201   before the object is created. During a vampire, w2k8 sends us linked
6202   attributes before the objects they are part of.
6203  */
6204 static int replmd_start_transaction(struct ldb_module *module)
6205 {
6206         /* create our private structure for this transaction */
6207         struct replmd_private *replmd_private = talloc_get_type(ldb_module_get_private(module),
6208                                                                 struct replmd_private);
6209         replmd_txn_cleanup(replmd_private);
6210
6211         /* free any leftover mod_usn records from cancelled
6212            transactions */
6213         while (replmd_private->ncs) {
6214                 struct nc_entry *e = replmd_private->ncs;
6215                 DLIST_REMOVE(replmd_private->ncs, e);
6216                 talloc_free(e);
6217         }
6218
6219         return ldb_next_start_trans(module);
6220 }
6221
6222 /*
6223   on prepare commit we loop over our queued la_context structures and
6224   apply each of them
6225  */
6226 static int replmd_prepare_commit(struct ldb_module *module)
6227 {
6228         struct replmd_private *replmd_private =
6229                 talloc_get_type(ldb_module_get_private(module), struct replmd_private);
6230         struct la_entry *la, *prev;
6231         struct la_backlink *bl;
6232         int ret;
6233
6234         /* walk the list backwards, to do the first entry first, as we
6235          * added the entries with DLIST_ADD() which puts them at the
6236          * start of the list */
6237         for (la = DLIST_TAIL(replmd_private->la_list); la; la=prev) {
6238                 prev = DLIST_PREV(la);
6239                 DLIST_REMOVE(replmd_private->la_list, la);
6240                 ret = replmd_process_linked_attribute(module, la, NULL);
6241                 if (ret != LDB_SUCCESS) {
6242                         replmd_txn_cleanup(replmd_private);
6243                         return ret;
6244                 }
6245         }
6246
6247         /* process our backlink list, creating and deleting backlinks
6248            as necessary */
6249         for (bl=replmd_private->la_backlinks; bl; bl=bl->next) {
6250                 ret = replmd_process_backlink(module, bl, NULL);
6251                 if (ret != LDB_SUCCESS) {
6252                         replmd_txn_cleanup(replmd_private);
6253                         return ret;
6254                 }
6255         }
6256
6257         replmd_txn_cleanup(replmd_private);
6258
6259         /* possibly change @REPLCHANGED */
6260         ret = replmd_notify_store(module, NULL);
6261         if (ret != LDB_SUCCESS) {
6262                 return ret;
6263         }
6264
6265         return ldb_next_prepare_commit(module);
6266 }
6267
6268 static int replmd_del_transaction(struct ldb_module *module)
6269 {
6270         struct replmd_private *replmd_private =
6271                 talloc_get_type(ldb_module_get_private(module), struct replmd_private);
6272         replmd_txn_cleanup(replmd_private);
6273
6274         return ldb_next_del_trans(module);
6275 }
6276
6277
6278 static const struct ldb_module_ops ldb_repl_meta_data_module_ops = {
6279         .name          = "repl_meta_data",
6280         .init_context      = replmd_init,
6281         .add               = replmd_add,
6282         .modify            = replmd_modify,
6283         .rename            = replmd_rename,
6284         .del               = replmd_delete,
6285         .extended          = replmd_extended,
6286         .start_transaction = replmd_start_transaction,
6287         .prepare_commit    = replmd_prepare_commit,
6288         .del_transaction   = replmd_del_transaction,
6289 };
6290
6291 int ldb_repl_meta_data_module_init(const char *version)
6292 {
6293         LDB_MODULE_CHECK_VERSION(version);
6294         return ldb_register_module(&ldb_repl_meta_data_module_ops);
6295 }