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