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