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