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