s4-dsdb: Do not assume that all deleted objects have an objectCategory and sAMAccountType
[amitay/samba.git] / source4 / dsdb / samdb / ldb_modules / repl_meta_data.c
1 /*
2    ldb database library
3
4    Copyright (C) Simo Sorce  2004-2008
5    Copyright (C) Andrew Bartlett <abartlet@samba.org> 2005
6    Copyright (C) Andrew Tridgell 2005
7    Copyright (C) Stefan Metzmacher <metze@samba.org> 2007
8    Copyright (C) Matthieu Patou <mat@samba.org> 2010
9
10    This program is free software; you can redistribute it and/or modify
11    it under the terms of the GNU General Public License as published by
12    the Free Software Foundation; either version 3 of the License, or
13    (at your option) any later version.
14
15    This program is distributed in the hope that it will be useful,
16    but WITHOUT ANY WARRANTY; without even the implied warranty of
17    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
18    GNU General Public License for more details.
19
20    You should have received a copy of the GNU General Public License
21    along with this program.  If not, see <http://www.gnu.org/licenses/>.
22 */
23
24 /*
25  *  Name: ldb
26  *
27  *  Component: ldb repl_meta_data module
28  *
29  *  Description: - add a unique objectGUID onto every new record,
30  *               - handle whenCreated, whenChanged timestamps
31  *               - handle uSNCreated, uSNChanged numbers
32  *               - handle replPropertyMetaData attribute
33  *
34  *  Author: Simo Sorce
35  *  Author: Stefan Metzmacher
36  */
37
38 #include "includes.h"
39 #include "ldb_module.h"
40 #include "dsdb/samdb/samdb.h"
41 #include "dsdb/common/proto.h"
42 #include "../libds/common/flags.h"
43 #include "librpc/gen_ndr/ndr_misc.h"
44 #include "librpc/gen_ndr/ndr_drsuapi.h"
45 #include "librpc/gen_ndr/ndr_drsblobs.h"
46 #include "param/param.h"
47 #include "libcli/security/security.h"
48 #include "lib/util/dlinklist.h"
49 #include "dsdb/samdb/ldb_modules/util.h"
50 #include "lib/util/binsearch.h"
51 #include "lib/util/tsort.h"
52
53 struct replmd_private {
54         TALLOC_CTX *la_ctx;
55         struct la_entry *la_list;
56         TALLOC_CTX *bl_ctx;
57         struct la_backlink *la_backlinks;
58         struct nc_entry {
59                 struct nc_entry *prev, *next;
60                 struct ldb_dn *dn;
61                 uint64_t mod_usn;
62                 uint64_t mod_usn_urgent;
63         } *ncs;
64 };
65
66 struct la_entry {
67         struct la_entry *next, *prev;
68         struct drsuapi_DsReplicaLinkedAttribute *la;
69 };
70
71 struct replmd_replicated_request {
72         struct ldb_module *module;
73         struct ldb_request *req;
74
75         const struct dsdb_schema *schema;
76
77         /* the controls we pass down */
78         struct ldb_control **controls;
79
80         /* details for the mode where we apply a bunch of inbound replication meessages */
81         bool apply_mode;
82         uint32_t index_current;
83         struct dsdb_extended_replicated_objects *objs;
84
85         struct ldb_message *search_msg;
86
87         uint64_t seq_num;
88         bool is_urgent;
89 };
90
91 enum urgent_situation {
92         REPL_URGENT_ON_CREATE = 1,
93         REPL_URGENT_ON_UPDATE = 2,
94         REPL_URGENT_ON_DELETE = 4
95 };
96
97
98 static const struct {
99         const char *update_name;
100         enum urgent_situation repl_situation;
101 } urgent_objects[] = {
102                 {"nTDSDSA", (REPL_URGENT_ON_CREATE | REPL_URGENT_ON_DELETE)},
103                 {"crossRef", (REPL_URGENT_ON_CREATE | REPL_URGENT_ON_DELETE)},
104                 {"attributeSchema", (REPL_URGENT_ON_CREATE | REPL_URGENT_ON_UPDATE)},
105                 {"classSchema", (REPL_URGENT_ON_CREATE | REPL_URGENT_ON_UPDATE)},
106                 {"secret", (REPL_URGENT_ON_CREATE | REPL_URGENT_ON_UPDATE)},
107                 {"rIDManager", (REPL_URGENT_ON_CREATE | REPL_URGENT_ON_UPDATE)},
108                 {NULL, 0}
109 };
110
111 /* Attributes looked for when updating or deleting, to check for a urgent replication needed */
112 static const char *urgent_attrs[] = {
113                 "lockoutTime",
114                 "pwdLastSet",
115                 "userAccountControl",
116                 NULL
117 };
118
119
120 static bool replmd_check_urgent_objectclass(const struct ldb_message_element *objectclass_el,
121                                         enum urgent_situation situation)
122 {
123         unsigned int i, j;
124         for (i=0; urgent_objects[i].update_name; i++) {
125
126                 if ((situation & urgent_objects[i].repl_situation) == 0) {
127                         continue;
128                 }
129
130                 for (j=0; j<objectclass_el->num_values; j++) {
131                         const struct ldb_val *v = &objectclass_el->values[j];
132                         if (ldb_attr_cmp((const char *)v->data, urgent_objects[i].update_name) == 0) {
133                                 return true;
134                         }
135                 }
136         }
137         return false;
138 }
139
140 static bool replmd_check_urgent_attribute(const struct ldb_message_element *el)
141 {
142         if (ldb_attr_in_list(urgent_attrs, el->name)) {
143                 return true;
144         }
145         return false;
146 }
147
148
149 static int replmd_replicated_apply_next(struct replmd_replicated_request *ar);
150
151 /*
152   initialise the module
153   allocate the private structure and build the list
154   of partition DNs for use by replmd_notify()
155  */
156 static int replmd_init(struct ldb_module *module)
157 {
158         struct replmd_private *replmd_private;
159         struct ldb_context *ldb = ldb_module_get_ctx(module);
160
161         replmd_private = talloc_zero(module, struct replmd_private);
162         if (replmd_private == NULL) {
163                 ldb_oom(ldb);
164                 return LDB_ERR_OPERATIONS_ERROR;
165         }
166         ldb_module_set_private(module, replmd_private);
167
168         return ldb_next_init(module);
169 }
170
171 /*
172   cleanup our per-transaction contexts
173  */
174 static void replmd_txn_cleanup(struct replmd_private *replmd_private)
175 {
176         talloc_free(replmd_private->la_ctx);
177         replmd_private->la_list = NULL;
178         replmd_private->la_ctx = NULL;
179
180         talloc_free(replmd_private->bl_ctx);
181         replmd_private->la_backlinks = NULL;
182         replmd_private->bl_ctx = NULL;
183 }
184
185
186 struct la_backlink {
187         struct la_backlink *next, *prev;
188         const char *attr_name;
189         struct GUID forward_guid, target_guid;
190         bool active;
191 };
192
193 /*
194   process a backlinks we accumulated during a transaction, adding and
195   deleting the backlinks from the target objects
196  */
197 static int replmd_process_backlink(struct ldb_module *module, struct la_backlink *bl, struct ldb_request *parent)
198 {
199         struct ldb_dn *target_dn, *source_dn;
200         int ret;
201         struct ldb_context *ldb = ldb_module_get_ctx(module);
202         struct ldb_message *msg;
203         TALLOC_CTX *tmp_ctx = talloc_new(bl);
204         char *dn_string;
205
206         /*
207           - find DN of target
208           - find DN of source
209           - construct ldb_message
210               - either an add or a delete
211          */
212         ret = dsdb_module_dn_by_guid(module, tmp_ctx, &bl->target_guid, &target_dn, parent);
213         if (ret != LDB_SUCCESS) {
214                 DEBUG(2,(__location__ ": WARNING: Failed to find target DN for linked attribute with GUID %s\n",
215                          GUID_string(bl, &bl->target_guid)));
216                 return LDB_SUCCESS;
217         }
218
219         ret = dsdb_module_dn_by_guid(module, tmp_ctx, &bl->forward_guid, &source_dn, parent);
220         if (ret != LDB_SUCCESS) {
221                 ldb_asprintf_errstring(ldb, "Failed to find source DN for linked attribute with GUID %s\n",
222                                        GUID_string(bl, &bl->forward_guid));
223                 talloc_free(tmp_ctx);
224                 return ret;
225         }
226
227         msg = ldb_msg_new(tmp_ctx);
228         if (msg == NULL) {
229                 ldb_module_oom(module);
230                 talloc_free(tmp_ctx);
231                 return LDB_ERR_OPERATIONS_ERROR;
232         }
233
234         /* construct a ldb_message for adding/deleting the backlink */
235         msg->dn = target_dn;
236         dn_string = ldb_dn_get_extended_linearized(tmp_ctx, source_dn, 1);
237         if (!dn_string) {
238                 ldb_module_oom(module);
239                 talloc_free(tmp_ctx);
240                 return LDB_ERR_OPERATIONS_ERROR;
241         }
242         ret = ldb_msg_add_steal_string(msg, bl->attr_name, dn_string);
243         if (ret != LDB_SUCCESS) {
244                 talloc_free(tmp_ctx);
245                 return ret;
246         }
247         msg->elements[0].flags = bl->active?LDB_FLAG_MOD_ADD:LDB_FLAG_MOD_DELETE;
248
249         /* a backlink should never be single valued. Unfortunately the
250            exchange schema has a attribute
251            msExchBridgeheadedLocalConnectorsDNBL which is single
252            valued and a backlink. We need to cope with that by
253            ignoring the single value flag */
254         msg->elements[0].flags |= LDB_FLAG_INTERNAL_DISABLE_SINGLE_VALUE_CHECK;
255
256         ret = dsdb_module_modify(module, msg, DSDB_FLAG_NEXT_MODULE, parent);
257         if (ret == LDB_ERR_NO_SUCH_ATTRIBUTE && !bl->active) {
258                 /* we allow LDB_ERR_NO_SUCH_ATTRIBUTE as success to
259                    cope with possible corruption where the backlink has
260                    already been removed */
261                 DEBUG(3,("WARNING: backlink from %s already removed from %s - %s\n",
262                          ldb_dn_get_linearized(target_dn),
263                          ldb_dn_get_linearized(source_dn),
264                          ldb_errstring(ldb)));
265                 ret = LDB_SUCCESS;
266         } else if (ret != LDB_SUCCESS) {
267                 ldb_asprintf_errstring(ldb, "Failed to %s backlink from %s to %s - %s",
268                                        bl->active?"add":"remove",
269                                        ldb_dn_get_linearized(source_dn),
270                                        ldb_dn_get_linearized(target_dn),
271                                        ldb_errstring(ldb));
272                 talloc_free(tmp_ctx);
273                 return ret;
274         }
275         talloc_free(tmp_ctx);
276         return ret;
277 }
278
279 /*
280   add a backlink to the list of backlinks to add/delete in the prepare
281   commit
282  */
283 static int replmd_add_backlink(struct ldb_module *module, const struct dsdb_schema *schema,
284                                struct GUID *forward_guid, struct GUID *target_guid,
285                                bool active, const struct dsdb_attribute *schema_attr, bool immediate)
286 {
287         const struct dsdb_attribute *target_attr;
288         struct la_backlink *bl;
289         struct replmd_private *replmd_private =
290                 talloc_get_type_abort(ldb_module_get_private(module), struct replmd_private);
291
292         target_attr = dsdb_attribute_by_linkID(schema, schema_attr->linkID ^ 1);
293         if (!target_attr) {
294                 /*
295                  * windows 2003 has a broken schema where the
296                  * definition of msDS-IsDomainFor is missing (which is
297                  * supposed to be the backlink of the
298                  * msDS-HasDomainNCs attribute
299                  */
300                 return LDB_SUCCESS;
301         }
302
303         /* see if its already in the list */
304         for (bl=replmd_private->la_backlinks; bl; bl=bl->next) {
305                 if (GUID_equal(forward_guid, &bl->forward_guid) &&
306                     GUID_equal(target_guid, &bl->target_guid) &&
307                     (target_attr->lDAPDisplayName == bl->attr_name ||
308                      strcmp(target_attr->lDAPDisplayName, bl->attr_name) == 0)) {
309                         break;
310                 }
311         }
312
313         if (bl) {
314                 /* we found an existing one */
315                 if (bl->active == active) {
316                         return LDB_SUCCESS;
317                 }
318                 DLIST_REMOVE(replmd_private->la_backlinks, bl);
319                 talloc_free(bl);
320                 return LDB_SUCCESS;
321         }
322
323         if (replmd_private->bl_ctx == NULL) {
324                 replmd_private->bl_ctx = talloc_new(replmd_private);
325                 if (replmd_private->bl_ctx == NULL) {
326                         ldb_module_oom(module);
327                         return LDB_ERR_OPERATIONS_ERROR;
328                 }
329         }
330
331         /* its a new one */
332         bl = talloc(replmd_private->bl_ctx, struct la_backlink);
333         if (bl == NULL) {
334                 ldb_module_oom(module);
335                 return LDB_ERR_OPERATIONS_ERROR;
336         }
337
338         /* Ensure the schema does not go away before the bl->attr_name is used */
339         if (!talloc_reference(bl, schema)) {
340                 talloc_free(bl);
341                 ldb_module_oom(module);
342                 return LDB_ERR_OPERATIONS_ERROR;
343         }
344
345         bl->attr_name = target_attr->lDAPDisplayName;
346         bl->forward_guid = *forward_guid;
347         bl->target_guid = *target_guid;
348         bl->active = active;
349
350         /* the caller may ask for this backlink to be processed
351            immediately */
352         if (immediate) {
353                 int ret = replmd_process_backlink(module, bl, NULL);
354                 talloc_free(bl);
355                 return ret;
356         }
357
358         DLIST_ADD(replmd_private->la_backlinks, bl);
359
360         return LDB_SUCCESS;
361 }
362
363
364 /*
365  * Callback for most write operations in this module:
366  *
367  * notify the repl task that a object has changed. The notifies are
368  * gathered up in the replmd_private structure then written to the
369  * @REPLCHANGED object in each partition during the prepare_commit
370  */
371 static int replmd_op_callback(struct ldb_request *req, struct ldb_reply *ares)
372 {
373         int ret;
374         struct replmd_replicated_request *ac =
375                 talloc_get_type_abort(req->context, struct replmd_replicated_request);
376         struct replmd_private *replmd_private =
377                 talloc_get_type_abort(ldb_module_get_private(ac->module), struct replmd_private);
378         struct nc_entry *modified_partition;
379         struct ldb_control *partition_ctrl;
380         const struct dsdb_control_current_partition *partition;
381
382         struct ldb_control **controls;
383
384         partition_ctrl = ldb_reply_get_control(ares, DSDB_CONTROL_CURRENT_PARTITION_OID);
385
386         controls = ares->controls;
387         if (ldb_request_get_control(ac->req,
388                                     DSDB_CONTROL_CURRENT_PARTITION_OID) == NULL) {
389                 /*
390                  * Remove the current partition control from what we pass up
391                  * the chain if it hasn't been requested manually.
392                  */
393                 controls = ldb_controls_except_specified(ares->controls, ares,
394                                                          partition_ctrl);
395         }
396
397         if (ares->error != LDB_SUCCESS) {
398                 DEBUG(5,("%s failure. Error is: %s\n", __FUNCTION__, ldb_strerror(ares->error)));
399                 return ldb_module_done(ac->req, controls,
400                                         ares->response, ares->error);
401         }
402
403         if (ares->type != LDB_REPLY_DONE) {
404                 ldb_set_errstring(ldb_module_get_ctx(ac->module), "Invalid reply type for notify\n!");
405                 return ldb_module_done(ac->req, NULL,
406                                        NULL, LDB_ERR_OPERATIONS_ERROR);
407         }
408
409         if (!partition_ctrl) {
410                 ldb_set_errstring(ldb_module_get_ctx(ac->module),"No partition control on reply");
411                 return ldb_module_done(ac->req, NULL,
412                                        NULL, LDB_ERR_OPERATIONS_ERROR);
413         }
414
415         partition = talloc_get_type_abort(partition_ctrl->data,
416                                     struct dsdb_control_current_partition);
417
418         if (ac->seq_num > 0) {
419                 for (modified_partition = replmd_private->ncs; modified_partition;
420                      modified_partition = modified_partition->next) {
421                         if (ldb_dn_compare(modified_partition->dn, partition->dn) == 0) {
422                                 break;
423                         }
424                 }
425
426                 if (modified_partition == NULL) {
427                         modified_partition = talloc_zero(replmd_private, struct nc_entry);
428                         if (!modified_partition) {
429                                 ldb_oom(ldb_module_get_ctx(ac->module));
430                                 return ldb_module_done(ac->req, NULL,
431                                                        NULL, LDB_ERR_OPERATIONS_ERROR);
432                         }
433                         modified_partition->dn = ldb_dn_copy(modified_partition, partition->dn);
434                         if (!modified_partition->dn) {
435                                 ldb_oom(ldb_module_get_ctx(ac->module));
436                                 return ldb_module_done(ac->req, NULL,
437                                                        NULL, LDB_ERR_OPERATIONS_ERROR);
438                         }
439                         DLIST_ADD(replmd_private->ncs, modified_partition);
440                 }
441
442                 if (ac->seq_num > modified_partition->mod_usn) {
443                         modified_partition->mod_usn = ac->seq_num;
444                         if (ac->is_urgent) {
445                                 modified_partition->mod_usn_urgent = ac->seq_num;
446                         }
447                 }
448         }
449
450         if (ac->apply_mode) {
451                 talloc_free(ares);
452                 ac->index_current++;
453
454                 ret = replmd_replicated_apply_next(ac);
455                 if (ret != LDB_SUCCESS) {
456                         return ldb_module_done(ac->req, NULL, NULL, ret);
457                 }
458                 return ret;
459         } else {
460                 /* free the partition control container here, for the
461                  * common path.  Other cases will have it cleaned up
462                  * eventually with the ares */
463                 talloc_free(partition_ctrl);
464                 return ldb_module_done(ac->req, controls,
465                                        ares->response, LDB_SUCCESS);
466         }
467 }
468
469
470 /*
471  * update a @REPLCHANGED record in each partition if there have been
472  * any writes of replicated data in the partition
473  */
474 static int replmd_notify_store(struct ldb_module *module, struct ldb_request *parent)
475 {
476         struct replmd_private *replmd_private =
477                 talloc_get_type(ldb_module_get_private(module), struct replmd_private);
478
479         while (replmd_private->ncs) {
480                 int ret;
481                 struct nc_entry *modified_partition = replmd_private->ncs;
482
483                 ret = dsdb_module_save_partition_usn(module, modified_partition->dn,
484                                                      modified_partition->mod_usn,
485                                                      modified_partition->mod_usn_urgent, parent);
486                 if (ret != LDB_SUCCESS) {
487                         DEBUG(0,(__location__ ": Failed to save partition uSN for %s\n",
488                                  ldb_dn_get_linearized(modified_partition->dn)));
489                         return ret;
490                 }
491                 DLIST_REMOVE(replmd_private->ncs, modified_partition);
492                 talloc_free(modified_partition);
493         }
494
495         return LDB_SUCCESS;
496 }
497
498
499 /*
500   created a replmd_replicated_request context
501  */
502 static struct replmd_replicated_request *replmd_ctx_init(struct ldb_module *module,
503                                                          struct ldb_request *req)
504 {
505         struct ldb_context *ldb;
506         struct replmd_replicated_request *ac;
507
508         ldb = ldb_module_get_ctx(module);
509
510         ac = talloc_zero(req, struct replmd_replicated_request);
511         if (ac == NULL) {
512                 ldb_oom(ldb);
513                 return NULL;
514         }
515
516         ac->module = module;
517         ac->req = req;
518
519         ac->schema = dsdb_get_schema(ldb, ac);
520         if (!ac->schema) {
521                 ldb_debug_set(ldb, LDB_DEBUG_FATAL,
522                               "replmd_modify: no dsdb_schema loaded");
523                 DEBUG(0,(__location__ ": %s\n", ldb_errstring(ldb)));
524                 return NULL;
525         }
526
527         return ac;
528 }
529
530 /*
531   add a time element to a record
532 */
533 static int add_time_element(struct ldb_message *msg, const char *attr, time_t t)
534 {
535         struct ldb_message_element *el;
536         char *s;
537         int ret;
538
539         if (ldb_msg_find_element(msg, attr) != NULL) {
540                 return LDB_SUCCESS;
541         }
542
543         s = ldb_timestring(msg, t);
544         if (s == NULL) {
545                 return LDB_ERR_OPERATIONS_ERROR;
546         }
547
548         ret = ldb_msg_add_string(msg, attr, s);
549         if (ret != LDB_SUCCESS) {
550                 return ret;
551         }
552
553         el = ldb_msg_find_element(msg, attr);
554         /* always set as replace. This works because on add ops, the flag
555            is ignored */
556         el->flags = LDB_FLAG_MOD_REPLACE;
557
558         return LDB_SUCCESS;
559 }
560
561 /*
562   add a uint64_t element to a record
563 */
564 static int add_uint64_element(struct ldb_context *ldb, struct ldb_message *msg,
565                               const char *attr, uint64_t v)
566 {
567         struct ldb_message_element *el;
568         int ret;
569
570         if (ldb_msg_find_element(msg, attr) != NULL) {
571                 return LDB_SUCCESS;
572         }
573
574         ret = samdb_msg_add_uint64(ldb, msg, msg, attr, v);
575         if (ret != LDB_SUCCESS) {
576                 return ret;
577         }
578
579         el = ldb_msg_find_element(msg, attr);
580         /* always set as replace. This works because on add ops, the flag
581            is ignored */
582         el->flags = LDB_FLAG_MOD_REPLACE;
583
584         return LDB_SUCCESS;
585 }
586
587 static int replmd_replPropertyMetaData1_attid_sort(const struct replPropertyMetaData1 *m1,
588                                                    const struct replPropertyMetaData1 *m2,
589                                                    const uint32_t *rdn_attid)
590 {
591         if (m1->attid == m2->attid) {
592                 return 0;
593         }
594
595         /*
596          * the rdn attribute should be at the end!
597          * so we need to return a value greater than zero
598          * which means m1 is greater than m2
599          */
600         if (m1->attid == *rdn_attid) {
601                 return 1;
602         }
603
604         /*
605          * the rdn attribute should be at the end!
606          * so we need to return a value less than zero
607          * which means m2 is greater than m1
608          */
609         if (m2->attid == *rdn_attid) {
610                 return -1;
611         }
612
613         return m1->attid > m2->attid ? 1 : -1;
614 }
615
616 static int replmd_replPropertyMetaDataCtr1_sort(struct replPropertyMetaDataCtr1 *ctr1,
617                                                 const struct dsdb_schema *schema,
618                                                 struct ldb_dn *dn)
619 {
620         const char *rdn_name;
621         const struct dsdb_attribute *rdn_sa;
622
623         rdn_name = ldb_dn_get_rdn_name(dn);
624         if (!rdn_name) {
625                 DEBUG(0,(__location__ ": No rDN for %s?\n", ldb_dn_get_linearized(dn)));
626                 return LDB_ERR_OPERATIONS_ERROR;
627         }
628
629         rdn_sa = dsdb_attribute_by_lDAPDisplayName(schema, rdn_name);
630         if (rdn_sa == NULL) {
631                 DEBUG(0,(__location__ ": No sa found for rDN %s for %s\n", rdn_name, ldb_dn_get_linearized(dn)));
632                 return LDB_ERR_OPERATIONS_ERROR;
633         }
634
635         DEBUG(6,("Sorting rpmd with attid exception %u rDN=%s DN=%s\n",
636                  rdn_sa->attributeID_id, rdn_name, ldb_dn_get_linearized(dn)));
637
638         LDB_TYPESAFE_QSORT(ctr1->array, ctr1->count, &rdn_sa->attributeID_id, replmd_replPropertyMetaData1_attid_sort);
639
640         return LDB_SUCCESS;
641 }
642
643 static int replmd_ldb_message_element_attid_sort(const struct ldb_message_element *e1,
644                                                  const struct ldb_message_element *e2,
645                                                  const struct dsdb_schema *schema)
646 {
647         const struct dsdb_attribute *a1;
648         const struct dsdb_attribute *a2;
649
650         /*
651          * TODO: make this faster by caching the dsdb_attribute pointer
652          *       on the ldb_messag_element
653          */
654
655         a1 = dsdb_attribute_by_lDAPDisplayName(schema, e1->name);
656         a2 = dsdb_attribute_by_lDAPDisplayName(schema, e2->name);
657
658         /*
659          * TODO: remove this check, we should rely on e1 and e2 having valid attribute names
660          *       in the schema
661          */
662         if (!a1 || !a2) {
663                 return strcasecmp(e1->name, e2->name);
664         }
665         if (a1->attributeID_id == a2->attributeID_id) {
666                 return 0;
667         }
668         return a1->attributeID_id > a2->attributeID_id ? 1 : -1;
669 }
670
671 static void replmd_ldb_message_sort(struct ldb_message *msg,
672                                     const struct dsdb_schema *schema)
673 {
674         LDB_TYPESAFE_QSORT(msg->elements, msg->num_elements, schema, replmd_ldb_message_element_attid_sort);
675 }
676
677 static int replmd_build_la_val(TALLOC_CTX *mem_ctx, struct ldb_val *v, struct dsdb_dn *dsdb_dn,
678                                const struct GUID *invocation_id, uint64_t seq_num,
679                                uint64_t local_usn, NTTIME nttime, uint32_t version, bool deleted);
680
681
682 /*
683   fix up linked attributes in replmd_add.
684   This involves setting up the right meta-data in extended DN
685   components, and creating backlinks to the object
686  */
687 static int replmd_add_fix_la(struct ldb_module *module, struct ldb_message_element *el,
688                              uint64_t seq_num, const struct GUID *invocationId, time_t t,
689                              struct GUID *guid, const struct dsdb_attribute *sa, struct ldb_request *parent)
690 {
691         unsigned int i;
692         TALLOC_CTX *tmp_ctx = talloc_new(el->values);
693         struct ldb_context *ldb = ldb_module_get_ctx(module);
694
695         /* We will take a reference to the schema in replmd_add_backlink */
696         const struct dsdb_schema *schema = dsdb_get_schema(ldb, NULL);
697         NTTIME now;
698
699         unix_to_nt_time(&now, t);
700
701         for (i=0; i<el->num_values; i++) {
702                 struct ldb_val *v = &el->values[i];
703                 struct dsdb_dn *dsdb_dn = dsdb_dn_parse(tmp_ctx, ldb, v, sa->syntax->ldap_oid);
704                 struct GUID target_guid;
705                 NTSTATUS status;
706                 int ret;
707
708                 /* note that the DN already has the extended
709                    components from the extended_dn_store module */
710                 status = dsdb_get_extended_dn_guid(dsdb_dn->dn, &target_guid, "GUID");
711                 if (!NT_STATUS_IS_OK(status) || GUID_all_zero(&target_guid)) {
712                         ret = dsdb_module_guid_by_dn(module, dsdb_dn->dn, &target_guid, parent);
713                         if (ret != LDB_SUCCESS) {
714                                 talloc_free(tmp_ctx);
715                                 return ret;
716                         }
717                         ret = dsdb_set_extended_dn_guid(dsdb_dn->dn, &target_guid, "GUID");
718                         if (ret != LDB_SUCCESS) {
719                                 talloc_free(tmp_ctx);
720                                 return ret;
721                         }
722                 }
723
724                 ret = replmd_build_la_val(el->values, v, dsdb_dn, invocationId,
725                                           seq_num, seq_num, now, 0, false);
726                 if (ret != LDB_SUCCESS) {
727                         talloc_free(tmp_ctx);
728                         return ret;
729                 }
730
731                 ret = replmd_add_backlink(module, schema, guid, &target_guid, true, sa, false);
732                 if (ret != LDB_SUCCESS) {
733                         talloc_free(tmp_ctx);
734                         return ret;
735                 }
736         }
737
738         talloc_free(tmp_ctx);
739         return LDB_SUCCESS;
740 }
741
742
743 /*
744   intercept add requests
745  */
746 static int replmd_add(struct ldb_module *module, struct ldb_request *req)
747 {
748         struct ldb_context *ldb;
749         struct ldb_control *control;
750         struct replmd_replicated_request *ac;
751         enum ndr_err_code ndr_err;
752         struct ldb_request *down_req;
753         struct ldb_message *msg;
754         const DATA_BLOB *guid_blob;
755         struct GUID guid;
756         struct replPropertyMetaDataBlob nmd;
757         struct ldb_val nmd_value;
758         const struct GUID *our_invocation_id;
759         time_t t = time(NULL);
760         NTTIME now;
761         char *time_str;
762         int ret;
763         unsigned int i;
764         unsigned int functional_level;
765         uint32_t ni=0;
766         bool allow_add_guid = false;
767         bool remove_current_guid = false;
768         bool is_urgent = false;
769         struct ldb_message_element *objectclass_el;
770
771         /* check if there's a show relax control (used by provision to say 'I know what I'm doing') */
772         control = ldb_request_get_control(req, LDB_CONTROL_RELAX_OID);
773         if (control) {
774                 allow_add_guid = true;
775         }
776
777         /* do not manipulate our control entries */
778         if (ldb_dn_is_special(req->op.add.message->dn)) {
779                 return ldb_next_request(module, req);
780         }
781
782         ldb = ldb_module_get_ctx(module);
783
784         ldb_debug(ldb, LDB_DEBUG_TRACE, "replmd_add\n");
785
786         guid_blob = ldb_msg_find_ldb_val(req->op.add.message, "objectGUID");
787         if (guid_blob != NULL) {
788                 if (!allow_add_guid) {
789                         ldb_set_errstring(ldb,
790                                           "replmd_add: it's not allowed to add an object with objectGUID!");
791                         return LDB_ERR_UNWILLING_TO_PERFORM;
792                 } else {
793                         NTSTATUS status = GUID_from_data_blob(guid_blob,&guid);
794                         if (!NT_STATUS_IS_OK(status)) {
795                                 ldb_set_errstring(ldb,
796                                                   "replmd_add: Unable to parse the 'objectGUID' as a GUID!");
797                                 return LDB_ERR_UNWILLING_TO_PERFORM;
798                         }
799                         /* we remove this attribute as it can be a string and
800                          * will not be treated correctly and then we will re-add
801                          * it later on in the good format */
802                         remove_current_guid = true;
803                 }
804         } else {
805                 /* a new GUID */
806                 guid = GUID_random();
807         }
808
809         ac = replmd_ctx_init(module, req);
810         if (ac == NULL) {
811                 return ldb_module_oom(module);
812         }
813
814         functional_level = dsdb_functional_level(ldb);
815
816         /* Get a sequence number from the backend */
817         ret = ldb_sequence_number(ldb, LDB_SEQ_NEXT, &ac->seq_num);
818         if (ret != LDB_SUCCESS) {
819                 talloc_free(ac);
820                 return ret;
821         }
822
823         /* get our invocationId */
824         our_invocation_id = samdb_ntds_invocation_id(ldb);
825         if (!our_invocation_id) {
826                 ldb_debug_set(ldb, LDB_DEBUG_ERROR,
827                               "replmd_add: unable to find invocationId\n");
828                 talloc_free(ac);
829                 return LDB_ERR_OPERATIONS_ERROR;
830         }
831
832         /* we have to copy the message as the caller might have it as a const */
833         msg = ldb_msg_copy_shallow(ac, req->op.add.message);
834         if (msg == NULL) {
835                 ldb_oom(ldb);
836                 talloc_free(ac);
837                 return LDB_ERR_OPERATIONS_ERROR;
838         }
839
840         /* generated times */
841         unix_to_nt_time(&now, t);
842         time_str = ldb_timestring(msg, t);
843         if (!time_str) {
844                 ldb_oom(ldb);
845                 talloc_free(ac);
846                 return LDB_ERR_OPERATIONS_ERROR;
847         }
848         if (remove_current_guid) {
849                 ldb_msg_remove_attr(msg,"objectGUID");
850         }
851
852         /*
853          * remove autogenerated attributes
854          */
855         ldb_msg_remove_attr(msg, "whenCreated");
856         ldb_msg_remove_attr(msg, "whenChanged");
857         ldb_msg_remove_attr(msg, "uSNCreated");
858         ldb_msg_remove_attr(msg, "uSNChanged");
859         ldb_msg_remove_attr(msg, "replPropertyMetaData");
860
861         /*
862          * readd replicated attributes
863          */
864         ret = ldb_msg_add_string(msg, "whenCreated", time_str);
865         if (ret != LDB_SUCCESS) {
866                 ldb_oom(ldb);
867                 talloc_free(ac);
868                 return ret;
869         }
870
871         /* build the replication meta_data */
872         ZERO_STRUCT(nmd);
873         nmd.version             = 1;
874         nmd.ctr.ctr1.count      = msg->num_elements;
875         nmd.ctr.ctr1.array      = talloc_array(msg,
876                                                struct replPropertyMetaData1,
877                                                nmd.ctr.ctr1.count);
878         if (!nmd.ctr.ctr1.array) {
879                 ldb_oom(ldb);
880                 talloc_free(ac);
881                 return LDB_ERR_OPERATIONS_ERROR;
882         }
883
884         for (i=0; i < msg->num_elements; i++) {
885                 struct ldb_message_element *e = &msg->elements[i];
886                 struct replPropertyMetaData1 *m = &nmd.ctr.ctr1.array[ni];
887                 const struct dsdb_attribute *sa;
888
889                 if (e->name[0] == '@') continue;
890
891                 sa = dsdb_attribute_by_lDAPDisplayName(ac->schema, e->name);
892                 if (!sa) {
893                         ldb_debug_set(ldb, LDB_DEBUG_ERROR,
894                                       "replmd_add: attribute '%s' not defined in schema\n",
895                                       e->name);
896                         talloc_free(ac);
897                         return LDB_ERR_NO_SUCH_ATTRIBUTE;
898                 }
899
900                 if ((sa->systemFlags & DS_FLAG_ATTR_NOT_REPLICATED) || (sa->systemFlags & DS_FLAG_ATTR_IS_CONSTRUCTED)) {
901                         /* if the attribute is not replicated (0x00000001)
902                          * or constructed (0x00000004) it has no metadata
903                          */
904                         continue;
905                 }
906
907                 if (sa->linkID != 0 && functional_level > DS_DOMAIN_FUNCTION_2000) {
908                         ret = replmd_add_fix_la(module, e, ac->seq_num, our_invocation_id, t, &guid, sa, req);
909                         if (ret != LDB_SUCCESS) {
910                                 talloc_free(ac);
911                                 return ret;
912                         }
913                         /* linked attributes are not stored in
914                            replPropertyMetaData in FL above w2k */
915                         continue;
916                 }
917
918                 m->attid                        = sa->attributeID_id;
919                 m->version                      = 1;
920                 m->originating_change_time      = now;
921                 m->originating_invocation_id    = *our_invocation_id;
922                 m->originating_usn              = ac->seq_num;
923                 m->local_usn                    = ac->seq_num;
924                 ni++;
925         }
926
927         /* fix meta data count */
928         nmd.ctr.ctr1.count = ni;
929
930         /*
931          * sort meta data array, and move the rdn attribute entry to the end
932          */
933         ret = replmd_replPropertyMetaDataCtr1_sort(&nmd.ctr.ctr1, ac->schema, msg->dn);
934         if (ret != LDB_SUCCESS) {
935                 talloc_free(ac);
936                 return ret;
937         }
938
939         /* generated NDR encoded values */
940         ndr_err = ndr_push_struct_blob(&nmd_value, msg,
941                                        &nmd,
942                                        (ndr_push_flags_fn_t)ndr_push_replPropertyMetaDataBlob);
943         if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
944                 ldb_oom(ldb);
945                 talloc_free(ac);
946                 return LDB_ERR_OPERATIONS_ERROR;
947         }
948
949         /*
950          * add the autogenerated values
951          */
952         ret = dsdb_msg_add_guid(msg, &guid, "objectGUID");
953         if (ret != LDB_SUCCESS) {
954                 ldb_oom(ldb);
955                 talloc_free(ac);
956                 return ret;
957         }
958         ret = ldb_msg_add_string(msg, "whenChanged", time_str);
959         if (ret != LDB_SUCCESS) {
960                 ldb_oom(ldb);
961                 talloc_free(ac);
962                 return ret;
963         }
964         ret = samdb_msg_add_uint64(ldb, msg, msg, "uSNCreated", ac->seq_num);
965         if (ret != LDB_SUCCESS) {
966                 ldb_oom(ldb);
967                 talloc_free(ac);
968                 return ret;
969         }
970         ret = samdb_msg_add_uint64(ldb, msg, msg, "uSNChanged", ac->seq_num);
971         if (ret != LDB_SUCCESS) {
972                 ldb_oom(ldb);
973                 talloc_free(ac);
974                 return ret;
975         }
976         ret = ldb_msg_add_value(msg, "replPropertyMetaData", &nmd_value, NULL);
977         if (ret != LDB_SUCCESS) {
978                 ldb_oom(ldb);
979                 talloc_free(ac);
980                 return ret;
981         }
982
983         /*
984          * sort the attributes by attid before storing the object
985          */
986         replmd_ldb_message_sort(msg, ac->schema);
987
988         objectclass_el = ldb_msg_find_element(msg, "objectClass");
989         is_urgent = replmd_check_urgent_objectclass(objectclass_el,
990                                                         REPL_URGENT_ON_CREATE);
991
992         ac->is_urgent = is_urgent;
993         ret = ldb_build_add_req(&down_req, ldb, ac,
994                                 msg,
995                                 req->controls,
996                                 ac, replmd_op_callback,
997                                 req);
998
999         LDB_REQ_SET_LOCATION(down_req);
1000         if (ret != LDB_SUCCESS) {
1001                 talloc_free(ac);
1002                 return ret;
1003         }
1004
1005         /* current partition control is needed by "replmd_op_callback" */
1006         if (ldb_request_get_control(req, DSDB_CONTROL_CURRENT_PARTITION_OID) == NULL) {
1007                 ret = ldb_request_add_control(down_req,
1008                                               DSDB_CONTROL_CURRENT_PARTITION_OID,
1009                                               false, NULL);
1010                 if (ret != LDB_SUCCESS) {
1011                         talloc_free(ac);
1012                         return ret;
1013                 }
1014         }
1015
1016         if (functional_level == DS_DOMAIN_FUNCTION_2000) {
1017                 ret = ldb_request_add_control(down_req, DSDB_CONTROL_APPLY_LINKS, false, NULL);
1018                 if (ret != LDB_SUCCESS) {
1019                         talloc_free(ac);
1020                         return ret;
1021                 }
1022         }
1023
1024         /* mark the control done */
1025         if (control) {
1026                 control->critical = 0;
1027         }
1028
1029         /* go on with the call chain */
1030         return ldb_next_request(module, down_req);
1031 }
1032
1033
1034 /*
1035  * update the replPropertyMetaData for one element
1036  */
1037 static int replmd_update_rpmd_element(struct ldb_context *ldb,
1038                                       struct ldb_message *msg,
1039                                       struct ldb_message_element *el,
1040                                       struct ldb_message_element *old_el,
1041                                       struct replPropertyMetaDataBlob *omd,
1042                                       const struct dsdb_schema *schema,
1043                                       uint64_t *seq_num,
1044                                       const struct GUID *our_invocation_id,
1045                                       NTTIME now,
1046                                       struct ldb_request *req)
1047 {
1048         uint32_t i;
1049         const struct dsdb_attribute *a;
1050         struct replPropertyMetaData1 *md1;
1051
1052         a = dsdb_attribute_by_lDAPDisplayName(schema, el->name);
1053         if (a == NULL) {
1054                 if (ldb_request_get_control(req, LDB_CONTROL_RELAX_OID)) {
1055                         /* allow this to make it possible for dbcheck
1056                            to remove bad attributes */
1057                         return LDB_SUCCESS;
1058                 }
1059
1060                 DEBUG(0,(__location__ ": Unable to find attribute %s in schema\n",
1061                          el->name));
1062                 return LDB_ERR_OPERATIONS_ERROR;
1063         }
1064
1065         if ((a->systemFlags & DS_FLAG_ATTR_NOT_REPLICATED) || (a->systemFlags & DS_FLAG_ATTR_IS_CONSTRUCTED)) {
1066                 return LDB_SUCCESS;
1067         }
1068
1069         /* if the attribute's value haven't changed then return LDB_SUCCESS     */
1070         if (old_el != NULL && ldb_msg_element_compare(el, old_el) == 0) {
1071                 if (!ldb_request_get_control(req, LDB_CONTROL_PROVISION_OID)) {
1072                         /*
1073                          * allow this to make it possible for dbcheck
1074                          * to rebuild broken metadata
1075                          */
1076                         return LDB_SUCCESS;
1077                 }
1078         }
1079
1080         for (i=0; i<omd->ctr.ctr1.count; i++) {
1081                 if (a->attributeID_id == omd->ctr.ctr1.array[i].attid) break;
1082         }
1083
1084         if (a->linkID != 0 && dsdb_functional_level(ldb) > DS_DOMAIN_FUNCTION_2000) {
1085                 /* linked attributes are not stored in
1086                    replPropertyMetaData in FL above w2k, but we do
1087                    raise the seqnum for the object  */
1088                 if (*seq_num == 0 &&
1089                     ldb_sequence_number(ldb, LDB_SEQ_NEXT, seq_num) != LDB_SUCCESS) {
1090                         return LDB_ERR_OPERATIONS_ERROR;
1091                 }
1092                 return LDB_SUCCESS;
1093         }
1094
1095         if (i == omd->ctr.ctr1.count) {
1096                 /* we need to add a new one */
1097                 omd->ctr.ctr1.array = talloc_realloc(msg, omd->ctr.ctr1.array,
1098                                                      struct replPropertyMetaData1, omd->ctr.ctr1.count+1);
1099                 if (omd->ctr.ctr1.array == NULL) {
1100                         ldb_oom(ldb);
1101                         return LDB_ERR_OPERATIONS_ERROR;
1102                 }
1103                 omd->ctr.ctr1.count++;
1104                 ZERO_STRUCT(omd->ctr.ctr1.array[i]);
1105         }
1106
1107         /* Get a new sequence number from the backend. We only do this
1108          * if we have a change that requires a new
1109          * replPropertyMetaData element
1110          */
1111         if (*seq_num == 0) {
1112                 int ret = ldb_sequence_number(ldb, LDB_SEQ_NEXT, seq_num);
1113                 if (ret != LDB_SUCCESS) {
1114                         return LDB_ERR_OPERATIONS_ERROR;
1115                 }
1116         }
1117
1118         md1 = &omd->ctr.ctr1.array[i];
1119         md1->version++;
1120         md1->attid                     = a->attributeID_id;
1121         md1->originating_change_time   = now;
1122         md1->originating_invocation_id = *our_invocation_id;
1123         md1->originating_usn           = *seq_num;
1124         md1->local_usn                 = *seq_num;
1125
1126         return LDB_SUCCESS;
1127 }
1128
1129 static uint64_t find_max_local_usn(struct replPropertyMetaDataBlob omd)
1130 {
1131         uint32_t count = omd.ctr.ctr1.count;
1132         uint64_t max = 0;
1133         uint32_t i;
1134         for (i=0; i < count; i++) {
1135                 struct replPropertyMetaData1 m = omd.ctr.ctr1.array[i];
1136                 if (max < m.local_usn) {
1137                         max = m.local_usn;
1138                 }
1139         }
1140         return max;
1141 }
1142
1143 /*
1144  * update the replPropertyMetaData object each time we modify an
1145  * object. This is needed for DRS replication, as the merge on the
1146  * client is based on this object
1147  */
1148 static int replmd_update_rpmd(struct ldb_module *module,
1149                               const struct dsdb_schema *schema,
1150                               struct ldb_request *req,
1151                               const char * const *rename_attrs,
1152                               struct ldb_message *msg, uint64_t *seq_num,
1153                               time_t t,
1154                               bool *is_urgent)
1155 {
1156         const struct ldb_val *omd_value;
1157         enum ndr_err_code ndr_err;
1158         struct replPropertyMetaDataBlob omd;
1159         unsigned int i;
1160         NTTIME now;
1161         const struct GUID *our_invocation_id;
1162         int ret;
1163         const char * const *attrs = NULL;
1164         const char * const attrs1[] = { "replPropertyMetaData", "*", NULL };
1165         const char * const attrs2[] = { "uSNChanged", "objectClass", "instanceType", NULL };
1166         struct ldb_result *res;
1167         struct ldb_context *ldb;
1168         struct ldb_message_element *objectclass_el;
1169         enum urgent_situation situation;
1170         bool rodc, rmd_is_provided;
1171
1172         if (rename_attrs) {
1173                 attrs = rename_attrs;
1174         } else {
1175                 attrs = attrs1;
1176         }
1177
1178         ldb = ldb_module_get_ctx(module);
1179
1180         our_invocation_id = samdb_ntds_invocation_id(ldb);
1181         if (!our_invocation_id) {
1182                 /* this happens during an initial vampire while
1183                    updating the schema */
1184                 DEBUG(5,("No invocationID - skipping replPropertyMetaData update\n"));
1185                 return LDB_SUCCESS;
1186         }
1187
1188         unix_to_nt_time(&now, t);
1189
1190         if (ldb_request_get_control(req, DSDB_CONTROL_CHANGEREPLMETADATA_OID)) {
1191                 rmd_is_provided = true;
1192         } else {
1193                 rmd_is_provided = false;
1194         }
1195
1196         /* if isDeleted is present and is TRUE, then we consider we are deleting,
1197          * otherwise we consider we are updating */
1198         if (ldb_msg_check_string_attribute(msg, "isDeleted", "TRUE")) {
1199                 situation = REPL_URGENT_ON_DELETE;
1200         } else if (rename_attrs) {
1201                 situation = REPL_URGENT_ON_CREATE | REPL_URGENT_ON_DELETE;
1202         } else {
1203                 situation = REPL_URGENT_ON_UPDATE;
1204         }
1205
1206         if (rmd_is_provided) {
1207                 /* In this case the change_replmetadata control was supplied */
1208                 /* We check that it's the only attribute that is provided
1209                  * (it's a rare case so it's better to keep the code simplier)
1210                  * We also check that the highest local_usn is bigger than
1211                  * uSNChanged. */
1212                 uint64_t db_seq;
1213                 if( msg->num_elements != 1 ||
1214                         strncmp(msg->elements[0].name,
1215                                 "replPropertyMetaData", 20) ) {
1216                         DEBUG(0,(__location__ ": changereplmetada control called without "\
1217                                 "a specified replPropertyMetaData attribute or with others\n"));
1218                         return LDB_ERR_OPERATIONS_ERROR;
1219                 }
1220                 if (situation != REPL_URGENT_ON_UPDATE) {
1221                         DEBUG(0,(__location__ ": changereplmetada control can't be called when deleting an object\n"));
1222                         return LDB_ERR_OPERATIONS_ERROR;
1223                 }
1224                 omd_value = ldb_msg_find_ldb_val(msg, "replPropertyMetaData");
1225                 if (!omd_value) {
1226                         DEBUG(0,(__location__ ": replPropertyMetaData was not specified for Object %s\n",
1227                                  ldb_dn_get_linearized(msg->dn)));
1228                         return LDB_ERR_OPERATIONS_ERROR;
1229                 }
1230                 ndr_err = ndr_pull_struct_blob(omd_value, msg, &omd,
1231                                                (ndr_pull_flags_fn_t)ndr_pull_replPropertyMetaDataBlob);
1232                 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
1233                         DEBUG(0,(__location__ ": Failed to parse replPropertyMetaData for %s\n",
1234                                  ldb_dn_get_linearized(msg->dn)));
1235                         return LDB_ERR_OPERATIONS_ERROR;
1236                 }
1237                 *seq_num = find_max_local_usn(omd);
1238
1239                 ret = dsdb_module_search_dn(module, msg, &res, msg->dn, attrs2,
1240                                             DSDB_FLAG_NEXT_MODULE |
1241                                             DSDB_SEARCH_SHOW_RECYCLED |
1242                                             DSDB_SEARCH_SHOW_EXTENDED_DN |
1243                                             DSDB_SEARCH_SHOW_DN_IN_STORAGE_FORMAT |
1244                                             DSDB_SEARCH_REVEAL_INTERNALS, req);
1245
1246                 if (ret != LDB_SUCCESS || res->count != 1) {
1247                         DEBUG(0,(__location__ ": Object %s failed to find uSNChanged\n",
1248                                  ldb_dn_get_linearized(msg->dn)));
1249                         return LDB_ERR_OPERATIONS_ERROR;
1250                 }
1251
1252                 objectclass_el = ldb_msg_find_element(res->msgs[0], "objectClass");
1253                 if (is_urgent && replmd_check_urgent_objectclass(objectclass_el,
1254                                                                 situation)) {
1255                         *is_urgent = true;
1256                 }
1257
1258                 db_seq = ldb_msg_find_attr_as_uint64(res->msgs[0], "uSNChanged", 0);
1259                 if (*seq_num <= db_seq) {
1260                         DEBUG(0,(__location__ ": changereplmetada control provided but max(local_usn)"\
1261                                               " is less or equal to uSNChanged (max = %lld uSNChanged = %lld)\n",
1262                                  (long long)*seq_num, (long long)db_seq));
1263                         return LDB_ERR_OPERATIONS_ERROR;
1264                 }
1265
1266         } else {
1267                 /* search for the existing replPropertyMetaDataBlob. We need
1268                  * to use REVEAL and ask for DNs in storage format to support
1269                  * the check for values being the same in
1270                  * replmd_update_rpmd_element()
1271                  */
1272                 ret = dsdb_module_search_dn(module, msg, &res, msg->dn, attrs,
1273                                             DSDB_FLAG_NEXT_MODULE |
1274                                             DSDB_SEARCH_SHOW_RECYCLED |
1275                                             DSDB_SEARCH_SHOW_EXTENDED_DN |
1276                                             DSDB_SEARCH_SHOW_DN_IN_STORAGE_FORMAT |
1277                                             DSDB_SEARCH_REVEAL_INTERNALS, req);
1278                 if (ret != LDB_SUCCESS || res->count != 1) {
1279                         DEBUG(0,(__location__ ": Object %s failed to find replPropertyMetaData\n",
1280                                  ldb_dn_get_linearized(msg->dn)));
1281                         return LDB_ERR_OPERATIONS_ERROR;
1282                 }
1283
1284                 objectclass_el = ldb_msg_find_element(res->msgs[0], "objectClass");
1285                 if (is_urgent && replmd_check_urgent_objectclass(objectclass_el,
1286                                                                 situation)) {
1287                         *is_urgent = true;
1288                 }
1289
1290                 omd_value = ldb_msg_find_ldb_val(res->msgs[0], "replPropertyMetaData");
1291                 if (!omd_value) {
1292                         DEBUG(0,(__location__ ": Object %s does not have a replPropertyMetaData attribute\n",
1293                                  ldb_dn_get_linearized(msg->dn)));
1294                         return LDB_ERR_OPERATIONS_ERROR;
1295                 }
1296
1297                 ndr_err = ndr_pull_struct_blob(omd_value, msg, &omd,
1298                                                (ndr_pull_flags_fn_t)ndr_pull_replPropertyMetaDataBlob);
1299                 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
1300                         DEBUG(0,(__location__ ": Failed to parse replPropertyMetaData for %s\n",
1301                                  ldb_dn_get_linearized(msg->dn)));
1302                         return LDB_ERR_OPERATIONS_ERROR;
1303                 }
1304
1305                 if (omd.version != 1) {
1306                         DEBUG(0,(__location__ ": bad version %u in replPropertyMetaData for %s\n",
1307                                  omd.version, ldb_dn_get_linearized(msg->dn)));
1308                         return LDB_ERR_OPERATIONS_ERROR;
1309                 }
1310
1311                 for (i=0; i<msg->num_elements; i++) {
1312                         struct ldb_message_element *old_el;
1313                         old_el = ldb_msg_find_element(res->msgs[0], msg->elements[i].name);
1314                         ret = replmd_update_rpmd_element(ldb, msg, &msg->elements[i], old_el, &omd, schema, seq_num,
1315                                                          our_invocation_id, now, req);
1316                         if (ret != LDB_SUCCESS) {
1317                                 return ret;
1318                         }
1319
1320                         if (is_urgent && !*is_urgent && (situation == REPL_URGENT_ON_UPDATE)) {
1321                                 *is_urgent = replmd_check_urgent_attribute(&msg->elements[i]);
1322                         }
1323
1324                 }
1325         }
1326         /*
1327          * replmd_update_rpmd_element has done an update if the
1328          * seq_num is set
1329          */
1330         if (*seq_num != 0) {
1331                 struct ldb_val *md_value;
1332                 struct ldb_message_element *el;
1333
1334                 /*if we are RODC and this is a DRSR update then its ok*/
1335                 if (!ldb_request_get_control(req, DSDB_CONTROL_REPLICATED_UPDATE_OID)) {
1336                         unsigned instanceType;
1337
1338                         ret = samdb_rodc(ldb, &rodc);
1339                         if (ret != LDB_SUCCESS) {
1340                                 DEBUG(4, (__location__ ": unable to tell if we are an RODC\n"));
1341                         } else if (rodc) {
1342                                 ldb_asprintf_errstring(ldb, "RODC modify is forbidden\n");
1343                                 return LDB_ERR_REFERRAL;
1344                         }
1345
1346                         instanceType = ldb_msg_find_attr_as_uint(res->msgs[0], "instanceType", INSTANCE_TYPE_WRITE);
1347                         if (!(instanceType & INSTANCE_TYPE_WRITE)) {
1348                                 return ldb_error(ldb, LDB_ERR_UNWILLING_TO_PERFORM,
1349                                                  "cannot change replicated attribute on partial replica");
1350                         }
1351                 }
1352
1353                 md_value = talloc(msg, struct ldb_val);
1354                 if (md_value == NULL) {
1355                         ldb_oom(ldb);
1356                         return LDB_ERR_OPERATIONS_ERROR;
1357                 }
1358
1359                 ret = replmd_replPropertyMetaDataCtr1_sort(&omd.ctr.ctr1, schema, msg->dn);
1360                 if (ret != LDB_SUCCESS) {
1361                         return ret;
1362                 }
1363
1364                 ndr_err = ndr_push_struct_blob(md_value, msg, &omd,
1365                                                (ndr_push_flags_fn_t)ndr_push_replPropertyMetaDataBlob);
1366                 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
1367                         DEBUG(0,(__location__ ": Failed to marshall replPropertyMetaData for %s\n",
1368                                  ldb_dn_get_linearized(msg->dn)));
1369                         return LDB_ERR_OPERATIONS_ERROR;
1370                 }
1371
1372                 ret = ldb_msg_add_empty(msg, "replPropertyMetaData", LDB_FLAG_MOD_REPLACE, &el);
1373                 if (ret != LDB_SUCCESS) {
1374                         DEBUG(0,(__location__ ": Failed to add updated replPropertyMetaData %s\n",
1375                                  ldb_dn_get_linearized(msg->dn)));
1376                         return ret;
1377                 }
1378
1379                 el->num_values = 1;
1380                 el->values = md_value;
1381         }
1382
1383         return LDB_SUCCESS;
1384 }
1385
1386 struct parsed_dn {
1387         struct dsdb_dn *dsdb_dn;
1388         struct GUID *guid;
1389         struct ldb_val *v;
1390 };
1391
1392 static int parsed_dn_compare(struct parsed_dn *pdn1, struct parsed_dn *pdn2)
1393 {
1394         return GUID_compare(pdn1->guid, pdn2->guid);
1395 }
1396
1397 static struct parsed_dn *parsed_dn_find(struct parsed_dn *pdn,
1398                                         unsigned int count, struct GUID *guid,
1399                                         struct ldb_dn *dn)
1400 {
1401         struct parsed_dn *ret;
1402         unsigned int i;
1403         if (dn && GUID_all_zero(guid)) {
1404                 /* when updating a link using DRS, we sometimes get a
1405                    NULL GUID. We then need to try and match by DN */
1406                 for (i=0; i<count; i++) {
1407                         if (ldb_dn_compare(pdn[i].dsdb_dn->dn, dn) == 0) {
1408                                 dsdb_get_extended_dn_guid(pdn[i].dsdb_dn->dn, guid, "GUID");
1409                                 return &pdn[i];
1410                         }
1411                 }
1412                 return NULL;
1413         }
1414         BINARY_ARRAY_SEARCH(pdn, count, guid, guid, GUID_compare, ret);
1415         return ret;
1416 }
1417
1418 /*
1419   get a series of message element values as an array of DNs and GUIDs
1420   the result is sorted by GUID
1421  */
1422 static int get_parsed_dns(struct ldb_module *module, TALLOC_CTX *mem_ctx,
1423                           struct ldb_message_element *el, struct parsed_dn **pdn,
1424                           const char *ldap_oid, struct ldb_request *parent)
1425 {
1426         unsigned int i;
1427         struct ldb_context *ldb = ldb_module_get_ctx(module);
1428
1429         if (el == NULL) {
1430                 *pdn = NULL;
1431                 return LDB_SUCCESS;
1432         }
1433
1434         (*pdn) = talloc_array(mem_ctx, struct parsed_dn, el->num_values);
1435         if (!*pdn) {
1436                 ldb_module_oom(module);
1437                 return LDB_ERR_OPERATIONS_ERROR;
1438         }
1439
1440         for (i=0; i<el->num_values; i++) {
1441                 struct ldb_val *v = &el->values[i];
1442                 NTSTATUS status;
1443                 struct ldb_dn *dn;
1444                 struct parsed_dn *p;
1445
1446                 p = &(*pdn)[i];
1447
1448                 p->dsdb_dn = dsdb_dn_parse(*pdn, ldb, v, ldap_oid);
1449                 if (p->dsdb_dn == NULL) {
1450                         return LDB_ERR_INVALID_DN_SYNTAX;
1451                 }
1452
1453                 dn = p->dsdb_dn->dn;
1454
1455                 p->guid = talloc(*pdn, struct GUID);
1456                 if (p->guid == NULL) {
1457                         ldb_module_oom(module);
1458                         return LDB_ERR_OPERATIONS_ERROR;
1459                 }
1460
1461                 status = dsdb_get_extended_dn_guid(dn, p->guid, "GUID");
1462                 if (NT_STATUS_EQUAL(status, NT_STATUS_OBJECT_NAME_NOT_FOUND)) {
1463                         /* we got a DN without a GUID - go find the GUID */
1464                         int ret = dsdb_module_guid_by_dn(module, dn, p->guid, parent);
1465                         if (ret != LDB_SUCCESS) {
1466                                 ldb_asprintf_errstring(ldb, "Unable to find GUID for DN %s\n",
1467                                                        ldb_dn_get_linearized(dn));
1468                                 if (ret == LDB_ERR_NO_SUCH_OBJECT &&
1469                                     LDB_FLAG_MOD_TYPE(el->flags) == LDB_FLAG_MOD_DELETE &&
1470                                     ldb_attr_cmp(el->name, "member") == 0) {
1471                                         return LDB_ERR_UNWILLING_TO_PERFORM;
1472                                 }
1473                                 return ret;
1474                         }
1475                         ret = dsdb_set_extended_dn_guid(dn, p->guid, "GUID");
1476                         if (ret != LDB_SUCCESS) {
1477                                 return ret;
1478                         }
1479                 } else if (!NT_STATUS_IS_OK(status)) {
1480                         return LDB_ERR_OPERATIONS_ERROR;
1481                 }
1482
1483                 /* keep a pointer to the original ldb_val */
1484                 p->v = v;
1485         }
1486
1487         TYPESAFE_QSORT(*pdn, el->num_values, parsed_dn_compare);
1488
1489         return LDB_SUCCESS;
1490 }
1491
1492 /*
1493   build a new extended DN, including all meta data fields
1494
1495   RMD_FLAGS           = DSDB_RMD_FLAG_* bits
1496   RMD_ADDTIME         = originating_add_time
1497   RMD_INVOCID         = originating_invocation_id
1498   RMD_CHANGETIME      = originating_change_time
1499   RMD_ORIGINATING_USN = originating_usn
1500   RMD_LOCAL_USN       = local_usn
1501   RMD_VERSION         = version
1502  */
1503 static int replmd_build_la_val(TALLOC_CTX *mem_ctx, struct ldb_val *v, struct dsdb_dn *dsdb_dn,
1504                                const struct GUID *invocation_id, uint64_t seq_num,
1505                                uint64_t local_usn, NTTIME nttime, uint32_t version, bool deleted)
1506 {
1507         struct ldb_dn *dn = dsdb_dn->dn;
1508         const char *tstring, *usn_string, *flags_string;
1509         struct ldb_val tval;
1510         struct ldb_val iid;
1511         struct ldb_val usnv, local_usnv;
1512         struct ldb_val vers, flagsv;
1513         NTSTATUS status;
1514         int ret;
1515         const char *dnstring;
1516         char *vstring;
1517         uint32_t rmd_flags = deleted?DSDB_RMD_FLAG_DELETED:0;
1518
1519         tstring = talloc_asprintf(mem_ctx, "%llu", (unsigned long long)nttime);
1520         if (!tstring) {
1521                 return LDB_ERR_OPERATIONS_ERROR;
1522         }
1523         tval = data_blob_string_const(tstring);
1524
1525         usn_string = talloc_asprintf(mem_ctx, "%llu", (unsigned long long)seq_num);
1526         if (!usn_string) {
1527                 return LDB_ERR_OPERATIONS_ERROR;
1528         }
1529         usnv = data_blob_string_const(usn_string);
1530
1531         usn_string = talloc_asprintf(mem_ctx, "%llu", (unsigned long long)local_usn);
1532         if (!usn_string) {
1533                 return LDB_ERR_OPERATIONS_ERROR;
1534         }
1535         local_usnv = data_blob_string_const(usn_string);
1536
1537         vstring = talloc_asprintf(mem_ctx, "%lu", (unsigned long)version);
1538         if (!vstring) {
1539                 return LDB_ERR_OPERATIONS_ERROR;
1540         }
1541         vers = data_blob_string_const(vstring);
1542
1543         status = GUID_to_ndr_blob(invocation_id, dn, &iid);
1544         if (!NT_STATUS_IS_OK(status)) {
1545                 return LDB_ERR_OPERATIONS_ERROR;
1546         }
1547
1548         flags_string = talloc_asprintf(mem_ctx, "%u", rmd_flags);
1549         if (!flags_string) {
1550                 return LDB_ERR_OPERATIONS_ERROR;
1551         }
1552         flagsv = data_blob_string_const(flags_string);
1553
1554         ret = ldb_dn_set_extended_component(dn, "RMD_FLAGS", &flagsv);
1555         if (ret != LDB_SUCCESS) return ret;
1556         ret = ldb_dn_set_extended_component(dn, "RMD_ADDTIME", &tval);
1557         if (ret != LDB_SUCCESS) return ret;
1558         ret = ldb_dn_set_extended_component(dn, "RMD_INVOCID", &iid);
1559         if (ret != LDB_SUCCESS) return ret;
1560         ret = ldb_dn_set_extended_component(dn, "RMD_CHANGETIME", &tval);
1561         if (ret != LDB_SUCCESS) return ret;
1562         ret = ldb_dn_set_extended_component(dn, "RMD_LOCAL_USN", &local_usnv);
1563         if (ret != LDB_SUCCESS) return ret;
1564         ret = ldb_dn_set_extended_component(dn, "RMD_ORIGINATING_USN", &usnv);
1565         if (ret != LDB_SUCCESS) return ret;
1566         ret = ldb_dn_set_extended_component(dn, "RMD_VERSION", &vers);
1567         if (ret != LDB_SUCCESS) return ret;
1568
1569         dnstring = dsdb_dn_get_extended_linearized(mem_ctx, dsdb_dn, 1);
1570         if (dnstring == NULL) {
1571                 return LDB_ERR_OPERATIONS_ERROR;
1572         }
1573         *v = data_blob_string_const(dnstring);
1574
1575         return LDB_SUCCESS;
1576 }
1577
1578 static int replmd_update_la_val(TALLOC_CTX *mem_ctx, struct ldb_val *v, struct dsdb_dn *dsdb_dn,
1579                                 struct dsdb_dn *old_dsdb_dn, const struct GUID *invocation_id,
1580                                 uint64_t seq_num, uint64_t local_usn, NTTIME nttime,
1581                                 uint32_t version, bool deleted);
1582
1583 /*
1584   check if any links need upgrading from w2k format
1585
1586   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.
1587  */
1588 static int replmd_check_upgrade_links(struct parsed_dn *dns, uint32_t count, struct ldb_message_element *parent_ctx, const struct GUID *invocation_id)
1589 {
1590         uint32_t i;
1591         for (i=0; i<count; i++) {
1592                 NTSTATUS status;
1593                 uint32_t version;
1594                 int ret;
1595
1596                 status = dsdb_get_extended_dn_uint32(dns[i].dsdb_dn->dn, &version, "RMD_VERSION");
1597                 if (!NT_STATUS_EQUAL(status, NT_STATUS_OBJECT_NAME_NOT_FOUND)) {
1598                         continue;
1599                 }
1600
1601                 /* it's an old one that needs upgrading */
1602                 ret = replmd_update_la_val(parent_ctx->values, dns[i].v, dns[i].dsdb_dn, dns[i].dsdb_dn, invocation_id,
1603                                            1, 1, 0, 0, false);
1604                 if (ret != LDB_SUCCESS) {
1605                         return ret;
1606                 }
1607         }
1608         return LDB_SUCCESS;
1609 }
1610
1611 /*
1612   update an extended DN, including all meta data fields
1613
1614   see replmd_build_la_val for value names
1615  */
1616 static int replmd_update_la_val(TALLOC_CTX *mem_ctx, struct ldb_val *v, struct dsdb_dn *dsdb_dn,
1617                                 struct dsdb_dn *old_dsdb_dn, const struct GUID *invocation_id,
1618                                 uint64_t seq_num, uint64_t local_usn, NTTIME nttime,
1619                                 uint32_t version, bool deleted)
1620 {
1621         struct ldb_dn *dn = dsdb_dn->dn;
1622         const char *tstring, *usn_string, *flags_string;
1623         struct ldb_val tval;
1624         struct ldb_val iid;
1625         struct ldb_val usnv, local_usnv;
1626         struct ldb_val vers, flagsv;
1627         const struct ldb_val *old_addtime;
1628         uint32_t old_version;
1629         NTSTATUS status;
1630         int ret;
1631         const char *dnstring;
1632         char *vstring;
1633         uint32_t rmd_flags = deleted?DSDB_RMD_FLAG_DELETED:0;
1634
1635         tstring = talloc_asprintf(mem_ctx, "%llu", (unsigned long long)nttime);
1636         if (!tstring) {
1637                 return LDB_ERR_OPERATIONS_ERROR;
1638         }
1639         tval = data_blob_string_const(tstring);
1640
1641         usn_string = talloc_asprintf(mem_ctx, "%llu", (unsigned long long)seq_num);
1642         if (!usn_string) {
1643                 return LDB_ERR_OPERATIONS_ERROR;
1644         }
1645         usnv = data_blob_string_const(usn_string);
1646
1647         usn_string = talloc_asprintf(mem_ctx, "%llu", (unsigned long long)local_usn);
1648         if (!usn_string) {
1649                 return LDB_ERR_OPERATIONS_ERROR;
1650         }
1651         local_usnv = data_blob_string_const(usn_string);
1652
1653         status = GUID_to_ndr_blob(invocation_id, dn, &iid);
1654         if (!NT_STATUS_IS_OK(status)) {
1655                 return LDB_ERR_OPERATIONS_ERROR;
1656         }
1657
1658         flags_string = talloc_asprintf(mem_ctx, "%u", rmd_flags);
1659         if (!flags_string) {
1660                 return LDB_ERR_OPERATIONS_ERROR;
1661         }
1662         flagsv = data_blob_string_const(flags_string);
1663
1664         ret = ldb_dn_set_extended_component(dn, "RMD_FLAGS", &flagsv);
1665         if (ret != LDB_SUCCESS) return ret;
1666
1667         /* get the ADDTIME from the original */
1668         old_addtime = ldb_dn_get_extended_component(old_dsdb_dn->dn, "RMD_ADDTIME");
1669         if (old_addtime == NULL) {
1670                 old_addtime = &tval;
1671         }
1672         if (dsdb_dn != old_dsdb_dn ||
1673             ldb_dn_get_extended_component(dn, "RMD_ADDTIME") == NULL) {
1674                 ret = ldb_dn_set_extended_component(dn, "RMD_ADDTIME", old_addtime);
1675                 if (ret != LDB_SUCCESS) return ret;
1676         }
1677
1678         /* use our invocation id */
1679         ret = ldb_dn_set_extended_component(dn, "RMD_INVOCID", &iid);
1680         if (ret != LDB_SUCCESS) return ret;
1681
1682         /* changetime is the current time */
1683         ret = ldb_dn_set_extended_component(dn, "RMD_CHANGETIME", &tval);
1684         if (ret != LDB_SUCCESS) return ret;
1685
1686         /* update the USN */
1687         ret = ldb_dn_set_extended_component(dn, "RMD_ORIGINATING_USN", &usnv);
1688         if (ret != LDB_SUCCESS) return ret;
1689
1690         ret = ldb_dn_set_extended_component(dn, "RMD_LOCAL_USN", &local_usnv);
1691         if (ret != LDB_SUCCESS) return ret;
1692
1693         /* increase the version by 1 */
1694         status = dsdb_get_extended_dn_uint32(old_dsdb_dn->dn, &old_version, "RMD_VERSION");
1695         if (NT_STATUS_IS_OK(status) && old_version >= version) {
1696                 version = old_version+1;
1697         }
1698         vstring = talloc_asprintf(dn, "%lu", (unsigned long)version);
1699         vers = data_blob_string_const(vstring);
1700         ret = ldb_dn_set_extended_component(dn, "RMD_VERSION", &vers);
1701         if (ret != LDB_SUCCESS) return ret;
1702
1703         dnstring = dsdb_dn_get_extended_linearized(mem_ctx, dsdb_dn, 1);
1704         if (dnstring == NULL) {
1705                 return LDB_ERR_OPERATIONS_ERROR;
1706         }
1707         *v = data_blob_string_const(dnstring);
1708
1709         return LDB_SUCCESS;
1710 }
1711
1712 /*
1713   handle adding a linked attribute
1714  */
1715 static int replmd_modify_la_add(struct ldb_module *module,
1716                                 const struct dsdb_schema *schema,
1717                                 struct ldb_message *msg,
1718                                 struct ldb_message_element *el,
1719                                 struct ldb_message_element *old_el,
1720                                 const struct dsdb_attribute *schema_attr,
1721                                 uint64_t seq_num,
1722                                 time_t t,
1723                                 struct GUID *msg_guid,
1724                                 struct ldb_request *parent)
1725 {
1726         unsigned int i;
1727         struct parsed_dn *dns, *old_dns;
1728         TALLOC_CTX *tmp_ctx = talloc_new(msg);
1729         int ret;
1730         struct ldb_val *new_values = NULL;
1731         unsigned int num_new_values = 0;
1732         unsigned old_num_values = old_el?old_el->num_values:0;
1733         const struct GUID *invocation_id;
1734         struct ldb_context *ldb = ldb_module_get_ctx(module);
1735         NTTIME now;
1736
1737         unix_to_nt_time(&now, t);
1738
1739         ret = get_parsed_dns(module, tmp_ctx, el, &dns, schema_attr->syntax->ldap_oid, parent);
1740         if (ret != LDB_SUCCESS) {
1741                 talloc_free(tmp_ctx);
1742                 return ret;
1743         }
1744
1745         ret = get_parsed_dns(module, tmp_ctx, old_el, &old_dns, schema_attr->syntax->ldap_oid, parent);
1746         if (ret != LDB_SUCCESS) {
1747                 talloc_free(tmp_ctx);
1748                 return ret;
1749         }
1750
1751         invocation_id = samdb_ntds_invocation_id(ldb);
1752         if (!invocation_id) {
1753                 talloc_free(tmp_ctx);
1754                 return LDB_ERR_OPERATIONS_ERROR;
1755         }
1756
1757         ret = replmd_check_upgrade_links(old_dns, old_num_values, old_el, invocation_id);
1758         if (ret != LDB_SUCCESS) {
1759                 talloc_free(tmp_ctx);
1760                 return ret;
1761         }
1762
1763         /* for each new value, see if it exists already with the same GUID */
1764         for (i=0; i<el->num_values; i++) {
1765                 struct parsed_dn *p = parsed_dn_find(old_dns, old_num_values, dns[i].guid, NULL);
1766                 if (p == NULL) {
1767                         /* this is a new linked attribute value */
1768                         new_values = talloc_realloc(tmp_ctx, new_values, struct ldb_val, num_new_values+1);
1769                         if (new_values == NULL) {
1770                                 ldb_module_oom(module);
1771                                 talloc_free(tmp_ctx);
1772                                 return LDB_ERR_OPERATIONS_ERROR;
1773                         }
1774                         ret = replmd_build_la_val(new_values, &new_values[num_new_values], dns[i].dsdb_dn,
1775                                                   invocation_id, seq_num, seq_num, now, 0, false);
1776                         if (ret != LDB_SUCCESS) {
1777                                 talloc_free(tmp_ctx);
1778                                 return ret;
1779                         }
1780                         num_new_values++;
1781                 } else {
1782                         /* this is only allowed if the GUID was
1783                            previously deleted. */
1784                         uint32_t rmd_flags = dsdb_dn_rmd_flags(p->dsdb_dn->dn);
1785
1786                         if (!(rmd_flags & DSDB_RMD_FLAG_DELETED)) {
1787                                 ldb_asprintf_errstring(ldb, "Attribute %s already exists for target GUID %s",
1788                                                        el->name, GUID_string(tmp_ctx, p->guid));
1789                                 talloc_free(tmp_ctx);
1790                                 /* error codes for 'member' need to be
1791                                    special cased */
1792                                 if (ldb_attr_cmp(el->name, "member") == 0) {
1793                                         return LDB_ERR_ENTRY_ALREADY_EXISTS;
1794                                 } else {
1795                                         return LDB_ERR_ATTRIBUTE_OR_VALUE_EXISTS;
1796                                 }
1797                         }
1798                         ret = replmd_update_la_val(old_el->values, p->v, dns[i].dsdb_dn, p->dsdb_dn,
1799                                                    invocation_id, seq_num, seq_num, now, 0, false);
1800                         if (ret != LDB_SUCCESS) {
1801                                 talloc_free(tmp_ctx);
1802                                 return ret;
1803                         }
1804                 }
1805
1806                 ret = replmd_add_backlink(module, schema, msg_guid, dns[i].guid, true, schema_attr, true);
1807                 if (ret != LDB_SUCCESS) {
1808                         talloc_free(tmp_ctx);
1809                         return ret;
1810                 }
1811         }
1812
1813         /* add the new ones on to the end of the old values, constructing a new el->values */
1814         el->values = talloc_realloc(msg->elements, old_el?old_el->values:NULL,
1815                                     struct ldb_val,
1816                                     old_num_values+num_new_values);
1817         if (el->values == NULL) {
1818                 ldb_module_oom(module);
1819                 return LDB_ERR_OPERATIONS_ERROR;
1820         }
1821
1822         memcpy(&el->values[old_num_values], new_values, num_new_values*sizeof(struct ldb_val));
1823         el->num_values = old_num_values + num_new_values;
1824
1825         talloc_steal(msg->elements, el->values);
1826         talloc_steal(el->values, new_values);
1827
1828         talloc_free(tmp_ctx);
1829
1830         /* we now tell the backend to replace all existing values
1831            with the one we have constructed */
1832         el->flags = LDB_FLAG_MOD_REPLACE;
1833
1834         return LDB_SUCCESS;
1835 }
1836
1837
1838 /*
1839   handle deleting all active linked attributes
1840  */
1841 static int replmd_modify_la_delete(struct ldb_module *module,
1842                                    const struct dsdb_schema *schema,
1843                                    struct ldb_message *msg,
1844                                    struct ldb_message_element *el,
1845                                    struct ldb_message_element *old_el,
1846                                    const struct dsdb_attribute *schema_attr,
1847                                    uint64_t seq_num,
1848                                    time_t t,
1849                                    struct GUID *msg_guid,
1850                                    struct ldb_request *parent)
1851 {
1852         unsigned int i;
1853         struct parsed_dn *dns, *old_dns;
1854         TALLOC_CTX *tmp_ctx = talloc_new(msg);
1855         int ret;
1856         const struct GUID *invocation_id;
1857         struct ldb_context *ldb = ldb_module_get_ctx(module);
1858         NTTIME now;
1859
1860         unix_to_nt_time(&now, t);
1861
1862         /* check if there is nothing to delete */
1863         if ((!old_el || old_el->num_values == 0) &&
1864             el->num_values == 0) {
1865                 return LDB_SUCCESS;
1866         }
1867
1868         if (!old_el || old_el->num_values == 0) {
1869                 return LDB_ERR_NO_SUCH_ATTRIBUTE;
1870         }
1871
1872         ret = get_parsed_dns(module, tmp_ctx, el, &dns, schema_attr->syntax->ldap_oid, parent);
1873         if (ret != LDB_SUCCESS) {
1874                 talloc_free(tmp_ctx);
1875                 return ret;
1876         }
1877
1878         ret = get_parsed_dns(module, tmp_ctx, old_el, &old_dns, schema_attr->syntax->ldap_oid, parent);
1879         if (ret != LDB_SUCCESS) {
1880                 talloc_free(tmp_ctx);
1881                 return ret;
1882         }
1883
1884         invocation_id = samdb_ntds_invocation_id(ldb);
1885         if (!invocation_id) {
1886                 return LDB_ERR_OPERATIONS_ERROR;
1887         }
1888
1889         ret = replmd_check_upgrade_links(old_dns, old_el->num_values, old_el, invocation_id);
1890         if (ret != LDB_SUCCESS) {
1891                 talloc_free(tmp_ctx);
1892                 return ret;
1893         }
1894
1895         el->values = NULL;
1896
1897         /* see if we are being asked to delete any links that
1898            don't exist or are already deleted */
1899         for (i=0; i<el->num_values; i++) {
1900                 struct parsed_dn *p = &dns[i];
1901                 struct parsed_dn *p2;
1902                 uint32_t rmd_flags;
1903
1904                 p2 = parsed_dn_find(old_dns, old_el->num_values, p->guid, NULL);
1905                 if (!p2) {
1906                         ldb_asprintf_errstring(ldb, "Attribute %s doesn't exist for target GUID %s",
1907                                                el->name, GUID_string(tmp_ctx, p->guid));
1908                         if (ldb_attr_cmp(el->name, "member") == 0) {
1909                                 return LDB_ERR_UNWILLING_TO_PERFORM;
1910                         } else {
1911                                 return LDB_ERR_NO_SUCH_ATTRIBUTE;
1912                         }
1913                 }
1914                 rmd_flags = dsdb_dn_rmd_flags(p2->dsdb_dn->dn);
1915                 if (rmd_flags & DSDB_RMD_FLAG_DELETED) {
1916                         ldb_asprintf_errstring(ldb, "Attribute %s already deleted for target GUID %s",
1917                                                el->name, GUID_string(tmp_ctx, p->guid));
1918                         if (ldb_attr_cmp(el->name, "member") == 0) {
1919                                 return LDB_ERR_UNWILLING_TO_PERFORM;
1920                         } else {
1921                                 return LDB_ERR_NO_SUCH_ATTRIBUTE;
1922                         }
1923                 }
1924         }
1925
1926         /* for each new value, see if it exists already with the same GUID
1927            if it is not already deleted and matches the delete list then delete it
1928         */
1929         for (i=0; i<old_el->num_values; i++) {
1930                 struct parsed_dn *p = &old_dns[i];
1931                 uint32_t rmd_flags;
1932
1933                 if (el->num_values && parsed_dn_find(dns, el->num_values, p->guid, NULL) == NULL) {
1934                         continue;
1935                 }
1936
1937                 rmd_flags = dsdb_dn_rmd_flags(p->dsdb_dn->dn);
1938                 if (rmd_flags & DSDB_RMD_FLAG_DELETED) continue;
1939
1940                 ret = replmd_update_la_val(old_el->values, p->v, p->dsdb_dn, p->dsdb_dn,
1941                                            invocation_id, seq_num, seq_num, now, 0, true);
1942                 if (ret != LDB_SUCCESS) {
1943                         talloc_free(tmp_ctx);
1944                         return ret;
1945                 }
1946
1947                 ret = replmd_add_backlink(module, schema, msg_guid, old_dns[i].guid, false, schema_attr, true);
1948                 if (ret != LDB_SUCCESS) {
1949                         talloc_free(tmp_ctx);
1950                         return ret;
1951                 }
1952         }
1953
1954         el->values = talloc_steal(msg->elements, old_el->values);
1955         el->num_values = old_el->num_values;
1956
1957         talloc_free(tmp_ctx);
1958
1959         /* we now tell the backend to replace all existing values
1960            with the one we have constructed */
1961         el->flags = LDB_FLAG_MOD_REPLACE;
1962
1963         return LDB_SUCCESS;
1964 }
1965
1966 /*
1967   handle replacing a linked attribute
1968  */
1969 static int replmd_modify_la_replace(struct ldb_module *module,
1970                                     const struct dsdb_schema *schema,
1971                                     struct ldb_message *msg,
1972                                     struct ldb_message_element *el,
1973                                     struct ldb_message_element *old_el,
1974                                     const struct dsdb_attribute *schema_attr,
1975                                     uint64_t seq_num,
1976                                     time_t t,
1977                                     struct GUID *msg_guid,
1978                                     struct ldb_request *parent)
1979 {
1980         unsigned int i;
1981         struct parsed_dn *dns, *old_dns;
1982         TALLOC_CTX *tmp_ctx = talloc_new(msg);
1983         int ret;
1984         const struct GUID *invocation_id;
1985         struct ldb_context *ldb = ldb_module_get_ctx(module);
1986         struct ldb_val *new_values = NULL;
1987         unsigned int num_new_values = 0;
1988         unsigned int old_num_values = old_el?old_el->num_values:0;
1989         NTTIME now;
1990
1991         unix_to_nt_time(&now, t);
1992
1993         /* check if there is nothing to replace */
1994         if ((!old_el || old_el->num_values == 0) &&
1995             el->num_values == 0) {
1996                 return LDB_SUCCESS;
1997         }
1998
1999         ret = get_parsed_dns(module, tmp_ctx, el, &dns, schema_attr->syntax->ldap_oid, parent);
2000         if (ret != LDB_SUCCESS) {
2001                 talloc_free(tmp_ctx);
2002                 return ret;
2003         }
2004
2005         ret = get_parsed_dns(module, tmp_ctx, old_el, &old_dns, schema_attr->syntax->ldap_oid, parent);
2006         if (ret != LDB_SUCCESS) {
2007                 talloc_free(tmp_ctx);
2008                 return ret;
2009         }
2010
2011         invocation_id = samdb_ntds_invocation_id(ldb);
2012         if (!invocation_id) {
2013                 return LDB_ERR_OPERATIONS_ERROR;
2014         }
2015
2016         ret = replmd_check_upgrade_links(old_dns, old_num_values, old_el, invocation_id);
2017         if (ret != LDB_SUCCESS) {
2018                 talloc_free(tmp_ctx);
2019                 return ret;
2020         }
2021
2022         /* mark all the old ones as deleted */
2023         for (i=0; i<old_num_values; i++) {
2024                 struct parsed_dn *old_p = &old_dns[i];
2025                 struct parsed_dn *p;
2026                 uint32_t rmd_flags = dsdb_dn_rmd_flags(old_p->dsdb_dn->dn);
2027
2028                 if (rmd_flags & DSDB_RMD_FLAG_DELETED) continue;
2029
2030                 ret = replmd_add_backlink(module, schema, msg_guid, old_dns[i].guid, false, schema_attr, false);
2031                 if (ret != LDB_SUCCESS) {
2032                         talloc_free(tmp_ctx);
2033                         return ret;
2034                 }
2035
2036                 p = parsed_dn_find(dns, el->num_values, old_p->guid, NULL);
2037                 if (p) {
2038                         /* we don't delete it if we are re-adding it */
2039                         continue;
2040                 }
2041
2042                 ret = replmd_update_la_val(old_el->values, old_p->v, old_p->dsdb_dn, old_p->dsdb_dn,
2043                                            invocation_id, seq_num, seq_num, now, 0, true);
2044                 if (ret != LDB_SUCCESS) {
2045                         talloc_free(tmp_ctx);
2046                         return ret;
2047                 }
2048         }
2049
2050         /* for each new value, either update its meta-data, or add it
2051          * to old_el
2052         */
2053         for (i=0; i<el->num_values; i++) {
2054                 struct parsed_dn *p = &dns[i], *old_p;
2055
2056                 if (old_dns &&
2057                     (old_p = parsed_dn_find(old_dns,
2058                                             old_num_values, p->guid, NULL)) != NULL) {
2059                         /* update in place */
2060                         ret = replmd_update_la_val(old_el->values, old_p->v, p->dsdb_dn,
2061                                                    old_p->dsdb_dn, invocation_id,
2062                                                    seq_num, seq_num, now, 0, false);
2063                         if (ret != LDB_SUCCESS) {
2064                                 talloc_free(tmp_ctx);
2065                                 return ret;
2066                         }
2067                 } else {
2068                         /* add a new one */
2069                         new_values = talloc_realloc(tmp_ctx, new_values, struct ldb_val,
2070                                                     num_new_values+1);
2071                         if (new_values == NULL) {
2072                                 ldb_module_oom(module);
2073                                 talloc_free(tmp_ctx);
2074                                 return LDB_ERR_OPERATIONS_ERROR;
2075                         }
2076                         ret = replmd_build_la_val(new_values, &new_values[num_new_values], dns[i].dsdb_dn,
2077                                                   invocation_id, seq_num, seq_num, now, 0, false);
2078                         if (ret != LDB_SUCCESS) {
2079                                 talloc_free(tmp_ctx);
2080                                 return ret;
2081                         }
2082                         num_new_values++;
2083                 }
2084
2085                 ret = replmd_add_backlink(module, schema, msg_guid, dns[i].guid, true, schema_attr, false);
2086                 if (ret != LDB_SUCCESS) {
2087                         talloc_free(tmp_ctx);
2088                         return ret;
2089                 }
2090         }
2091
2092         /* add the new values to the end of old_el */
2093         if (num_new_values != 0) {
2094                 el->values = talloc_realloc(msg->elements, old_el?old_el->values:NULL,
2095                                             struct ldb_val, old_num_values+num_new_values);
2096                 if (el->values == NULL) {
2097                         ldb_module_oom(module);
2098                         return LDB_ERR_OPERATIONS_ERROR;
2099                 }
2100                 memcpy(&el->values[old_num_values], &new_values[0],
2101                        sizeof(struct ldb_val)*num_new_values);
2102                 el->num_values = old_num_values + num_new_values;
2103                 talloc_steal(msg->elements, new_values);
2104         } else {
2105                 el->values = old_el->values;
2106                 el->num_values = old_el->num_values;
2107                 talloc_steal(msg->elements, el->values);
2108         }
2109
2110         talloc_free(tmp_ctx);
2111
2112         /* we now tell the backend to replace all existing values
2113            with the one we have constructed */
2114         el->flags = LDB_FLAG_MOD_REPLACE;
2115
2116         return LDB_SUCCESS;
2117 }
2118
2119
2120 /*
2121   handle linked attributes in modify requests
2122  */
2123 static int replmd_modify_handle_linked_attribs(struct ldb_module *module,
2124                                                struct ldb_message *msg,
2125                                                uint64_t seq_num, time_t t,
2126                                                struct ldb_request *parent)
2127 {
2128         struct ldb_result *res;
2129         unsigned int i;
2130         int ret;
2131         struct ldb_context *ldb = ldb_module_get_ctx(module);
2132         struct ldb_message *old_msg;
2133
2134         const struct dsdb_schema *schema;
2135         struct GUID old_guid;
2136
2137         if (seq_num == 0) {
2138                 /* there the replmd_update_rpmd code has already
2139                  * checked and saw that there are no linked
2140                  * attributes */
2141                 return LDB_SUCCESS;
2142         }
2143
2144         if (dsdb_functional_level(ldb) == DS_DOMAIN_FUNCTION_2000) {
2145                 /* don't do anything special for linked attributes */
2146                 return LDB_SUCCESS;
2147         }
2148
2149         ret = dsdb_module_search_dn(module, msg, &res, msg->dn, NULL,
2150                                     DSDB_FLAG_NEXT_MODULE |
2151                                     DSDB_SEARCH_SHOW_RECYCLED |
2152                                     DSDB_SEARCH_REVEAL_INTERNALS |
2153                                     DSDB_SEARCH_SHOW_DN_IN_STORAGE_FORMAT,
2154                                     parent);
2155         if (ret != LDB_SUCCESS) {
2156                 return ret;
2157         }
2158         schema = dsdb_get_schema(ldb, res);
2159         if (!schema) {
2160                 return LDB_ERR_OPERATIONS_ERROR;
2161         }
2162
2163         old_msg = res->msgs[0];
2164
2165         old_guid = samdb_result_guid(old_msg, "objectGUID");
2166
2167         for (i=0; i<msg->num_elements; i++) {
2168                 struct ldb_message_element *el = &msg->elements[i];
2169                 struct ldb_message_element *old_el, *new_el;
2170                 const struct dsdb_attribute *schema_attr
2171                         = dsdb_attribute_by_lDAPDisplayName(schema, el->name);
2172                 if (!schema_attr) {
2173                         ldb_asprintf_errstring(ldb,
2174                                                "%s: attribute %s is not a valid attribute in schema",
2175                                                __FUNCTION__, el->name);
2176                         return LDB_ERR_OBJECT_CLASS_VIOLATION;
2177                 }
2178                 if (schema_attr->linkID == 0) {
2179                         continue;
2180                 }
2181                 if ((schema_attr->linkID & 1) == 1) {
2182                         /* Odd is for the target.  Illegal to modify */
2183                         ldb_asprintf_errstring(ldb,
2184                                                "attribute %s must not be modified directly, it is a linked attribute", el->name);
2185                         return LDB_ERR_UNWILLING_TO_PERFORM;
2186                 }
2187                 old_el = ldb_msg_find_element(old_msg, el->name);
2188                 switch (el->flags & LDB_FLAG_MOD_MASK) {
2189                 case LDB_FLAG_MOD_REPLACE:
2190                         ret = replmd_modify_la_replace(module, schema, msg, el, old_el, schema_attr, seq_num, t, &old_guid, parent);
2191                         break;
2192                 case LDB_FLAG_MOD_DELETE:
2193                         ret = replmd_modify_la_delete(module, schema, msg, el, old_el, schema_attr, seq_num, t, &old_guid, parent);
2194                         break;
2195                 case LDB_FLAG_MOD_ADD:
2196                         ret = replmd_modify_la_add(module, schema, msg, el, old_el, schema_attr, seq_num, t, &old_guid, parent);
2197                         break;
2198                 default:
2199                         ldb_asprintf_errstring(ldb,
2200                                                "invalid flags 0x%x for %s linked attribute",
2201                                                el->flags, el->name);
2202                         return LDB_ERR_UNWILLING_TO_PERFORM;
2203                 }
2204                 if (dsdb_check_single_valued_link(schema_attr, el) != LDB_SUCCESS) {
2205                         ldb_asprintf_errstring(ldb,
2206                                                "Attribute %s is single valued but more than one value has been supplied",
2207                                                el->name);
2208                         return LDB_ERR_ATTRIBUTE_OR_VALUE_EXISTS;
2209                 } else {
2210                         el->flags |= LDB_FLAG_INTERNAL_DISABLE_SINGLE_VALUE_CHECK;
2211                 }
2212
2213
2214
2215                 if (ret != LDB_SUCCESS) {
2216                         return ret;
2217                 }
2218                 if (old_el) {
2219                         ldb_msg_remove_attr(old_msg, el->name);
2220                 }
2221                 ldb_msg_add_empty(old_msg, el->name, 0, &new_el);
2222                 new_el->num_values = el->num_values;
2223                 new_el->values = talloc_steal(msg->elements, el->values);
2224
2225                 /* TODO: this relises a bit too heavily on the exact
2226                    behaviour of ldb_msg_find_element and
2227                    ldb_msg_remove_element */
2228                 old_el = ldb_msg_find_element(msg, el->name);
2229                 if (old_el != el) {
2230                         ldb_msg_remove_element(msg, old_el);
2231                         i--;
2232                 }
2233         }
2234
2235         talloc_free(res);
2236         return ret;
2237 }
2238
2239
2240
2241 static int replmd_modify(struct ldb_module *module, struct ldb_request *req)
2242 {
2243         struct ldb_context *ldb;
2244         struct replmd_replicated_request *ac;
2245         struct ldb_request *down_req;
2246         struct ldb_message *msg;
2247         time_t t = time(NULL);
2248         int ret;
2249         bool is_urgent = false;
2250         struct loadparm_context *lp_ctx;
2251         char *referral;
2252         unsigned int functional_level;
2253         const DATA_BLOB *guid_blob;
2254
2255         /* do not manipulate our control entries */
2256         if (ldb_dn_is_special(req->op.mod.message->dn)) {
2257                 return ldb_next_request(module, req);
2258         }
2259
2260         ldb = ldb_module_get_ctx(module);
2261
2262         ldb_debug(ldb, LDB_DEBUG_TRACE, "replmd_modify\n");
2263
2264         guid_blob = ldb_msg_find_ldb_val(req->op.mod.message, "objectGUID");
2265         if ( guid_blob != NULL ) {
2266                 ldb_set_errstring(ldb,
2267                                   "replmd_modify: it's not allowed to change the objectGUID!");
2268                 return LDB_ERR_CONSTRAINT_VIOLATION;
2269         }
2270
2271         ac = replmd_ctx_init(module, req);
2272         if (ac == NULL) {
2273                 return ldb_module_oom(module);
2274         }
2275
2276         functional_level = dsdb_functional_level(ldb);
2277
2278         lp_ctx = talloc_get_type(ldb_get_opaque(ldb, "loadparm"),
2279                                  struct loadparm_context);
2280
2281         /* we have to copy the message as the caller might have it as a const */
2282         msg = ldb_msg_copy_shallow(ac, req->op.mod.message);
2283         if (msg == NULL) {
2284                 ldb_oom(ldb);
2285                 talloc_free(ac);
2286                 return LDB_ERR_OPERATIONS_ERROR;
2287         }
2288
2289         ldb_msg_remove_attr(msg, "whenChanged");
2290         ldb_msg_remove_attr(msg, "uSNChanged");
2291
2292         ret = replmd_update_rpmd(module, ac->schema, req, NULL,
2293                                  msg, &ac->seq_num, t, &is_urgent);
2294         if (ret == LDB_ERR_REFERRAL) {
2295                 referral = talloc_asprintf(req,
2296                                            "ldap://%s/%s",
2297                                            lpcfg_dnsdomain(lp_ctx),
2298                                            ldb_dn_get_linearized(msg->dn));
2299                 ret = ldb_module_send_referral(req, referral);
2300                 talloc_free(ac);
2301                 return ldb_module_done(req, NULL, NULL, ret);
2302         }
2303
2304         if (ret != LDB_SUCCESS) {
2305                 talloc_free(ac);
2306                 return ret;
2307         }
2308
2309         ret = replmd_modify_handle_linked_attribs(module, msg, ac->seq_num, t, req);
2310         if (ret != LDB_SUCCESS) {
2311                 talloc_free(ac);
2312                 return ret;
2313         }
2314
2315         /* TODO:
2316          * - replace the old object with the newly constructed one
2317          */
2318
2319         ac->is_urgent = is_urgent;
2320
2321         ret = ldb_build_mod_req(&down_req, ldb, ac,
2322                                 msg,
2323                                 req->controls,
2324                                 ac, replmd_op_callback,
2325                                 req);
2326         LDB_REQ_SET_LOCATION(down_req);
2327         if (ret != LDB_SUCCESS) {
2328                 talloc_free(ac);
2329                 return ret;
2330         }
2331
2332         /* current partition control is needed by "replmd_op_callback" */
2333         if (ldb_request_get_control(req, DSDB_CONTROL_CURRENT_PARTITION_OID) == NULL) {
2334                 ret = ldb_request_add_control(down_req,
2335                                               DSDB_CONTROL_CURRENT_PARTITION_OID,
2336                                               false, NULL);
2337                 if (ret != LDB_SUCCESS) {
2338                         talloc_free(ac);
2339                         return ret;
2340                 }
2341         }
2342
2343         /* If we are in functional level 2000, then
2344          * replmd_modify_handle_linked_attribs will have done
2345          * nothing */
2346         if (functional_level == DS_DOMAIN_FUNCTION_2000) {
2347                 ret = ldb_request_add_control(down_req, DSDB_CONTROL_APPLY_LINKS, false, NULL);
2348                 if (ret != LDB_SUCCESS) {
2349                         talloc_free(ac);
2350                         return ret;
2351                 }
2352         }
2353
2354         talloc_steal(down_req, msg);
2355
2356         /* we only change whenChanged and uSNChanged if the seq_num
2357            has changed */
2358         if (ac->seq_num != 0) {
2359                 ret = add_time_element(msg, "whenChanged", t);
2360                 if (ret != LDB_SUCCESS) {
2361                         talloc_free(ac);
2362                         return ret;
2363                 }
2364
2365                 ret = add_uint64_element(ldb, msg, "uSNChanged", ac->seq_num);
2366                 if (ret != LDB_SUCCESS) {
2367                         talloc_free(ac);
2368                         return ret;
2369                 }
2370         }
2371
2372         /* go on with the call chain */
2373         return ldb_next_request(module, down_req);
2374 }
2375
2376 static int replmd_rename_callback(struct ldb_request *req, struct ldb_reply *ares);
2377
2378 /*
2379   handle a rename request
2380
2381   On a rename we need to do an extra ldb_modify which sets the
2382   whenChanged and uSNChanged attributes.  We do this in a callback after the success.
2383  */
2384 static int replmd_rename(struct ldb_module *module, struct ldb_request *req)
2385 {
2386         struct ldb_context *ldb;
2387         struct replmd_replicated_request *ac;
2388         int ret;
2389         struct ldb_request *down_req;
2390
2391         /* do not manipulate our control entries */
2392         if (ldb_dn_is_special(req->op.mod.message->dn)) {
2393                 return ldb_next_request(module, req);
2394         }
2395
2396         ldb = ldb_module_get_ctx(module);
2397
2398         ldb_debug(ldb, LDB_DEBUG_TRACE, "replmd_rename\n");
2399
2400         ac = replmd_ctx_init(module, req);
2401         if (ac == NULL) {
2402                 return ldb_module_oom(module);
2403         }
2404
2405         ret = ldb_build_rename_req(&down_req, ldb, ac,
2406                                    ac->req->op.rename.olddn,
2407                                    ac->req->op.rename.newdn,
2408                                    ac->req->controls,
2409                                    ac, replmd_rename_callback,
2410                                    ac->req);
2411         LDB_REQ_SET_LOCATION(down_req);
2412         if (ret != LDB_SUCCESS) {
2413                 talloc_free(ac);
2414                 return ret;
2415         }
2416
2417         /* go on with the call chain */
2418         return ldb_next_request(module, down_req);
2419 }
2420
2421 /* After the rename is compleated, update the whenchanged etc */
2422 static int replmd_rename_callback(struct ldb_request *req, struct ldb_reply *ares)
2423 {
2424         struct ldb_context *ldb;
2425         struct replmd_replicated_request *ac;
2426         struct ldb_request *down_req;
2427         struct ldb_message *msg;
2428         const struct dsdb_attribute *rdn_attr;
2429         const char *rdn_name;
2430         const struct ldb_val *rdn_val;
2431         const char *attrs[5] = { NULL, };
2432         time_t t = time(NULL);
2433         int ret;
2434         bool is_urgent = false;
2435
2436         ac = talloc_get_type(req->context, struct replmd_replicated_request);
2437         ldb = ldb_module_get_ctx(ac->module);
2438
2439         if (ares->error != LDB_SUCCESS) {
2440                 return ldb_module_done(ac->req, ares->controls,
2441                                         ares->response, ares->error);
2442         }
2443
2444         if (ares->type != LDB_REPLY_DONE) {
2445                 ldb_set_errstring(ldb,
2446                                   "invalid ldb_reply_type in callback");
2447                 talloc_free(ares);
2448                 return ldb_module_done(ac->req, NULL, NULL,
2449                                         LDB_ERR_OPERATIONS_ERROR);
2450         }
2451
2452         /* TODO:
2453          * - replace the old object with the newly constructed one
2454          */
2455
2456         msg = ldb_msg_new(ac);
2457         if (msg == NULL) {
2458                 ldb_oom(ldb);
2459                 return LDB_ERR_OPERATIONS_ERROR;
2460         }
2461
2462         msg->dn = ac->req->op.rename.newdn;
2463
2464         rdn_name = ldb_dn_get_rdn_name(msg->dn);
2465         if (rdn_name == NULL) {
2466                 talloc_free(ares);
2467                 return ldb_module_done(ac->req, NULL, NULL,
2468                                        ldb_operr(ldb));
2469         }
2470
2471         /* normalize the rdn attribute name */
2472         rdn_attr = dsdb_attribute_by_lDAPDisplayName(ac->schema, rdn_name);
2473         if (rdn_attr == NULL) {
2474                 talloc_free(ares);
2475                 return ldb_module_done(ac->req, NULL, NULL,
2476                                        ldb_operr(ldb));
2477         }
2478         rdn_name = rdn_attr->lDAPDisplayName;
2479
2480         rdn_val = ldb_dn_get_rdn_val(msg->dn);
2481         if (rdn_val == NULL) {
2482                 talloc_free(ares);
2483                 return ldb_module_done(ac->req, NULL, NULL,
2484                                        ldb_operr(ldb));
2485         }
2486
2487         if (ldb_msg_add_empty(msg, rdn_name, LDB_FLAG_MOD_REPLACE, NULL) != 0) {
2488                 talloc_free(ares);
2489                 return ldb_module_done(ac->req, NULL, NULL,
2490                                        ldb_oom(ldb));
2491         }
2492         if (ldb_msg_add_value(msg, rdn_name, rdn_val, NULL) != 0) {
2493                 talloc_free(ares);
2494                 return ldb_module_done(ac->req, NULL, NULL,
2495                                        ldb_oom(ldb));
2496         }
2497         if (ldb_msg_add_empty(msg, "name", LDB_FLAG_MOD_REPLACE, NULL) != 0) {
2498                 talloc_free(ares);
2499                 return ldb_module_done(ac->req, NULL, NULL,
2500                                        ldb_oom(ldb));
2501         }
2502         if (ldb_msg_add_value(msg, "name", rdn_val, NULL) != 0) {
2503                 talloc_free(ares);
2504                 return ldb_module_done(ac->req, NULL, NULL,
2505                                        ldb_oom(ldb));
2506         }
2507
2508         /*
2509          * here we let replmd_update_rpmd() only search for
2510          * the existing "replPropertyMetaData" and rdn_name attributes.
2511          *
2512          * We do not want the existing "name" attribute as
2513          * the "name" attribute needs to get the version
2514          * updated on rename even if the rdn value hasn't changed.
2515          *
2516          * This is the diff of the meta data, for a moved user
2517          * on a w2k8r2 server:
2518          *
2519          * # record 1
2520          * -dn: CN=sdf df,CN=Users,DC=bla,DC=base
2521          * +dn: CN=sdf df,OU=TestOU,DC=bla,DC=base
2522          *  replPropertyMetaData:     NDR: struct replPropertyMetaDataBlob
2523          *         version                  : 0x00000001 (1)
2524          *         reserved                 : 0x00000000 (0)
2525          * @@ -66,11 +66,11 @@ replPropertyMetaData:     NDR: struct re
2526          *                      local_usn                : 0x00000000000037a5 (14245)
2527          *                 array: struct replPropertyMetaData1
2528          *                      attid                    : DRSUAPI_ATTID_name (0x90001)
2529          * -                    version                  : 0x00000001 (1)
2530          * -                    originating_change_time  : Wed Feb  9 17:20:49 2011 CET
2531          * +                    version                  : 0x00000002 (2)
2532          * +                    originating_change_time  : Wed Apr  6 15:21:01 2011 CEST
2533          *                      originating_invocation_id: 0d36ca05-5507-4e62-aca3-354bab0d39e1
2534          * -                    originating_usn          : 0x00000000000037a5 (14245)
2535          * -                    local_usn                : 0x00000000000037a5 (14245)
2536          * +                    originating_usn          : 0x0000000000003834 (14388)
2537          * +                    local_usn                : 0x0000000000003834 (14388)
2538          *                 array: struct replPropertyMetaData1
2539          *                      attid                    : DRSUAPI_ATTID_userAccountControl (0x90008)
2540          *                      version                  : 0x00000004 (4)
2541          */
2542         attrs[0] = "replPropertyMetaData";
2543         attrs[1] = "objectClass";
2544         attrs[2] = "instanceType";
2545         attrs[3] = rdn_name;
2546         attrs[4] = NULL;
2547
2548         ret = replmd_update_rpmd(ac->module, ac->schema, req, attrs,
2549                                  msg, &ac->seq_num, t, &is_urgent);
2550         if (ret == LDB_ERR_REFERRAL) {
2551                 struct ldb_dn *olddn = ac->req->op.rename.olddn;
2552                 struct loadparm_context *lp_ctx;
2553                 char *referral;
2554
2555                 lp_ctx = talloc_get_type(ldb_get_opaque(ldb, "loadparm"),
2556                                          struct loadparm_context);
2557
2558                 referral = talloc_asprintf(req,
2559                                            "ldap://%s/%s",
2560                                            lpcfg_dnsdomain(lp_ctx),
2561                                            ldb_dn_get_linearized(olddn));
2562                 ret = ldb_module_send_referral(req, referral);
2563                 talloc_free(ares);
2564                 return ldb_module_done(req, NULL, NULL, ret);
2565         }
2566
2567         if (ret != LDB_SUCCESS) {
2568                 talloc_free(ares);
2569                 return ldb_module_done(ac->req, NULL, NULL,
2570                                        ldb_error(ldb, ret,
2571                                         "failed to call replmd_update_rpmd()"));
2572         }
2573
2574         if (ac->seq_num == 0) {
2575                 talloc_free(ares);
2576                 return ldb_module_done(ac->req, NULL, NULL,
2577                                        ldb_error(ldb, ret,
2578                                         "internal error seq_num == 0"));
2579         }
2580         ac->is_urgent = is_urgent;
2581
2582         ret = ldb_build_mod_req(&down_req, ldb, ac,
2583                                 msg,
2584                                 req->controls,
2585                                 ac, replmd_op_callback,
2586                                 req);
2587         LDB_REQ_SET_LOCATION(down_req);
2588         if (ret != LDB_SUCCESS) {
2589                 talloc_free(ac);
2590                 return ret;
2591         }
2592
2593         /* current partition control is needed by "replmd_op_callback" */
2594         if (ldb_request_get_control(req, DSDB_CONTROL_CURRENT_PARTITION_OID) == NULL) {
2595                 ret = ldb_request_add_control(down_req,
2596                                               DSDB_CONTROL_CURRENT_PARTITION_OID,
2597                                               false, NULL);
2598                 if (ret != LDB_SUCCESS) {
2599                         talloc_free(ac);
2600                         return ret;
2601                 }
2602         }
2603
2604         talloc_steal(down_req, msg);
2605
2606         ret = add_time_element(msg, "whenChanged", t);
2607         if (ret != LDB_SUCCESS) {
2608                 talloc_free(ac);
2609                 return ret;
2610         }
2611
2612         ret = add_uint64_element(ldb, msg, "uSNChanged", ac->seq_num);
2613         if (ret != LDB_SUCCESS) {
2614                 talloc_free(ac);
2615                 return ret;
2616         }
2617
2618         /* go on with the call chain - do the modify after the rename */
2619         return ldb_next_request(ac->module, down_req);
2620 }
2621
2622 /*
2623    remove links from objects that point at this object when an object
2624    is deleted
2625  */
2626 static int replmd_delete_remove_link(struct ldb_module *module,
2627                                      const struct dsdb_schema *schema,
2628                                      struct ldb_dn *dn,
2629                                      struct ldb_message_element *el,
2630                                      const struct dsdb_attribute *sa,
2631                                      struct ldb_request *parent)
2632 {
2633         unsigned int i;
2634         TALLOC_CTX *tmp_ctx = talloc_new(module);
2635         struct ldb_context *ldb = ldb_module_get_ctx(module);
2636
2637         for (i=0; i<el->num_values; i++) {
2638                 struct dsdb_dn *dsdb_dn;
2639                 NTSTATUS status;
2640                 int ret;
2641                 struct GUID guid2;
2642                 struct ldb_message *msg;
2643                 const struct dsdb_attribute *target_attr;
2644                 struct ldb_message_element *el2;
2645                 struct ldb_val dn_val;
2646
2647                 if (dsdb_dn_is_deleted_val(&el->values[i])) {
2648                         continue;
2649                 }
2650
2651                 dsdb_dn = dsdb_dn_parse(tmp_ctx, ldb, &el->values[i], sa->syntax->ldap_oid);
2652                 if (!dsdb_dn) {
2653                         talloc_free(tmp_ctx);
2654                         return LDB_ERR_OPERATIONS_ERROR;
2655                 }
2656
2657                 status = dsdb_get_extended_dn_guid(dsdb_dn->dn, &guid2, "GUID");
2658                 if (!NT_STATUS_IS_OK(status)) {
2659                         talloc_free(tmp_ctx);
2660                         return LDB_ERR_OPERATIONS_ERROR;
2661                 }
2662
2663                 /* remove the link */
2664                 msg = ldb_msg_new(tmp_ctx);
2665                 if (!msg) {
2666                         ldb_module_oom(module);
2667                         talloc_free(tmp_ctx);
2668                         return LDB_ERR_OPERATIONS_ERROR;
2669                 }
2670
2671
2672                 msg->dn = dsdb_dn->dn;
2673
2674                 target_attr = dsdb_attribute_by_linkID(schema, sa->linkID ^ 1);
2675                 if (target_attr == NULL) {
2676                         continue;
2677                 }
2678
2679                 ret = ldb_msg_add_empty(msg, target_attr->lDAPDisplayName, LDB_FLAG_MOD_DELETE, &el2);
2680                 if (ret != LDB_SUCCESS) {
2681                         ldb_module_oom(module);
2682                         talloc_free(tmp_ctx);
2683                         return LDB_ERR_OPERATIONS_ERROR;
2684                 }
2685                 dn_val = data_blob_string_const(ldb_dn_get_linearized(dn));
2686                 el2->values = &dn_val;
2687                 el2->num_values = 1;
2688
2689                 ret = dsdb_module_modify(module, msg, DSDB_FLAG_OWN_MODULE, parent);
2690                 if (ret != LDB_SUCCESS) {
2691                         talloc_free(tmp_ctx);
2692                         return ret;
2693                 }
2694         }
2695         talloc_free(tmp_ctx);
2696         return LDB_SUCCESS;
2697 }
2698
2699
2700 /*
2701   handle update of replication meta data for deletion of objects
2702
2703   This also handles the mapping of delete to a rename operation
2704   to allow deletes to be replicated.
2705  */
2706 static int replmd_delete(struct ldb_module *module, struct ldb_request *req)
2707 {
2708         int ret = LDB_ERR_OTHER;
2709         bool retb, disallow_move_on_delete;
2710         struct ldb_dn *old_dn, *new_dn;
2711         const char *rdn_name;
2712         const struct ldb_val *rdn_value, *new_rdn_value;
2713         struct GUID guid;
2714         struct ldb_context *ldb = ldb_module_get_ctx(module);
2715         const struct dsdb_schema *schema;
2716         struct ldb_message *msg, *old_msg;
2717         struct ldb_message_element *el;
2718         TALLOC_CTX *tmp_ctx;
2719         struct ldb_result *res, *parent_res;
2720         const char *preserved_attrs[] = {
2721                 /* yes, this really is a hard coded list. See MS-ADTS
2722                    section 3.1.1.5.5.1.1 */
2723                 "nTSecurityDescriptor", "attributeID", "attributeSyntax", "dNReferenceUpdate", "dNSHostName",
2724                 "flatName", "governsID", "groupType", "instanceType", "lDAPDisplayName", "legacyExchangeDN",
2725                 "isDeleted", "isRecycled", "lastKnownParent", "msDS-LastKnownRDN", "mS-DS-CreatorSID",
2726                 "mSMQOwnerID", "nCName", "objectClass", "distinguishedName", "objectGUID", "objectSid",
2727                 "oMSyntax", "proxiedObjectName", "name", "replPropertyMetaData", "sAMAccountName",
2728                 "securityIdentifier", "sIDHistory", "subClassOf", "systemFlags", "trustPartner", "trustDirection",
2729                 "trustType", "trustAttributes", "userAccountControl", "uSNChanged", "uSNCreated", "whenCreated",
2730                 "whenChanged", NULL};
2731         unsigned int i, el_count = 0;
2732         enum deletion_state { OBJECT_NOT_DELETED=1, OBJECT_DELETED=2, OBJECT_RECYCLED=3,
2733                                                 OBJECT_TOMBSTONE=4, OBJECT_REMOVED=5 };
2734         enum deletion_state deletion_state, next_deletion_state;
2735         bool enabled;
2736         int functional_level;
2737
2738         if (ldb_dn_is_special(req->op.del.dn)) {
2739                 return ldb_next_request(module, req);
2740         }
2741
2742         tmp_ctx = talloc_new(ldb);
2743         if (!tmp_ctx) {
2744                 ldb_oom(ldb);
2745                 return LDB_ERR_OPERATIONS_ERROR;
2746         }
2747
2748         schema = dsdb_get_schema(ldb, tmp_ctx);
2749         if (!schema) {
2750                 return LDB_ERR_OPERATIONS_ERROR;
2751         }
2752
2753         functional_level = dsdb_functional_level(ldb);
2754
2755         old_dn = ldb_dn_copy(tmp_ctx, req->op.del.dn);
2756
2757         /* we need the complete msg off disk, so we can work out which
2758            attributes need to be removed */
2759         ret = dsdb_module_search_dn(module, tmp_ctx, &res, old_dn, NULL,
2760                                     DSDB_FLAG_NEXT_MODULE |
2761                                     DSDB_SEARCH_SHOW_RECYCLED |
2762                                     DSDB_SEARCH_REVEAL_INTERNALS |
2763                                     DSDB_SEARCH_SHOW_DN_IN_STORAGE_FORMAT, req);
2764         if (ret != LDB_SUCCESS) {
2765                 talloc_free(tmp_ctx);
2766                 return ret;
2767         }
2768         old_msg = res->msgs[0];
2769
2770
2771         ret = dsdb_recyclebin_enabled(module, &enabled);
2772         if (ret != LDB_SUCCESS) {
2773                 talloc_free(tmp_ctx);
2774                 return ret;
2775         }
2776
2777         if (ldb_msg_check_string_attribute(old_msg, "isDeleted", "TRUE")) {
2778                 if (!enabled) {
2779                         deletion_state = OBJECT_TOMBSTONE;
2780                         next_deletion_state = OBJECT_REMOVED;
2781                 } else if (ldb_msg_check_string_attribute(old_msg, "isRecycled", "TRUE")) {
2782                         deletion_state = OBJECT_RECYCLED;
2783                         next_deletion_state = OBJECT_REMOVED;
2784                 } else {
2785                         deletion_state = OBJECT_DELETED;
2786                         next_deletion_state = OBJECT_RECYCLED;
2787                 }
2788         } else {
2789                 deletion_state = OBJECT_NOT_DELETED;
2790                 if (enabled) {
2791                         next_deletion_state = OBJECT_DELETED;
2792                 } else {
2793                         next_deletion_state = OBJECT_TOMBSTONE;
2794                 }
2795         }
2796
2797         if (next_deletion_state == OBJECT_REMOVED) {
2798                 struct auth_session_info *session_info =
2799                                 (struct auth_session_info *)ldb_get_opaque(ldb, "sessionInfo");
2800                 if (security_session_user_level(session_info, NULL) != SECURITY_SYSTEM) {
2801                         ldb_asprintf_errstring(ldb, "Refusing to delete deleted object %s",
2802                                         ldb_dn_get_linearized(old_msg->dn));
2803                         return LDB_ERR_UNWILLING_TO_PERFORM;
2804                 }
2805
2806                 /* it is already deleted - really remove it this time */
2807                 talloc_free(tmp_ctx);
2808                 return ldb_next_request(module, req);
2809         }
2810
2811         rdn_name = ldb_dn_get_rdn_name(old_dn);
2812         rdn_value = ldb_dn_get_rdn_val(old_dn);
2813         if ((rdn_name == NULL) || (rdn_value == NULL)) {
2814                 talloc_free(tmp_ctx);
2815                 return ldb_operr(ldb);
2816         }
2817
2818         msg = ldb_msg_new(tmp_ctx);
2819         if (msg == NULL) {
2820                 ldb_module_oom(module);
2821                 talloc_free(tmp_ctx);
2822                 return LDB_ERR_OPERATIONS_ERROR;
2823         }
2824
2825         msg->dn = old_dn;
2826
2827         if (deletion_state == OBJECT_NOT_DELETED){
2828                 /* consider the SYSTEM_FLAG_DISALLOW_MOVE_ON_DELETE flag */
2829                 disallow_move_on_delete =
2830                         (ldb_msg_find_attr_as_int(old_msg, "systemFlags", 0)
2831                                 & SYSTEM_FLAG_DISALLOW_MOVE_ON_DELETE);
2832
2833                 /* work out where we will be renaming this object to */
2834                 if (!disallow_move_on_delete) {
2835                         ret = dsdb_get_deleted_objects_dn(ldb, tmp_ctx, old_dn,
2836                                                           &new_dn);
2837                         if (ret != LDB_SUCCESS) {
2838                                 /* this is probably an attempted delete on a partition
2839                                  * that doesn't allow delete operations, such as the
2840                                  * schema partition */
2841                                 ldb_asprintf_errstring(ldb, "No Deleted Objects container for DN %s",
2842                                                            ldb_dn_get_linearized(old_dn));
2843                                 talloc_free(tmp_ctx);
2844                                 return LDB_ERR_UNWILLING_TO_PERFORM;
2845                         }
2846                 } else {
2847                         new_dn = ldb_dn_get_parent(tmp_ctx, old_dn);
2848                         if (new_dn == NULL) {
2849                                 ldb_module_oom(module);
2850                                 talloc_free(tmp_ctx);
2851                                 return LDB_ERR_OPERATIONS_ERROR;
2852                         }
2853                 }
2854
2855                 /* get the objects GUID from the search we just did */
2856                 guid = samdb_result_guid(old_msg, "objectGUID");
2857
2858                 /* Add a formatted child */
2859                 retb = ldb_dn_add_child_fmt(new_dn, "%s=%s\\0ADEL:%s",
2860                                                 rdn_name,
2861                                                 ldb_dn_escape_value(tmp_ctx, *rdn_value),
2862                                                 GUID_string(tmp_ctx, &guid));
2863                 if (!retb) {
2864                         DEBUG(0,(__location__ ": Unable to add a formatted child to dn: %s",
2865                                         ldb_dn_get_linearized(new_dn)));
2866                         talloc_free(tmp_ctx);
2867                         return LDB_ERR_OPERATIONS_ERROR;
2868                 }
2869
2870                 ret = ldb_msg_add_string(msg, "isDeleted", "TRUE");
2871                 if (ret != LDB_SUCCESS) {
2872                         DEBUG(0,(__location__ ": Failed to add isDeleted string to the msg\n"));
2873                         ldb_module_oom(module);
2874                         talloc_free(tmp_ctx);
2875                         return ret;
2876                 }
2877                 msg->elements[el_count++].flags = LDB_FLAG_MOD_REPLACE;
2878         }
2879
2880         /*
2881           now we need to modify the object in the following ways:
2882
2883           - add isDeleted=TRUE
2884           - update rDN and name, with new rDN
2885           - remove linked attributes
2886           - remove objectCategory and sAMAccountType
2887           - remove attribs not on the preserved list
2888              - preserved if in above list, or is rDN
2889           - remove all linked attribs from this object
2890           - remove all links from other objects to this object
2891           - add lastKnownParent
2892           - update replPropertyMetaData?
2893
2894           see MS-ADTS "Tombstone Requirements" section 3.1.1.5.5.1.1
2895          */
2896
2897         /* we need the storage form of the parent GUID */
2898         ret = dsdb_module_search_dn(module, tmp_ctx, &parent_res,
2899                                     ldb_dn_get_parent(tmp_ctx, old_dn), NULL,
2900                                     DSDB_FLAG_NEXT_MODULE |
2901                                     DSDB_SEARCH_SHOW_DN_IN_STORAGE_FORMAT |
2902                                     DSDB_SEARCH_REVEAL_INTERNALS|
2903                                     DSDB_SEARCH_SHOW_RECYCLED, req);
2904         if (ret != LDB_SUCCESS) {
2905                 talloc_free(tmp_ctx);
2906                 return ret;
2907         }
2908
2909         if (deletion_state == OBJECT_NOT_DELETED){
2910                 ret = ldb_msg_add_steal_string(msg, "lastKnownParent",
2911                                                    ldb_dn_get_extended_linearized(tmp_ctx, parent_res->msgs[0]->dn, 1));
2912                 if (ret != LDB_SUCCESS) {
2913                         DEBUG(0,(__location__ ": Failed to add lastKnownParent string to the msg\n"));
2914                         ldb_module_oom(module);
2915                         talloc_free(tmp_ctx);
2916                         return ret;
2917                 }
2918                 msg->elements[el_count++].flags = LDB_FLAG_MOD_ADD;
2919         }
2920
2921         switch (next_deletion_state){
2922
2923         case OBJECT_DELETED:
2924
2925                 ret = ldb_msg_add_value(msg, "msDS-LastKnownRDN", rdn_value, NULL);
2926                 if (ret != LDB_SUCCESS) {
2927                         DEBUG(0,(__location__ ": Failed to add msDS-LastKnownRDN string to the msg\n"));
2928                         ldb_module_oom(module);
2929                         talloc_free(tmp_ctx);
2930                         return ret;
2931                 }
2932                 msg->elements[el_count++].flags = LDB_FLAG_MOD_ADD;
2933
2934                 ret = ldb_msg_add_empty(msg, "objectCategory", LDB_FLAG_MOD_REPLACE, NULL);