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