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