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