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