5aa3ed7badaa7eb4f42fd813e747f2c2b33a62c3
[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-2013
6    Copyright (C) Andrew Tridgell 2005-2009
7    Copyright (C) Stefan Metzmacher <metze@samba.org> 2007
8    Copyright (C) Matthieu Patou <mat@samba.org> 2010-2011
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 "dsdb/common/util.h"
43 #include "../libds/common/flags.h"
44 #include "librpc/gen_ndr/irpc.h"
45 #include "librpc/gen_ndr/ndr_misc.h"
46 #include "librpc/gen_ndr/ndr_drsuapi.h"
47 #include "librpc/gen_ndr/ndr_drsblobs.h"
48 #include "param/param.h"
49 #include "libcli/security/security.h"
50 #include "lib/util/dlinklist.h"
51 #include "dsdb/samdb/ldb_modules/util.h"
52 #include "lib/util/tsort.h"
53
54 #undef DBGC_CLASS
55 #define DBGC_CLASS            DBGC_DRS_REPL
56
57 /* the RMD_VERSION for linked attributes starts from 1 */
58 #define RMD_VERSION_INITIAL   1
59
60 /*
61  * It's 29/12/9999 at 23:59:59 UTC as specified in MS-ADTS 7.1.1.4.2
62  * Deleted Objects Container
63  */
64 static const NTTIME DELETED_OBJECT_CONTAINER_CHANGE_TIME = 2650466015990000000ULL;
65
66 struct replmd_private {
67         TALLOC_CTX *la_ctx;
68         struct la_entry *la_list;
69         struct nc_entry {
70                 struct nc_entry *prev, *next;
71                 struct ldb_dn *dn;
72                 uint64_t mod_usn;
73                 uint64_t mod_usn_urgent;
74         } *ncs;
75         struct ldb_dn *schema_dn;
76         bool originating_updates;
77         bool sorted_links;
78 };
79
80 struct la_entry {
81         struct la_entry *next, *prev;
82         struct drsuapi_DsReplicaLinkedAttribute *la;
83         uint32_t dsdb_repl_flags;
84 };
85
86 struct replmd_replicated_request {
87         struct ldb_module *module;
88         struct ldb_request *req;
89
90         const struct dsdb_schema *schema;
91         struct GUID our_invocation_id;
92
93         /* the controls we pass down */
94         struct ldb_control **controls;
95
96         /*
97          * Backlinks for the replmd_add() case (we want to create
98          * backlinks after creating the user, but before the end of
99          * the ADD request) 
100          */
101         struct la_backlink *la_backlinks;
102
103         /* details for the mode where we apply a bunch of inbound replication meessages */
104         bool apply_mode;
105         uint32_t index_current;
106         struct dsdb_extended_replicated_objects *objs;
107
108         struct ldb_message *search_msg;
109         struct GUID local_parent_guid;
110
111         uint64_t seq_num;
112         bool is_urgent;
113
114         bool isDeleted;
115 };
116
117 static int replmd_replicated_apply_merge(struct replmd_replicated_request *ar);
118 static int replmd_delete_internals(struct ldb_module *module, struct ldb_request *req, bool re_delete);
119 static int replmd_check_upgrade_links(struct ldb_context *ldb,
120                                       struct parsed_dn *dns, uint32_t count,
121                                       struct ldb_message_element *el,
122                                       const char *ldap_oid);
123 static int replmd_verify_linked_attribute(struct replmd_replicated_request *ar,
124                                           struct la_entry *la);
125 static int replmd_set_la_val(TALLOC_CTX *mem_ctx, struct ldb_val *v, struct dsdb_dn *dsdb_dn,
126                              struct dsdb_dn *old_dsdb_dn, const struct GUID *invocation_id,
127                              uint64_t usn, uint64_t local_usn, NTTIME nttime,
128                              uint32_t version, bool deleted);
129
130 static int replmd_make_deleted_child_dn(TALLOC_CTX *tmp_ctx,
131                                         struct ldb_context *ldb,
132                                         struct ldb_dn *dn,
133                                         const char *rdn_name,
134                                         const struct ldb_val *rdn_value,
135                                         struct GUID guid);
136
137 enum urgent_situation {
138         REPL_URGENT_ON_CREATE = 1,
139         REPL_URGENT_ON_UPDATE = 2,
140         REPL_URGENT_ON_DELETE = 4
141 };
142
143 enum deletion_state {
144         OBJECT_NOT_DELETED=1,
145         OBJECT_DELETED=2,
146         OBJECT_RECYCLED=3,
147         OBJECT_TOMBSTONE=4,
148         OBJECT_REMOVED=5
149 };
150
151 static void replmd_deletion_state(struct ldb_module *module,
152                                   const struct ldb_message *msg,
153                                   enum deletion_state *current_state,
154                                   enum deletion_state *next_state)
155 {
156         int ret;
157         bool enabled = false;
158
159         if (msg == NULL) {
160                 *current_state = OBJECT_REMOVED;
161                 if (next_state != NULL) {
162                         *next_state = OBJECT_REMOVED;
163                 }
164                 return;
165         }
166
167         ret = dsdb_recyclebin_enabled(module, &enabled);
168         if (ret != LDB_SUCCESS) {
169                 enabled = false;
170         }
171
172         if (ldb_msg_check_string_attribute(msg, "isDeleted", "TRUE")) {
173                 if (!enabled) {
174                         *current_state = OBJECT_TOMBSTONE;
175                         if (next_state != NULL) {
176                                 *next_state = OBJECT_REMOVED;
177                         }
178                         return;
179                 }
180
181                 if (ldb_msg_check_string_attribute(msg, "isRecycled", "TRUE")) {
182                         *current_state = OBJECT_RECYCLED;
183                         if (next_state != NULL) {
184                                 *next_state = OBJECT_REMOVED;
185                         }
186                         return;
187                 }
188
189                 *current_state = OBJECT_DELETED;
190                 if (next_state != NULL) {
191                         *next_state = OBJECT_RECYCLED;
192                 }
193                 return;
194         }
195
196         *current_state = OBJECT_NOT_DELETED;
197         if (next_state == NULL) {
198                 return;
199         }
200
201         if (enabled) {
202                 *next_state = OBJECT_DELETED;
203         } else {
204                 *next_state = OBJECT_TOMBSTONE;
205         }
206 }
207
208 static const struct {
209         const char *update_name;
210         enum urgent_situation repl_situation;
211 } urgent_objects[] = {
212                 {"nTDSDSA", (REPL_URGENT_ON_CREATE | REPL_URGENT_ON_DELETE)},
213                 {"crossRef", (REPL_URGENT_ON_CREATE | REPL_URGENT_ON_DELETE)},
214                 {"attributeSchema", (REPL_URGENT_ON_CREATE | REPL_URGENT_ON_UPDATE)},
215                 {"classSchema", (REPL_URGENT_ON_CREATE | REPL_URGENT_ON_UPDATE)},
216                 {"secret", (REPL_URGENT_ON_CREATE | REPL_URGENT_ON_UPDATE)},
217                 {"rIDManager", (REPL_URGENT_ON_CREATE | REPL_URGENT_ON_UPDATE)},
218                 {NULL, 0}
219 };
220
221 /* Attributes looked for when updating or deleting, to check for a urgent replication needed */
222 static const char *urgent_attrs[] = {
223                 "lockoutTime",
224                 "pwdLastSet",
225                 "userAccountControl",
226                 NULL
227 };
228
229
230 static bool replmd_check_urgent_objectclass(const struct ldb_message_element *objectclass_el,
231                                         enum urgent_situation situation)
232 {
233         unsigned int i, j;
234         for (i=0; urgent_objects[i].update_name; i++) {
235
236                 if ((situation & urgent_objects[i].repl_situation) == 0) {
237                         continue;
238                 }
239
240                 for (j=0; j<objectclass_el->num_values; j++) {
241                         const struct ldb_val *v = &objectclass_el->values[j];
242                         if (ldb_attr_cmp((const char *)v->data, urgent_objects[i].update_name) == 0) {
243                                 return true;
244                         }
245                 }
246         }
247         return false;
248 }
249
250 static bool replmd_check_urgent_attribute(const struct ldb_message_element *el)
251 {
252         if (ldb_attr_in_list(urgent_attrs, el->name)) {
253                 return true;
254         }
255         return false;
256 }
257
258 static int replmd_replicated_apply_isDeleted(struct replmd_replicated_request *ar);
259
260 /*
261   initialise the module
262   allocate the private structure and build the list
263   of partition DNs for use by replmd_notify()
264  */
265 static int replmd_init(struct ldb_module *module)
266 {
267         struct replmd_private *replmd_private;
268         struct ldb_context *ldb = ldb_module_get_ctx(module);
269         static const char *samba_dsdb_attrs[] = { SAMBA_COMPATIBLE_FEATURES_ATTR, NULL };
270         struct ldb_dn *samba_dsdb_dn;
271         struct ldb_result *res;
272         int ret;
273         TALLOC_CTX *frame = talloc_stackframe();
274         replmd_private = talloc_zero(module, struct replmd_private);
275         if (replmd_private == NULL) {
276                 ldb_oom(ldb);
277                 TALLOC_FREE(frame);
278                 return LDB_ERR_OPERATIONS_ERROR;
279         }
280         ldb_module_set_private(module, replmd_private);
281
282         replmd_private->schema_dn = ldb_get_schema_basedn(ldb);
283
284         samba_dsdb_dn = ldb_dn_new(frame, ldb, "@SAMBA_DSDB");
285         if (!samba_dsdb_dn) {
286                 TALLOC_FREE(frame);
287                 return ldb_oom(ldb);
288         }
289
290         ret = dsdb_module_search_dn(module, frame, &res, samba_dsdb_dn,
291                                     samba_dsdb_attrs, DSDB_FLAG_NEXT_MODULE, NULL);
292         if (ret == LDB_SUCCESS) {
293                 replmd_private->sorted_links
294                         = ldb_msg_check_string_attribute(res->msgs[0],
295                                                          SAMBA_COMPATIBLE_FEATURES_ATTR,
296                                                          SAMBA_SORTED_LINKS_FEATURE);
297         }
298         TALLOC_FREE(frame);
299
300         return ldb_next_init(module);
301 }
302
303 /*
304   cleanup our per-transaction contexts
305  */
306 static void replmd_txn_cleanup(struct replmd_private *replmd_private)
307 {
308         talloc_free(replmd_private->la_ctx);
309         replmd_private->la_list = NULL;
310         replmd_private->la_ctx = NULL;
311
312 }
313
314
315 struct la_backlink {
316         struct la_backlink *next, *prev;
317         const char *attr_name;
318         struct ldb_dn *forward_dn;
319         struct GUID target_guid;
320         bool active;
321 };
322
323 /*
324   a ldb_modify request operating on modules below the
325   current module
326  */
327 static int linked_attr_modify(struct ldb_module *module,
328                               const struct ldb_message *message,
329                               struct ldb_request *parent)
330 {
331         struct ldb_request *mod_req;
332         int ret;
333         struct ldb_context *ldb = ldb_module_get_ctx(module);
334         TALLOC_CTX *tmp_ctx = talloc_new(module);
335         struct ldb_result *res;
336
337         res = talloc_zero(tmp_ctx, struct ldb_result);
338         if (!res) {
339                 talloc_free(tmp_ctx);
340                 return ldb_oom(ldb_module_get_ctx(module));
341         }
342
343         ret = ldb_build_mod_req(&mod_req, ldb, tmp_ctx,
344                                 message,
345                                 NULL,
346                                 res,
347                                 ldb_modify_default_callback,
348                                 parent);
349         LDB_REQ_SET_LOCATION(mod_req);
350         if (ret != LDB_SUCCESS) {
351                 talloc_free(tmp_ctx);
352                 return ret;
353         }
354
355         ret = ldb_request_add_control(mod_req, DSDB_CONTROL_REPLICATED_UPDATE_OID,
356                                       false, NULL);
357         if (ret != LDB_SUCCESS) {
358                 return ret;
359         }
360
361         /* Run the new request */
362         ret = ldb_next_request(module, mod_req);
363
364         if (ret == LDB_SUCCESS) {
365                 ret = ldb_wait(mod_req->handle, LDB_WAIT_ALL);
366         }
367
368         talloc_free(tmp_ctx);
369         return ret;
370 }
371
372 /*
373   process a backlinks we accumulated during a transaction, adding and
374   deleting the backlinks from the target objects
375  */
376 static int replmd_process_backlink(struct ldb_module *module, struct la_backlink *bl, struct ldb_request *parent)
377 {
378         struct ldb_dn *target_dn, *source_dn;
379         int ret;
380         struct ldb_context *ldb = ldb_module_get_ctx(module);
381         struct ldb_message *msg;
382         TALLOC_CTX *frame = talloc_stackframe();
383         char *dn_string;
384
385         /*
386           - find DN of target
387           - find DN of source
388           - construct ldb_message
389               - either an add or a delete
390          */
391         ret = dsdb_module_dn_by_guid(module, frame, &bl->target_guid, &target_dn, parent);
392         if (ret != LDB_SUCCESS) {
393                 struct GUID_txt_buf guid_str;
394                 DBG_WARNING("Failed to find target DN for linked attribute with GUID %s\n",
395                             GUID_buf_string(&bl->target_guid, &guid_str));
396                 DBG_WARNING("Please run 'samba-tool dbcheck' to resolve any missing backlinks.\n");
397                 talloc_free(frame);
398                 return LDB_SUCCESS;
399         }
400
401         msg = ldb_msg_new(frame);
402         if (msg == NULL) {
403                 ldb_module_oom(module);
404                 talloc_free(frame);
405                 return LDB_ERR_OPERATIONS_ERROR;
406         }
407
408         source_dn = ldb_dn_copy(frame, bl->forward_dn);
409         if (!source_dn) {
410                 ldb_module_oom(module);
411                 talloc_free(frame);
412                 return LDB_ERR_OPERATIONS_ERROR;
413         } else {
414                 /* Filter down to the attributes we want in the backlink */
415                 const char *accept[] = { "GUID", "SID", NULL };
416                 ldb_dn_extended_filter(source_dn, accept);
417         }
418
419         /* construct a ldb_message for adding/deleting the backlink */
420         msg->dn = target_dn;
421         dn_string = ldb_dn_get_extended_linearized(frame, bl->forward_dn, 1);
422         if (!dn_string) {
423                 ldb_module_oom(module);
424                 talloc_free(frame);
425                 return LDB_ERR_OPERATIONS_ERROR;
426         }
427         ret = ldb_msg_add_steal_string(msg, bl->attr_name, dn_string);
428         if (ret != LDB_SUCCESS) {
429                 talloc_free(frame);
430                 return ret;
431         }
432         msg->elements[0].flags = bl->active?LDB_FLAG_MOD_ADD:LDB_FLAG_MOD_DELETE;
433
434         /* a backlink should never be single valued. Unfortunately the
435            exchange schema has a attribute
436            msExchBridgeheadedLocalConnectorsDNBL which is single
437            valued and a backlink. We need to cope with that by
438            ignoring the single value flag */
439         msg->elements[0].flags |= LDB_FLAG_INTERNAL_DISABLE_SINGLE_VALUE_CHECK;
440
441         ret = dsdb_module_modify(module, msg, DSDB_FLAG_NEXT_MODULE, parent);
442         if (ret == LDB_ERR_NO_SUCH_ATTRIBUTE && !bl->active) {
443                 /* we allow LDB_ERR_NO_SUCH_ATTRIBUTE as success to
444                    cope with possible corruption where the backlink has
445                    already been removed */
446                 DEBUG(3,("WARNING: backlink from %s already removed from %s - %s\n",
447                          ldb_dn_get_linearized(target_dn),
448                          ldb_dn_get_linearized(source_dn),
449                          ldb_errstring(ldb)));
450                 ret = LDB_SUCCESS;
451         } else if (ret != LDB_SUCCESS) {
452                 ldb_asprintf_errstring(ldb, "Failed to %s backlink from %s to %s - %s",
453                                        bl->active?"add":"remove",
454                                        ldb_dn_get_linearized(source_dn),
455                                        ldb_dn_get_linearized(target_dn),
456                                        ldb_errstring(ldb));
457                 talloc_free(frame);
458                 return ret;
459         }
460         talloc_free(frame);
461         return ret;
462 }
463
464 /*
465   add a backlink to the list of backlinks to add/delete in the prepare
466   commit
467
468   forward_dn is stolen onto the defereed context
469  */
470 static int replmd_defer_add_backlink(struct ldb_module *module,
471                                      struct replmd_private *replmd_private,
472                                      const struct dsdb_schema *schema,
473                                      struct replmd_replicated_request *ac,
474                                      struct ldb_dn *forward_dn,
475                                      struct GUID *target_guid, bool active,
476                                      const struct dsdb_attribute *schema_attr,
477                                      struct ldb_request *parent)
478 {
479         const struct dsdb_attribute *target_attr;
480         struct la_backlink *bl;
481         
482         bl = talloc(ac, struct la_backlink);
483         if (bl == NULL) {
484                 ldb_module_oom(module);
485                 return LDB_ERR_OPERATIONS_ERROR;
486         }
487
488         target_attr = dsdb_attribute_by_linkID(schema, schema_attr->linkID ^ 1);
489         if (!target_attr) {
490                 /*
491                  * windows 2003 has a broken schema where the
492                  * definition of msDS-IsDomainFor is missing (which is
493                  * supposed to be the backlink of the
494                  * msDS-HasDomainNCs attribute
495                  */
496                 return LDB_SUCCESS;
497         }
498
499         bl->attr_name = target_attr->lDAPDisplayName;
500         bl->forward_dn = talloc_steal(bl, forward_dn);
501         bl->target_guid = *target_guid;
502         bl->active = active;
503
504         DLIST_ADD(ac->la_backlinks, bl);
505
506         return LDB_SUCCESS;
507 }
508
509 /*
510   add a backlink to the list of backlinks to add/delete in the prepare
511   commit
512  */
513 static int replmd_add_backlink(struct ldb_module *module,
514                                struct replmd_private *replmd_private,
515                                const struct dsdb_schema *schema,
516                                struct ldb_dn *forward_dn,
517                                struct GUID *target_guid, bool active,
518                                const struct dsdb_attribute *schema_attr,
519                                struct ldb_request *parent)
520 {
521         const struct dsdb_attribute *target_attr;
522         struct la_backlink bl;
523         int ret;
524         
525         target_attr = dsdb_attribute_by_linkID(schema, schema_attr->linkID ^ 1);
526         if (!target_attr) {
527                 /*
528                  * windows 2003 has a broken schema where the
529                  * definition of msDS-IsDomainFor is missing (which is
530                  * supposed to be the backlink of the
531                  * msDS-HasDomainNCs attribute
532                  */
533                 return LDB_SUCCESS;
534         }
535
536         bl.attr_name = target_attr->lDAPDisplayName;
537         bl.forward_dn = forward_dn;
538         bl.target_guid = *target_guid;
539         bl.active = active;
540
541         ret = replmd_process_backlink(module, &bl, parent);
542         return ret;
543 }
544
545
546 /*
547  * Callback for most write operations in this module:
548  *
549  * notify the repl task that a object has changed. The notifies are
550  * gathered up in the replmd_private structure then written to the
551  * @REPLCHANGED object in each partition during the prepare_commit
552  */
553 static int replmd_op_callback(struct ldb_request *req, struct ldb_reply *ares)
554 {
555         int ret;
556         struct replmd_replicated_request *ac =
557                 talloc_get_type_abort(req->context, struct replmd_replicated_request);
558         struct replmd_private *replmd_private =
559                 talloc_get_type_abort(ldb_module_get_private(ac->module), struct replmd_private);
560         struct nc_entry *modified_partition;
561         struct ldb_control *partition_ctrl;
562         const struct dsdb_control_current_partition *partition;
563
564         struct ldb_control **controls;
565
566         partition_ctrl = ldb_reply_get_control(ares, DSDB_CONTROL_CURRENT_PARTITION_OID);
567
568         controls = ares->controls;
569         if (ldb_request_get_control(ac->req,
570                                     DSDB_CONTROL_CURRENT_PARTITION_OID) == NULL) {
571                 /*
572                  * Remove the current partition control from what we pass up
573                  * the chain if it hasn't been requested manually.
574                  */
575                 controls = ldb_controls_except_specified(ares->controls, ares,
576                                                          partition_ctrl);
577         }
578
579         if (ares->error != LDB_SUCCESS) {
580                 struct GUID_txt_buf guid_txt;
581                 struct ldb_message *msg = NULL;
582                 char *s = NULL;
583
584                 if (ac->apply_mode == false) {
585                         DBG_NOTICE("Originating update failure. Error is: %s\n",
586                                    ldb_strerror(ares->error));
587                         return ldb_module_done(ac->req, controls,
588                                                ares->response, ares->error);
589                 }
590
591                 msg = ac->objs->objects[ac->index_current].msg;
592                 /*
593                  * Set at DBG_NOTICE as once these start to happe, they
594                  * will happen a lot until resolved, due to repeated
595                  * replication.  The caller will probably print the
596                  * ldb error string anyway.
597                  */
598                 DBG_NOTICE("DRS replication apply failure for %s. Error is: %s\n",
599                            ldb_dn_get_linearized(msg->dn),
600                            ldb_strerror(ares->error));
601
602                 s = ldb_ldif_message_redacted_string(ldb_module_get_ctx(ac->module),
603                                                      ac,
604                                                      LDB_CHANGETYPE_ADD,
605                                                      msg);
606
607                 DBG_INFO("Failing DRS %s replication message was %s:\n%s\n",
608                          ac->search_msg == NULL ? "ADD" : "MODIFY",
609                          GUID_buf_string(&ac->objs->objects[ac->index_current].object_guid,
610                                          &guid_txt),
611                          s);
612                 talloc_free(s);
613                 return ldb_module_done(ac->req, controls,
614                                        ares->response, ares->error);
615         }
616
617         if (ares->type != LDB_REPLY_DONE) {
618                 ldb_set_errstring(ldb_module_get_ctx(ac->module), "Invalid reply type for notify\n!");
619                 return ldb_module_done(ac->req, NULL,
620                                        NULL, LDB_ERR_OPERATIONS_ERROR);
621         }
622
623         if (ac->apply_mode == false) {
624                 struct la_backlink *bl;
625                 /*
626                  * process our backlink list after an replmd_add(),
627                  * creating and deleting backlinks as necessary (this
628                  * code is sync).  The other cases are handled inline
629                  * with the modify.
630                  */
631                 for (bl=ac->la_backlinks; bl; bl=bl->next) {
632                         ret = replmd_process_backlink(ac->module, bl, ac->req);
633                         if (ret != LDB_SUCCESS) {
634                                 return ldb_module_done(ac->req, NULL,
635                                                        NULL, ret);
636                         }
637                 }
638         }
639         
640         if (!partition_ctrl) {
641                 ldb_set_errstring(ldb_module_get_ctx(ac->module),"No partition control on reply");
642                 return ldb_module_done(ac->req, NULL,
643                                        NULL, LDB_ERR_OPERATIONS_ERROR);
644         }
645
646         partition = talloc_get_type_abort(partition_ctrl->data,
647                                     struct dsdb_control_current_partition);
648
649         if (ac->seq_num > 0) {
650                 for (modified_partition = replmd_private->ncs; modified_partition;
651                      modified_partition = modified_partition->next) {
652                         if (ldb_dn_compare(modified_partition->dn, partition->dn) == 0) {
653                                 break;
654                         }
655                 }
656
657                 if (modified_partition == NULL) {
658                         modified_partition = talloc_zero(replmd_private, struct nc_entry);
659                         if (!modified_partition) {
660                                 ldb_oom(ldb_module_get_ctx(ac->module));
661                                 return ldb_module_done(ac->req, NULL,
662                                                        NULL, LDB_ERR_OPERATIONS_ERROR);
663                         }
664                         modified_partition->dn = ldb_dn_copy(modified_partition, partition->dn);
665                         if (!modified_partition->dn) {
666                                 ldb_oom(ldb_module_get_ctx(ac->module));
667                                 return ldb_module_done(ac->req, NULL,
668                                                        NULL, LDB_ERR_OPERATIONS_ERROR);
669                         }
670                         DLIST_ADD(replmd_private->ncs, modified_partition);
671                 }
672
673                 if (ac->seq_num > modified_partition->mod_usn) {
674                         modified_partition->mod_usn = ac->seq_num;
675                         if (ac->is_urgent) {
676                                 modified_partition->mod_usn_urgent = ac->seq_num;
677                         }
678                 }
679                 if (!ac->apply_mode) {
680                         replmd_private->originating_updates = true;
681                 }
682         }
683
684         if (ac->apply_mode) {
685                 ret = replmd_replicated_apply_isDeleted(ac);
686                 if (ret != LDB_SUCCESS) {
687                         return ldb_module_done(ac->req, NULL, NULL, ret);
688                 }
689                 return ret;
690         } else {
691                 /* free the partition control container here, for the
692                  * common path.  Other cases will have it cleaned up
693                  * eventually with the ares */
694                 talloc_free(partition_ctrl);
695                 return ldb_module_done(ac->req, controls,
696                                        ares->response, LDB_SUCCESS);
697         }
698 }
699
700
701 /*
702  * update a @REPLCHANGED record in each partition if there have been
703  * any writes of replicated data in the partition
704  */
705 static int replmd_notify_store(struct ldb_module *module, struct ldb_request *parent)
706 {
707         struct replmd_private *replmd_private =
708                 talloc_get_type(ldb_module_get_private(module), struct replmd_private);
709
710         while (replmd_private->ncs) {
711                 int ret;
712                 struct nc_entry *modified_partition = replmd_private->ncs;
713
714                 ret = dsdb_module_save_partition_usn(module, modified_partition->dn,
715                                                      modified_partition->mod_usn,
716                                                      modified_partition->mod_usn_urgent, parent);
717                 if (ret != LDB_SUCCESS) {
718                         DEBUG(0,(__location__ ": Failed to save partition uSN for %s\n",
719                                  ldb_dn_get_linearized(modified_partition->dn)));
720                         return ret;
721                 }
722
723                 if (ldb_dn_compare(modified_partition->dn,
724                                    replmd_private->schema_dn) == 0) {
725                         struct ldb_result *ext_res;
726                         ret = dsdb_module_extended(module,
727                                                    replmd_private->schema_dn,
728                                                    &ext_res,
729                                                    DSDB_EXTENDED_SCHEMA_UPDATE_NOW_OID,
730                                                    ext_res,
731                                                    DSDB_FLAG_NEXT_MODULE,
732                                                    parent);
733                         if (ret != LDB_SUCCESS) {
734                                 return ret;
735                         }
736                         talloc_free(ext_res);
737                 }
738
739                 DLIST_REMOVE(replmd_private->ncs, modified_partition);
740                 talloc_free(modified_partition);
741         }
742
743         return LDB_SUCCESS;
744 }
745
746
747 /*
748   created a replmd_replicated_request context
749  */
750 static struct replmd_replicated_request *replmd_ctx_init(struct ldb_module *module,
751                                                          struct ldb_request *req)
752 {
753         struct ldb_context *ldb;
754         struct replmd_replicated_request *ac;
755         const struct GUID *our_invocation_id;
756
757         ldb = ldb_module_get_ctx(module);
758
759         ac = talloc_zero(req, struct replmd_replicated_request);
760         if (ac == NULL) {
761                 ldb_oom(ldb);
762                 return NULL;
763         }
764
765         ac->module = module;
766         ac->req = req;
767
768         ac->schema = dsdb_get_schema(ldb, ac);
769         if (!ac->schema) {
770                 ldb_debug_set(ldb, LDB_DEBUG_FATAL,
771                               "replmd_modify: no dsdb_schema loaded");
772                 DEBUG(0,(__location__ ": %s\n", ldb_errstring(ldb)));
773                 talloc_free(ac);
774                 return NULL;
775         }
776
777         /* get our invocationId */
778         our_invocation_id = samdb_ntds_invocation_id(ldb);
779         if (!our_invocation_id) {
780                 ldb_debug_set(ldb, LDB_DEBUG_FATAL,
781                               "replmd_add: unable to find invocationId\n");
782                 talloc_free(ac);
783                 return NULL;
784         }
785         ac->our_invocation_id = *our_invocation_id;
786
787         return ac;
788 }
789
790 /*
791   add a time element to a record
792 */
793 static int add_time_element(struct ldb_message *msg, const char *attr, time_t t)
794 {
795         struct ldb_message_element *el;
796         char *s;
797         int ret;
798
799         if (ldb_msg_find_element(msg, attr) != NULL) {
800                 return LDB_SUCCESS;
801         }
802
803         s = ldb_timestring(msg, t);
804         if (s == NULL) {
805                 return LDB_ERR_OPERATIONS_ERROR;
806         }
807
808         ret = ldb_msg_add_string(msg, attr, s);
809         if (ret != LDB_SUCCESS) {
810                 return ret;
811         }
812
813         el = ldb_msg_find_element(msg, attr);
814         /* always set as replace. This works because on add ops, the flag
815            is ignored */
816         el->flags = LDB_FLAG_MOD_REPLACE;
817
818         return LDB_SUCCESS;
819 }
820
821 /*
822   add a uint64_t element to a record
823 */
824 static int add_uint64_element(struct ldb_context *ldb, struct ldb_message *msg,
825                               const char *attr, uint64_t v)
826 {
827         struct ldb_message_element *el;
828         int ret;
829
830         if (ldb_msg_find_element(msg, attr) != NULL) {
831                 return LDB_SUCCESS;
832         }
833
834         ret = samdb_msg_add_uint64(ldb, msg, msg, attr, v);
835         if (ret != LDB_SUCCESS) {
836                 return ret;
837         }
838
839         el = ldb_msg_find_element(msg, attr);
840         /* always set as replace. This works because on add ops, the flag
841            is ignored */
842         el->flags = LDB_FLAG_MOD_REPLACE;
843
844         return LDB_SUCCESS;
845 }
846
847 static int replmd_replPropertyMetaData1_attid_sort(const struct replPropertyMetaData1 *m1,
848                                                    const struct replPropertyMetaData1 *m2,
849                                                    const uint32_t *rdn_attid)
850 {
851         /*
852          * This assignment seems inoccous, but it is critical for the
853          * system, as we need to do the comparisons as a unsigned
854          * quantity, not signed (enums are signed integers)
855          */
856         uint32_t attid_1 = m1->attid;
857         uint32_t attid_2 = m2->attid;
858
859         if (attid_1 == attid_2) {
860                 return 0;
861         }
862
863         /*
864          * See above regarding this being an unsigned comparison.
865          * Otherwise when the high bit is set on non-standard
866          * attributes, they would end up first, before objectClass
867          * (0).
868          */
869         return attid_1 > attid_2 ? 1 : -1;
870 }
871
872 static int replmd_replPropertyMetaDataCtr1_verify(struct ldb_context *ldb,
873                                                   struct replPropertyMetaDataCtr1 *ctr1,
874                                                   struct ldb_dn *dn)
875 {
876         if (ctr1->count == 0) {
877                 ldb_debug_set(ldb, LDB_DEBUG_FATAL,
878                               "No elements found in replPropertyMetaData for %s!\n",
879                               ldb_dn_get_linearized(dn));
880                 return LDB_ERR_CONSTRAINT_VIOLATION;
881         }
882
883         /* the objectClass attribute is value 0x00000000, so must be first */
884         if (ctr1->array[0].attid != DRSUAPI_ATTID_objectClass) {
885                 ldb_debug_set(ldb, LDB_DEBUG_FATAL,
886                               "No objectClass found in replPropertyMetaData for %s!\n",
887                               ldb_dn_get_linearized(dn));
888                 return LDB_ERR_OBJECT_CLASS_VIOLATION;
889         }
890
891         return LDB_SUCCESS;
892 }
893
894 static int replmd_replPropertyMetaDataCtr1_sort_and_verify(struct ldb_context *ldb,
895                                                            struct replPropertyMetaDataCtr1 *ctr1,
896                                                            struct ldb_dn *dn)
897 {
898         /* Note this is O(n^2) for the almost-sorted case, which this is */
899         LDB_TYPESAFE_QSORT(ctr1->array, ctr1->count, NULL,
900                            replmd_replPropertyMetaData1_attid_sort);
901         return replmd_replPropertyMetaDataCtr1_verify(ldb, ctr1, dn);
902 }
903
904 static int replmd_ldb_message_element_attid_sort(const struct ldb_message_element *e1,
905                                                  const struct ldb_message_element *e2,
906                                                  const struct dsdb_schema *schema)
907 {
908         const struct dsdb_attribute *a1;
909         const struct dsdb_attribute *a2;
910
911         /*
912          * TODO: make this faster by caching the dsdb_attribute pointer
913          *       on the ldb_messag_element
914          */
915
916         a1 = dsdb_attribute_by_lDAPDisplayName(schema, e1->name);
917         a2 = dsdb_attribute_by_lDAPDisplayName(schema, e2->name);
918
919         /*
920          * TODO: remove this check, we should rely on e1 and e2 having valid attribute names
921          *       in the schema
922          */
923         if (!a1 || !a2) {
924                 return strcasecmp(e1->name, e2->name);
925         }
926         if (a1->attributeID_id == a2->attributeID_id) {
927                 return 0;
928         }
929         return a1->attributeID_id > a2->attributeID_id ? 1 : -1;
930 }
931
932 static void replmd_ldb_message_sort(struct ldb_message *msg,
933                                     const struct dsdb_schema *schema)
934 {
935         LDB_TYPESAFE_QSORT(msg->elements, msg->num_elements, schema, replmd_ldb_message_element_attid_sort);
936 }
937
938 static int replmd_build_la_val(TALLOC_CTX *mem_ctx, struct ldb_val *v, struct dsdb_dn *dsdb_dn,
939                                const struct GUID *invocation_id,
940                                uint64_t local_usn, NTTIME nttime);
941
942 static int parsed_dn_compare(struct parsed_dn *pdn1, struct parsed_dn *pdn2);
943
944 static int get_parsed_dns(struct ldb_module *module, TALLOC_CTX *mem_ctx,
945                           struct ldb_message_element *el, struct parsed_dn **pdn,
946                           const char *ldap_oid, struct ldb_request *parent);
947
948 static int check_parsed_dn_duplicates(struct ldb_module *module,
949                                       struct ldb_message_element *el,
950                                       struct parsed_dn *pdn);
951
952 /*
953   fix up linked attributes in replmd_add.
954   This involves setting up the right meta-data in extended DN
955   components, and creating backlinks to the object
956  */
957 static int replmd_add_fix_la(struct ldb_module *module, TALLOC_CTX *mem_ctx,
958                              struct replmd_private *replmd_private,
959                              struct ldb_message_element *el,
960                              struct replmd_replicated_request *ac,
961                              NTTIME now,
962                              struct ldb_dn *forward_dn,
963                              const struct dsdb_attribute *sa,
964                              struct ldb_request *parent)
965 {
966         unsigned int i;
967         TALLOC_CTX *tmp_ctx = talloc_new(mem_ctx);
968         struct ldb_context *ldb = ldb_module_get_ctx(module);
969         struct parsed_dn *pdn;
970         /* We will take a reference to the schema in replmd_add_backlink */
971         const struct dsdb_schema *schema = dsdb_get_schema(ldb, NULL);
972         struct ldb_val *new_values = NULL;
973         int ret;
974
975         if (dsdb_check_single_valued_link(sa, el) == LDB_SUCCESS) {
976                 el->flags |= LDB_FLAG_INTERNAL_DISABLE_SINGLE_VALUE_CHECK;
977         } else {
978                 ldb_asprintf_errstring(ldb,
979                                        "Attribute %s is single valued but "
980                                        "more than one value has been supplied",
981                                        el->name);
982                 talloc_free(tmp_ctx);
983                 return LDB_ERR_CONSTRAINT_VIOLATION;
984         }
985         
986         ret = get_parsed_dns(module, tmp_ctx, el, &pdn,
987                              sa->syntax->ldap_oid, parent);
988         if (ret != LDB_SUCCESS) {
989                 talloc_free(tmp_ctx);
990                 return ret;
991         }
992
993         ret = check_parsed_dn_duplicates(module, el, pdn);
994         if (ret != LDB_SUCCESS) {
995                 talloc_free(tmp_ctx);
996                 return ret;
997         }
998
999         new_values = talloc_array(tmp_ctx, struct ldb_val, el->num_values);
1000         if (new_values == NULL) {
1001                 ldb_module_oom(module);
1002                 talloc_free(tmp_ctx);
1003                 return LDB_ERR_OPERATIONS_ERROR;
1004         }
1005
1006         for (i = 0; i < el->num_values; i++) {
1007                 struct parsed_dn *p = &pdn[i];
1008                 ret = replmd_build_la_val(el->values, p->v, p->dsdb_dn,
1009                                           &ac->our_invocation_id,
1010                                           ac->seq_num, now);
1011                 if (ret != LDB_SUCCESS) {
1012                         talloc_free(tmp_ctx);
1013                         return ret;
1014                 }
1015
1016                 ret = replmd_defer_add_backlink(module, replmd_private,
1017                                                 schema, ac,
1018                                                 forward_dn, &p->guid, true, sa,
1019                                                 parent);
1020                 if (ret != LDB_SUCCESS) {
1021                         talloc_free(tmp_ctx);
1022                         return ret;
1023                 }
1024
1025                 new_values[i] = *p->v;
1026         }
1027         el->values = talloc_steal(mem_ctx, new_values);
1028
1029         talloc_free(tmp_ctx);
1030         return LDB_SUCCESS;
1031 }
1032
1033 static int replmd_add_make_extended_dn(struct ldb_request *req,
1034                                        const DATA_BLOB *guid_blob,
1035                                        struct ldb_dn **_extended_dn)
1036 {
1037         int ret;
1038         const DATA_BLOB *sid_blob;
1039         /* Calculate an extended DN for any linked attributes */
1040         struct ldb_dn *extended_dn = ldb_dn_copy(req, req->op.add.message->dn);
1041         if (!extended_dn) {
1042                 return LDB_ERR_OPERATIONS_ERROR;
1043         }
1044         ret = ldb_dn_set_extended_component(extended_dn, "GUID", guid_blob);
1045         if (ret != LDB_SUCCESS) {
1046                 return ret;
1047         }
1048
1049         sid_blob = ldb_msg_find_ldb_val(req->op.add.message, "objectSID");
1050         if (sid_blob != NULL) {
1051                 ret = ldb_dn_set_extended_component(extended_dn, "SID", sid_blob);
1052                 if (ret != LDB_SUCCESS) {
1053                         return ret;
1054                 }
1055         }
1056         *_extended_dn = extended_dn;
1057         return LDB_SUCCESS;
1058 }
1059
1060 /*
1061   intercept add requests
1062  */
1063 static int replmd_add(struct ldb_module *module, struct ldb_request *req)
1064 {
1065         struct ldb_context *ldb;
1066         struct ldb_control *control;
1067         struct replmd_replicated_request *ac;
1068         enum ndr_err_code ndr_err;
1069         struct ldb_request *down_req;
1070         struct ldb_message *msg;
1071         const DATA_BLOB *guid_blob;
1072         DATA_BLOB guid_blob_stack;
1073         struct GUID guid;
1074         uint8_t guid_data[16];
1075         struct replPropertyMetaDataBlob nmd;
1076         struct ldb_val nmd_value;
1077         struct ldb_dn *extended_dn = NULL;
1078         
1079         /*
1080          * The use of a time_t here seems odd, but as the NTTIME
1081          * elements are actually declared as NTTIME_1sec in the IDL,
1082          * getting a higher resolution timestamp is not required.
1083          */
1084         time_t t = time(NULL);
1085         NTTIME now;
1086         char *time_str;
1087         int ret;
1088         unsigned int i;
1089         unsigned int functional_level;
1090         uint32_t ni=0;
1091         bool allow_add_guid = false;
1092         bool remove_current_guid = false;
1093         bool is_urgent = false;
1094         bool is_schema_nc = false;
1095         struct ldb_message_element *objectclass_el;
1096         struct replmd_private *replmd_private =
1097                 talloc_get_type_abort(ldb_module_get_private(module), struct replmd_private);
1098
1099         /* check if there's a show relax control (used by provision to say 'I know what I'm doing') */
1100         control = ldb_request_get_control(req, LDB_CONTROL_RELAX_OID);
1101         if (control) {
1102                 allow_add_guid = true;
1103         }
1104
1105         /* do not manipulate our control entries */
1106         if (ldb_dn_is_special(req->op.add.message->dn)) {
1107                 return ldb_next_request(module, req);
1108         }
1109
1110         ldb = ldb_module_get_ctx(module);
1111
1112         ldb_debug(ldb, LDB_DEBUG_TRACE, "replmd_add\n");
1113
1114         guid_blob = ldb_msg_find_ldb_val(req->op.add.message, "objectGUID");
1115         if (guid_blob != NULL) {
1116                 if (!allow_add_guid) {
1117                         ldb_set_errstring(ldb,
1118                                           "replmd_add: it's not allowed to add an object with objectGUID!");
1119                         return LDB_ERR_UNWILLING_TO_PERFORM;
1120                 } else {
1121                         NTSTATUS status = GUID_from_data_blob(guid_blob,&guid);
1122                         if (!NT_STATUS_IS_OK(status)) {
1123                                 ldb_set_errstring(ldb,
1124                                                   "replmd_add: Unable to parse the 'objectGUID' as a GUID!");
1125                                 return LDB_ERR_UNWILLING_TO_PERFORM;
1126                         }
1127                         /* we remove this attribute as it can be a string and
1128                          * will not be treated correctly and then we will re-add
1129                          * it later on in the good format */
1130                         remove_current_guid = true;
1131                 }
1132         } else {
1133                 /* a new GUID */
1134                 guid = GUID_random();
1135                 
1136                 guid_blob_stack = data_blob_const(guid_data, sizeof(guid_data));
1137                 
1138                 /* This can't fail */
1139                 ndr_push_struct_into_fixed_blob(&guid_blob_stack, &guid,
1140                                                 (ndr_push_flags_fn_t)ndr_push_GUID);
1141                 guid_blob = &guid_blob_stack;
1142         }
1143
1144         ac = replmd_ctx_init(module, req);
1145         if (ac == NULL) {
1146                 return ldb_module_oom(module);
1147         }
1148
1149         functional_level = dsdb_functional_level(ldb);
1150
1151         /* Get a sequence number from the backend */
1152         ret = ldb_sequence_number(ldb, LDB_SEQ_NEXT, &ac->seq_num);
1153         if (ret != LDB_SUCCESS) {
1154                 talloc_free(ac);
1155                 return ret;
1156         }
1157
1158         /* we have to copy the message as the caller might have it as a const */
1159         msg = ldb_msg_copy_shallow(ac, req->op.add.message);
1160         if (msg == NULL) {
1161                 ldb_oom(ldb);
1162                 talloc_free(ac);
1163                 return LDB_ERR_OPERATIONS_ERROR;
1164         }
1165
1166         /* generated times */
1167         unix_to_nt_time(&now, t);
1168         time_str = ldb_timestring(msg, t);
1169         if (!time_str) {
1170                 ldb_oom(ldb);
1171                 talloc_free(ac);
1172                 return LDB_ERR_OPERATIONS_ERROR;
1173         }
1174         if (remove_current_guid) {
1175                 ldb_msg_remove_attr(msg,"objectGUID");
1176         }
1177
1178         /*
1179          * remove autogenerated attributes
1180          */
1181         ldb_msg_remove_attr(msg, "whenCreated");
1182         ldb_msg_remove_attr(msg, "whenChanged");
1183         ldb_msg_remove_attr(msg, "uSNCreated");
1184         ldb_msg_remove_attr(msg, "uSNChanged");
1185         ldb_msg_remove_attr(msg, "replPropertyMetaData");
1186
1187         /*
1188          * readd replicated attributes
1189          */
1190         ret = ldb_msg_add_string(msg, "whenCreated", time_str);
1191         if (ret != LDB_SUCCESS) {
1192                 ldb_oom(ldb);
1193                 talloc_free(ac);
1194                 return ret;
1195         }
1196
1197         /* build the replication meta_data */
1198         ZERO_STRUCT(nmd);
1199         nmd.version             = 1;
1200         nmd.ctr.ctr1.count      = msg->num_elements;
1201         nmd.ctr.ctr1.array      = talloc_array(msg,
1202                                                struct replPropertyMetaData1,
1203                                                nmd.ctr.ctr1.count);
1204         if (!nmd.ctr.ctr1.array) {
1205                 ldb_oom(ldb);
1206                 talloc_free(ac);
1207                 return LDB_ERR_OPERATIONS_ERROR;
1208         }
1209
1210         is_schema_nc = ldb_dn_compare_base(replmd_private->schema_dn, msg->dn) == 0;
1211
1212         for (i=0; i < msg->num_elements;) {
1213                 struct ldb_message_element *e = &msg->elements[i];
1214                 struct replPropertyMetaData1 *m = &nmd.ctr.ctr1.array[ni];
1215                 const struct dsdb_attribute *sa;
1216
1217                 if (e->name[0] == '@') {
1218                         i++;
1219                         continue;
1220                 }
1221
1222                 sa = dsdb_attribute_by_lDAPDisplayName(ac->schema, e->name);
1223                 if (!sa) {
1224                         ldb_debug_set(ldb, LDB_DEBUG_ERROR,
1225                                       "replmd_add: attribute '%s' not defined in schema\n",
1226                                       e->name);
1227                         talloc_free(ac);
1228                         return LDB_ERR_NO_SUCH_ATTRIBUTE;
1229                 }
1230
1231                 if ((sa->systemFlags & DS_FLAG_ATTR_NOT_REPLICATED) || (sa->systemFlags & DS_FLAG_ATTR_IS_CONSTRUCTED)) {
1232                         /* if the attribute is not replicated (0x00000001)
1233                          * or constructed (0x00000004) it has no metadata
1234                          */
1235                         i++;
1236                         continue;
1237                 }
1238
1239                 if (sa->linkID != 0 && functional_level > DS_DOMAIN_FUNCTION_2000) {
1240                         if (extended_dn == NULL) {
1241                                 ret = replmd_add_make_extended_dn(req,
1242                                                                   guid_blob,
1243                                                                   &extended_dn);
1244                                 if (ret != LDB_SUCCESS) {
1245                                         talloc_free(ac);
1246                                         return ret;
1247                                 }
1248                         }                       
1249
1250                         /*
1251                          * Prepare the context for the backlinks and
1252                          * create metadata for the forward links.  The
1253                          * backlinks are created in
1254                          * replmd_op_callback() after the successful
1255                          * ADD of the object.
1256                          */
1257                         ret = replmd_add_fix_la(module, msg->elements,
1258                                                 replmd_private, e,
1259                                                 ac, now,
1260                                                 extended_dn,
1261                                                 sa, req);
1262                         if (ret != LDB_SUCCESS) {
1263                                 talloc_free(ac);
1264                                 return ret;
1265                         }
1266                         /* linked attributes are not stored in
1267                            replPropertyMetaData in FL above w2k */
1268                         i++;
1269                         continue;
1270                 }
1271
1272                 m->attid   = dsdb_attribute_get_attid(sa, is_schema_nc);
1273                 m->version = 1;
1274                 if (m->attid == DRSUAPI_ATTID_isDeleted) {
1275                         const struct ldb_val *rdn_val = ldb_dn_get_rdn_val(msg->dn);
1276                         const char* rdn;
1277
1278                         if (rdn_val == NULL) {
1279                                 ldb_oom(ldb);
1280                                 talloc_free(ac);
1281                                 return LDB_ERR_OPERATIONS_ERROR;
1282                         }
1283
1284                         rdn = (const char*)rdn_val->data;
1285                         if (strcmp(rdn, "Deleted Objects") == 0) {
1286                                 /*
1287                                  * Set the originating_change_time to 29/12/9999 at 23:59:59
1288                                  * as specified in MS-ADTS 7.1.1.4.2 Deleted Objects Container
1289                                  */
1290                                 m->originating_change_time      = DELETED_OBJECT_CONTAINER_CHANGE_TIME;
1291                         } else {
1292                                 m->originating_change_time      = now;
1293                         }
1294                 } else {
1295                         m->originating_change_time      = now;
1296                 }
1297                 m->originating_invocation_id    = ac->our_invocation_id;
1298                 m->originating_usn              = ac->seq_num;
1299                 m->local_usn                    = ac->seq_num;
1300                 ni++;
1301
1302                 if (!(e->flags & DSDB_FLAG_INTERNAL_FORCE_META_DATA)) {
1303                         i++;
1304                         continue;
1305                 }
1306
1307                 e->flags &= ~DSDB_FLAG_INTERNAL_FORCE_META_DATA;
1308
1309                 if (e->num_values != 0) {
1310                         i++;
1311                         continue;
1312                 }
1313
1314                 ldb_msg_remove_element(msg, e);
1315         }
1316
1317         /* fix meta data count */
1318         nmd.ctr.ctr1.count = ni;
1319
1320         /*
1321          * sort meta data array
1322          */
1323         ret = replmd_replPropertyMetaDataCtr1_sort_and_verify(ldb, &nmd.ctr.ctr1, msg->dn);
1324         if (ret != LDB_SUCCESS) {
1325                 ldb_asprintf_errstring(ldb, "%s: error during direct ADD: %s", __func__, ldb_errstring(ldb));
1326                 talloc_free(ac);
1327                 return ret;
1328         }
1329
1330         /* generated NDR encoded values */
1331         ndr_err = ndr_push_struct_blob(&nmd_value, msg,
1332                                        &nmd,
1333                                        (ndr_push_flags_fn_t)ndr_push_replPropertyMetaDataBlob);
1334         if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
1335                 ldb_oom(ldb);
1336                 talloc_free(ac);
1337                 return LDB_ERR_OPERATIONS_ERROR;
1338         }
1339
1340         /*
1341          * add the autogenerated values
1342          */
1343         ret = dsdb_msg_add_guid(msg, &guid, "objectGUID");
1344         if (ret != LDB_SUCCESS) {
1345                 ldb_oom(ldb);
1346                 talloc_free(ac);
1347                 return ret;
1348         }
1349         ret = ldb_msg_add_string(msg, "whenChanged", time_str);
1350         if (ret != LDB_SUCCESS) {
1351                 ldb_oom(ldb);
1352                 talloc_free(ac);
1353                 return ret;
1354         }
1355         ret = samdb_msg_add_uint64(ldb, msg, msg, "uSNCreated", ac->seq_num);
1356         if (ret != LDB_SUCCESS) {
1357                 ldb_oom(ldb);
1358                 talloc_free(ac);
1359                 return ret;
1360         }
1361         ret = samdb_msg_add_uint64(ldb, msg, msg, "uSNChanged", ac->seq_num);
1362         if (ret != LDB_SUCCESS) {
1363                 ldb_oom(ldb);
1364                 talloc_free(ac);
1365                 return ret;
1366         }
1367         ret = ldb_msg_add_value(msg, "replPropertyMetaData", &nmd_value, NULL);
1368         if (ret != LDB_SUCCESS) {
1369                 ldb_oom(ldb);
1370                 talloc_free(ac);
1371                 return ret;
1372         }
1373
1374         /*
1375          * sort the attributes by attid before storing the object
1376          */
1377         replmd_ldb_message_sort(msg, ac->schema);
1378
1379         /*
1380          * Assert that we do have an objectClass
1381          */
1382         objectclass_el = ldb_msg_find_element(msg, "objectClass");
1383         if (objectclass_el == NULL) {
1384                 ldb_asprintf_errstring(ldb, __location__
1385                                        ": objectClass missing on %s\n",
1386                                        ldb_dn_get_linearized(msg->dn));
1387                 talloc_free(ac);
1388                 return LDB_ERR_OBJECT_CLASS_VIOLATION;
1389         }
1390         is_urgent = replmd_check_urgent_objectclass(objectclass_el,
1391                                                         REPL_URGENT_ON_CREATE);
1392
1393         ac->is_urgent = is_urgent;
1394         ret = ldb_build_add_req(&down_req, ldb, ac,
1395                                 msg,
1396                                 req->controls,
1397                                 ac, replmd_op_callback,
1398                                 req);
1399
1400         LDB_REQ_SET_LOCATION(down_req);
1401         if (ret != LDB_SUCCESS) {
1402                 talloc_free(ac);
1403                 return ret;
1404         }
1405
1406         /* current partition control is needed by "replmd_op_callback" */
1407         if (ldb_request_get_control(req, DSDB_CONTROL_CURRENT_PARTITION_OID) == NULL) {
1408                 ret = ldb_request_add_control(down_req,
1409                                               DSDB_CONTROL_CURRENT_PARTITION_OID,
1410                                               false, NULL);
1411                 if (ret != LDB_SUCCESS) {
1412                         talloc_free(ac);
1413                         return ret;
1414                 }
1415         }
1416
1417         if (functional_level == DS_DOMAIN_FUNCTION_2000) {
1418                 ret = ldb_request_add_control(down_req, DSDB_CONTROL_APPLY_LINKS, false, NULL);
1419                 if (ret != LDB_SUCCESS) {
1420                         talloc_free(ac);
1421                         return ret;
1422                 }
1423         }
1424
1425         /* mark the control done */
1426         if (control) {
1427                 control->critical = 0;
1428         }
1429         /* go on with the call chain */
1430         return ldb_next_request(module, down_req);
1431 }
1432
1433
1434 /*
1435  * update the replPropertyMetaData for one element
1436  */
1437 static int replmd_update_rpmd_element(struct ldb_context *ldb,
1438                                       struct ldb_message *msg,
1439                                       struct ldb_message_element *el,
1440                                       struct ldb_message_element *old_el,
1441                                       struct replPropertyMetaDataBlob *omd,
1442                                       const struct dsdb_schema *schema,
1443                                       uint64_t *seq_num,
1444                                       const struct GUID *our_invocation_id,
1445                                       NTTIME now,
1446                                       bool is_schema_nc,
1447                                       bool is_forced_rodc,
1448                                       struct ldb_request *req)
1449 {
1450         uint32_t i;
1451         const struct dsdb_attribute *a;
1452         struct replPropertyMetaData1 *md1;
1453         bool may_skip = false;
1454         uint32_t attid;
1455
1456         a = dsdb_attribute_by_lDAPDisplayName(schema, el->name);
1457         if (a == NULL) {
1458                 if (ldb_request_get_control(req, LDB_CONTROL_RELAX_OID)) {
1459                         /* allow this to make it possible for dbcheck
1460                            to remove bad attributes */
1461                         return LDB_SUCCESS;
1462                 }
1463
1464                 DEBUG(0,(__location__ ": Unable to find attribute %s in schema\n",
1465                          el->name));
1466                 return LDB_ERR_OPERATIONS_ERROR;
1467         }
1468
1469         attid = dsdb_attribute_get_attid(a, is_schema_nc);
1470
1471         if ((a->systemFlags & DS_FLAG_ATTR_NOT_REPLICATED) || (a->systemFlags & DS_FLAG_ATTR_IS_CONSTRUCTED)) {
1472                 return LDB_SUCCESS;
1473         }
1474
1475         /*
1476          * if the attribute's value haven't changed, and this isn't
1477          * just a delete of everything then return LDB_SUCCESS Unless
1478          * we have the provision control or if the attribute is
1479          * interSiteTopologyGenerator as this page explain:
1480          * http://support.microsoft.com/kb/224815 this attribute is
1481          * periodicaly written by the DC responsible for the intersite
1482          * generation in a given site
1483          *
1484          * Unchanged could be deleting or replacing an already-gone
1485          * thing with an unconstrained delete/empty replace or a
1486          * replace with the same value, but not an add with the same
1487          * value because that could be about adding a duplicate (which
1488          * is for someone else to error out on).
1489          */
1490         if (old_el != NULL && ldb_msg_element_equal_ordered(el, old_el)) {
1491                 if (LDB_FLAG_MOD_TYPE(el->flags) == LDB_FLAG_MOD_REPLACE) {
1492                         may_skip = true;
1493                 }
1494         } else if (old_el == NULL && el->num_values == 0) {
1495                 if (LDB_FLAG_MOD_TYPE(el->flags) == LDB_FLAG_MOD_REPLACE) {
1496                         may_skip = true;
1497                 } else if (LDB_FLAG_MOD_TYPE(el->flags) == LDB_FLAG_MOD_DELETE) {
1498                         may_skip = true;
1499                 }
1500         } else if (a->linkID != 0 && LDB_FLAG_MOD_TYPE(el->flags) == LDB_FLAG_MOD_DELETE &&
1501                    ldb_request_get_control(req, DSDB_CONTROL_REPLMD_VANISH_LINKS) != NULL) {
1502                 /*
1503                  * We intentionally skip the version bump when attempting to
1504                  * vanish links.
1505                  *
1506                  * The control is set by dbcheck and expunge-tombstones which
1507                  * both attempt to be non-replicating. Otherwise, making an
1508                  * alteration to the replication state would trigger a
1509                  * broadcast of all expunged objects.
1510                  */
1511                 may_skip = true;
1512         }
1513
1514         if (el->flags & DSDB_FLAG_INTERNAL_FORCE_META_DATA) {
1515                 may_skip = false;
1516                 el->flags &= ~DSDB_FLAG_INTERNAL_FORCE_META_DATA;
1517         }
1518
1519         if (may_skip) {
1520                 if (strcmp(el->name, "interSiteTopologyGenerator") != 0 &&
1521                     !ldb_request_get_control(req, LDB_CONTROL_PROVISION_OID)) {
1522                         /*
1523                          * allow this to make it possible for dbcheck
1524                          * to rebuild broken metadata
1525                          */
1526                         return LDB_SUCCESS;
1527                 }
1528         }
1529
1530         for (i=0; i<omd->ctr.ctr1.count; i++) {
1531                 /*
1532                  * First check if we find it under the msDS-IntID,
1533                  * then check if we find it under the OID and
1534                  * prefixMap ID.
1535                  *
1536                  * This allows the administrator to simply re-write
1537                  * the attributes and so restore replication, which is
1538                  * likely what they will try to do.
1539                  */
1540                 if (attid == omd->ctr.ctr1.array[i].attid) {
1541                         break;
1542                 }
1543
1544                 if (a->attributeID_id == omd->ctr.ctr1.array[i].attid) {
1545                         break;
1546                 }
1547         }
1548
1549         if (a->linkID != 0 && dsdb_functional_level(ldb) > DS_DOMAIN_FUNCTION_2000) {
1550                 /* linked attributes are not stored in
1551                    replPropertyMetaData in FL above w2k, but we do
1552                    raise the seqnum for the object  */
1553                 if (*seq_num == 0 &&
1554                     ldb_sequence_number(ldb, LDB_SEQ_NEXT, seq_num) != LDB_SUCCESS) {
1555                         return LDB_ERR_OPERATIONS_ERROR;
1556                 }
1557                 return LDB_SUCCESS;
1558         }
1559
1560         if (i == omd->ctr.ctr1.count) {
1561                 /* we need to add a new one */
1562                 omd->ctr.ctr1.array = talloc_realloc(msg, omd->ctr.ctr1.array,
1563                                                      struct replPropertyMetaData1, omd->ctr.ctr1.count+1);
1564                 if (omd->ctr.ctr1.array == NULL) {
1565                         ldb_oom(ldb);
1566                         return LDB_ERR_OPERATIONS_ERROR;
1567                 }
1568                 omd->ctr.ctr1.count++;
1569                 ZERO_STRUCT(omd->ctr.ctr1.array[i]);
1570         }
1571
1572         /* Get a new sequence number from the backend. We only do this
1573          * if we have a change that requires a new
1574          * replPropertyMetaData element
1575          */
1576         if (*seq_num == 0) {
1577                 int ret = ldb_sequence_number(ldb, LDB_SEQ_NEXT, seq_num);
1578                 if (ret != LDB_SUCCESS) {
1579                         return LDB_ERR_OPERATIONS_ERROR;
1580                 }
1581         }
1582
1583         md1 = &omd->ctr.ctr1.array[i];
1584         md1->version++;
1585         md1->attid = attid;
1586
1587         if (md1->attid == DRSUAPI_ATTID_isDeleted) {
1588                 const struct ldb_val *rdn_val = ldb_dn_get_rdn_val(msg->dn);
1589                 const char* rdn;
1590
1591                 if (rdn_val == NULL) {
1592                         ldb_oom(ldb);
1593                         return LDB_ERR_OPERATIONS_ERROR;
1594                 }
1595
1596                 rdn = (const char*)rdn_val->data;
1597                 if (strcmp(rdn, "Deleted Objects") == 0) {
1598                         /*
1599                          * Set the originating_change_time to 29/12/9999 at 23:59:59
1600                          * as specified in MS-ADTS 7.1.1.4.2 Deleted Objects Container
1601                          */
1602                         md1->originating_change_time    = DELETED_OBJECT_CONTAINER_CHANGE_TIME;
1603                 } else {
1604                         md1->originating_change_time    = now;
1605                 }
1606         } else {
1607                 md1->originating_change_time    = now;
1608         }
1609         md1->originating_invocation_id = *our_invocation_id;
1610         md1->originating_usn           = *seq_num;
1611         md1->local_usn                 = *seq_num;
1612
1613         if (is_forced_rodc) {
1614                 /* Force version to 0 to be overriden later via replication */
1615                 md1->version = 0;
1616         }
1617
1618         return LDB_SUCCESS;
1619 }
1620
1621 /*
1622  * Bump the replPropertyMetaData version on an attribute, and if it
1623  * has changed (or forced by leaving rdn_old NULL), update the value
1624  * in the entry.
1625  *
1626  * This is important, as calling a modify operation may not change the
1627  * version number if the values appear unchanged, but a rename between
1628  * parents bumps this value.
1629  *
1630  */
1631 static int replmd_update_rpmd_rdn_attr(struct ldb_context *ldb,
1632                                        struct ldb_message *msg,
1633                                        const struct ldb_val *rdn_new,
1634                                        const struct ldb_val *rdn_old,
1635                                        struct replPropertyMetaDataBlob *omd,
1636                                        struct replmd_replicated_request *ar,
1637                                        NTTIME now,
1638                                        bool is_schema_nc,
1639                                        bool is_forced_rodc)
1640 {
1641         const char *rdn_name = ldb_dn_get_rdn_name(msg->dn);
1642         const struct dsdb_attribute *rdn_attr =
1643                 dsdb_attribute_by_lDAPDisplayName(ar->schema, rdn_name);
1644         const char *attr_name = rdn_attr != NULL ?
1645                                 rdn_attr->lDAPDisplayName :
1646                                 rdn_name;
1647         struct ldb_message_element new_el = {
1648                 .flags = LDB_FLAG_MOD_REPLACE,
1649                 .name = attr_name,
1650                 .num_values = 1,
1651                 .values = discard_const_p(struct ldb_val, rdn_new)
1652         };
1653         struct ldb_message_element old_el = {
1654                 .flags = LDB_FLAG_MOD_REPLACE,
1655                 .name = attr_name,
1656                 .num_values = rdn_old ? 1 : 0,
1657                 .values = discard_const_p(struct ldb_val, rdn_old)
1658         };
1659
1660         if (ldb_msg_element_equal_ordered(&new_el, &old_el) == false) {
1661                 int ret = ldb_msg_add(msg, &new_el, LDB_FLAG_MOD_REPLACE);
1662                 if (ret != LDB_SUCCESS) {
1663                         return ldb_oom(ldb);
1664                 }
1665         }
1666
1667         return replmd_update_rpmd_element(ldb, msg, &new_el, NULL,
1668                                           omd, ar->schema, &ar->seq_num,
1669                                           &ar->our_invocation_id,
1670                                           now, is_schema_nc, is_forced_rodc,
1671                                           ar->req);
1672
1673 }
1674
1675 static uint64_t find_max_local_usn(struct replPropertyMetaDataBlob omd)
1676 {
1677         uint32_t count = omd.ctr.ctr1.count;
1678         uint64_t max = 0;
1679         uint32_t i;
1680         for (i=0; i < count; i++) {
1681                 struct replPropertyMetaData1 m = omd.ctr.ctr1.array[i];
1682                 if (max < m.local_usn) {
1683                         max = m.local_usn;
1684                 }
1685         }
1686         return max;
1687 }
1688
1689 /*
1690  * update the replPropertyMetaData object each time we modify an
1691  * object. This is needed for DRS replication, as the merge on the
1692  * client is based on this object
1693  */
1694 static int replmd_update_rpmd(struct ldb_module *module,
1695                               const struct dsdb_schema *schema,
1696                               struct ldb_request *req,
1697                               const char * const *rename_attrs,
1698                               struct ldb_message *msg, uint64_t *seq_num,
1699                               time_t t, bool is_schema_nc,
1700                               bool *is_urgent, bool *rodc)
1701 {
1702         const struct ldb_val *omd_value;
1703         enum ndr_err_code ndr_err;
1704         struct replPropertyMetaDataBlob omd;
1705         unsigned int i;
1706         NTTIME now;
1707         const struct GUID *our_invocation_id;
1708         int ret;
1709         const char * const *attrs = NULL;
1710         const char * const attrs2[] = { "uSNChanged", "objectClass", "instanceType", NULL };
1711         struct ldb_result *res;
1712         struct ldb_context *ldb;
1713         struct ldb_message_element *objectclass_el;
1714         enum urgent_situation situation;
1715         bool rmd_is_provided;
1716         bool rmd_is_just_resorted = false;
1717         const char *not_rename_attrs[4 + msg->num_elements];
1718         bool is_forced_rodc = false;
1719
1720         if (rename_attrs) {
1721                 attrs = rename_attrs;
1722         } else {
1723                 for (i = 0; i < msg->num_elements; i++) {
1724                         not_rename_attrs[i] = msg->elements[i].name;
1725                 }
1726                 not_rename_attrs[i] = "replPropertyMetaData";
1727                 not_rename_attrs[i+1] = "objectClass";
1728                 not_rename_attrs[i+2] = "instanceType";
1729                 not_rename_attrs[i+3] = NULL;
1730                 attrs = not_rename_attrs;
1731         }
1732
1733         ldb = ldb_module_get_ctx(module);
1734
1735         ret = samdb_rodc(ldb, rodc);
1736         if (ret != LDB_SUCCESS) {
1737                 DEBUG(4, (__location__ ": unable to tell if we are an RODC\n"));
1738                 *rodc = false;
1739         }
1740
1741         if (*rodc &&
1742             ldb_request_get_control(req, DSDB_CONTROL_FORCE_RODC_LOCAL_CHANGE)) {
1743                 is_forced_rodc = true;
1744         }
1745
1746         our_invocation_id = samdb_ntds_invocation_id(ldb);
1747         if (!our_invocation_id) {
1748                 /* this happens during an initial vampire while
1749                    updating the schema */
1750                 DEBUG(5,("No invocationID - skipping replPropertyMetaData update\n"));
1751                 return LDB_SUCCESS;
1752         }
1753
1754         unix_to_nt_time(&now, t);
1755
1756         if (ldb_request_get_control(req, DSDB_CONTROL_CHANGEREPLMETADATA_OID)) {
1757                 rmd_is_provided = true;
1758                 if (ldb_request_get_control(req, DSDB_CONTROL_CHANGEREPLMETADATA_RESORT_OID)) {
1759                         rmd_is_just_resorted = true;
1760                 }
1761         } else {
1762                 rmd_is_provided = false;
1763         }
1764
1765         /* if isDeleted is present and is TRUE, then we consider we are deleting,
1766          * otherwise we consider we are updating */
1767         if (ldb_msg_check_string_attribute(msg, "isDeleted", "TRUE")) {
1768                 situation = REPL_URGENT_ON_DELETE;
1769         } else if (rename_attrs) {
1770                 situation = REPL_URGENT_ON_CREATE | REPL_URGENT_ON_DELETE;
1771         } else {
1772                 situation = REPL_URGENT_ON_UPDATE;
1773         }
1774
1775         if (rmd_is_provided) {
1776                 /* In this case the change_replmetadata control was supplied */
1777                 /* We check that it's the only attribute that is provided
1778                  * (it's a rare case so it's better to keep the code simplier)
1779                  * We also check that the highest local_usn is bigger or the same as
1780                  * uSNChanged. */
1781                 uint64_t db_seq;
1782                 if( msg->num_elements != 1 ||
1783                         strncmp(msg->elements[0].name,
1784                                 "replPropertyMetaData", 20) ) {
1785                         DEBUG(0,(__location__ ": changereplmetada control called without "\
1786                                 "a specified replPropertyMetaData attribute or with others\n"));
1787                         return LDB_ERR_OPERATIONS_ERROR;
1788                 }
1789                 if (situation != REPL_URGENT_ON_UPDATE) {
1790                         DEBUG(0,(__location__ ": changereplmetada control can't be called when deleting an object\n"));
1791                         return LDB_ERR_OPERATIONS_ERROR;
1792                 }
1793                 omd_value = ldb_msg_find_ldb_val(msg, "replPropertyMetaData");
1794                 if (!omd_value) {
1795                         DEBUG(0,(__location__ ": replPropertyMetaData was not specified for Object %s\n",
1796                                  ldb_dn_get_linearized(msg->dn)));
1797                         return LDB_ERR_OPERATIONS_ERROR;
1798                 }
1799                 ndr_err = ndr_pull_struct_blob(omd_value, msg, &omd,
1800                                                (ndr_pull_flags_fn_t)ndr_pull_replPropertyMetaDataBlob);
1801                 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
1802                         DEBUG(0,(__location__ ": Failed to parse replPropertyMetaData for %s\n",
1803                                  ldb_dn_get_linearized(msg->dn)));
1804                         return LDB_ERR_OPERATIONS_ERROR;
1805                 }
1806
1807                 ret = dsdb_module_search_dn(module, msg, &res, msg->dn, attrs2,
1808                                             DSDB_FLAG_NEXT_MODULE |
1809                                             DSDB_SEARCH_SHOW_RECYCLED |
1810                                             DSDB_SEARCH_SHOW_EXTENDED_DN |
1811                                             DSDB_SEARCH_SHOW_DN_IN_STORAGE_FORMAT |
1812                                             DSDB_SEARCH_REVEAL_INTERNALS, req);
1813
1814                 if (ret != LDB_SUCCESS) {
1815                         return ret;
1816                 }
1817
1818                 if (rmd_is_just_resorted == false) {
1819                         *seq_num = find_max_local_usn(omd);
1820
1821                         db_seq = ldb_msg_find_attr_as_uint64(res->msgs[0], "uSNChanged", 0);
1822
1823                         /*
1824                          * The test here now allows for a new
1825                          * replPropertyMetaData with no change, if was
1826                          * just dbcheck re-sorting the values.
1827                          */
1828                         if (*seq_num <= db_seq) {
1829                                 DEBUG(0,(__location__ ": changereplmetada control provided but max(local_usn)" \
1830                                          " is less than uSNChanged (max = %lld uSNChanged = %lld)\n",
1831                                          (long long)*seq_num, (long long)db_seq));
1832                                 return LDB_ERR_OPERATIONS_ERROR;
1833                         }
1834                 }
1835
1836         } else {
1837                 /* search for the existing replPropertyMetaDataBlob. We need
1838                  * to use REVEAL and ask for DNs in storage format to support
1839                  * the check for values being the same in
1840                  * replmd_update_rpmd_element()
1841                  */
1842                 ret = dsdb_module_search_dn(module, msg, &res, msg->dn, attrs,
1843                                             DSDB_FLAG_NEXT_MODULE |
1844                                             DSDB_SEARCH_SHOW_RECYCLED |
1845                                             DSDB_SEARCH_SHOW_EXTENDED_DN |
1846                                             DSDB_SEARCH_SHOW_DN_IN_STORAGE_FORMAT |
1847                                             DSDB_SEARCH_REVEAL_INTERNALS, req);
1848                 if (ret != LDB_SUCCESS) {
1849                         return ret;
1850                 }
1851
1852                 omd_value = ldb_msg_find_ldb_val(res->msgs[0], "replPropertyMetaData");
1853                 if (!omd_value) {
1854                         DEBUG(0,(__location__ ": Object %s does not have a replPropertyMetaData attribute\n",
1855                                  ldb_dn_get_linearized(msg->dn)));
1856                         return LDB_ERR_OPERATIONS_ERROR;
1857                 }
1858
1859                 ndr_err = ndr_pull_struct_blob(omd_value, msg, &omd,
1860                                                (ndr_pull_flags_fn_t)ndr_pull_replPropertyMetaDataBlob);
1861                 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
1862                         DEBUG(0,(__location__ ": Failed to parse replPropertyMetaData for %s\n",
1863                                  ldb_dn_get_linearized(msg->dn)));
1864                         return LDB_ERR_OPERATIONS_ERROR;
1865                 }
1866
1867                 if (omd.version != 1) {
1868                         DEBUG(0,(__location__ ": bad version %u in replPropertyMetaData for %s\n",
1869                                  omd.version, ldb_dn_get_linearized(msg->dn)));
1870                         return LDB_ERR_OPERATIONS_ERROR;
1871                 }
1872
1873                 for (i=0; i<msg->num_elements;) {
1874                         struct ldb_message_element *el = &msg->elements[i];
1875                         struct ldb_message_element *old_el;
1876
1877                         old_el = ldb_msg_find_element(res->msgs[0], el->name);
1878                         ret = replmd_update_rpmd_element(ldb, msg, el, old_el,
1879                                                          &omd, schema, seq_num,
1880                                                          our_invocation_id,
1881                                                          now, is_schema_nc,
1882                                                          is_forced_rodc,
1883                                                          req);
1884                         if (ret != LDB_SUCCESS) {
1885                                 return ret;
1886                         }
1887
1888                         if (!*is_urgent && (situation == REPL_URGENT_ON_UPDATE)) {
1889                                 *is_urgent = replmd_check_urgent_attribute(el);
1890                         }
1891
1892                         if (!(el->flags & DSDB_FLAG_INTERNAL_FORCE_META_DATA)) {
1893                                 i++;
1894                                 continue;
1895                         }
1896
1897                         el->flags &= ~DSDB_FLAG_INTERNAL_FORCE_META_DATA;
1898
1899                         if (el->num_values != 0) {
1900                                 i++;
1901                                 continue;
1902                         }
1903
1904                         ldb_msg_remove_element(msg, el);
1905                 }
1906         }
1907
1908         /*
1909          * Assert that we have an objectClass attribute - this is major
1910          * corruption if we don't have this!
1911          */
1912         objectclass_el = ldb_msg_find_element(res->msgs[0], "objectClass");
1913         if (objectclass_el != NULL) {
1914                 /*
1915                  * Now check if this objectClass means we need to do urgent replication
1916                  */
1917                 if (!*is_urgent && replmd_check_urgent_objectclass(objectclass_el,
1918                                                                    situation)) {
1919                         *is_urgent = true;
1920                 }
1921         } else if (!ldb_request_get_control(req, DSDB_CONTROL_DBCHECK)) {
1922                 ldb_asprintf_errstring(ldb, __location__
1923                                        ": objectClass missing on %s\n",
1924                                        ldb_dn_get_linearized(msg->dn));
1925                 return LDB_ERR_OBJECT_CLASS_VIOLATION;
1926         }
1927
1928         /*
1929          * replmd_update_rpmd_element has done an update if the
1930          * seq_num is set
1931          */
1932         if (*seq_num != 0 || rmd_is_just_resorted == true) {
1933                 struct ldb_val *md_value;
1934                 struct ldb_message_element *el;
1935
1936                 /*if we are RODC and this is a DRSR update then its ok*/
1937                 if (!ldb_request_get_control(req, DSDB_CONTROL_REPLICATED_UPDATE_OID)
1938                     && !ldb_request_get_control(req, DSDB_CONTROL_DBCHECK_MODIFY_RO_REPLICA)
1939                     && !is_forced_rodc) {
1940                         unsigned instanceType;
1941
1942                         if (*rodc) {
1943                                 ldb_set_errstring(ldb, "RODC modify is forbidden!");
1944                                 return LDB_ERR_REFERRAL;
1945                         }
1946
1947                         instanceType = ldb_msg_find_attr_as_uint(res->msgs[0], "instanceType", INSTANCE_TYPE_WRITE);
1948                         if (!(instanceType & INSTANCE_TYPE_WRITE)) {
1949                                 return ldb_error(ldb, LDB_ERR_UNWILLING_TO_PERFORM,
1950                                                  "cannot change replicated attribute on partial replica");
1951                         }
1952                 }
1953
1954                 md_value = talloc(msg, struct ldb_val);
1955                 if (md_value == NULL) {
1956                         ldb_oom(ldb);
1957                         return LDB_ERR_OPERATIONS_ERROR;
1958                 }
1959
1960                 ret = replmd_replPropertyMetaDataCtr1_sort_and_verify(ldb, &omd.ctr.ctr1, msg->dn);
1961                 if (ret != LDB_SUCCESS) {
1962                         ldb_asprintf_errstring(ldb, "%s: %s", __func__, ldb_errstring(ldb));
1963                         return ret;
1964                 }
1965
1966                 ndr_err = ndr_push_struct_blob(md_value, msg, &omd,
1967                                                (ndr_push_flags_fn_t)ndr_push_replPropertyMetaDataBlob);
1968                 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
1969                         DEBUG(0,(__location__ ": Failed to marshall replPropertyMetaData for %s\n",
1970                                  ldb_dn_get_linearized(msg->dn)));
1971                         return LDB_ERR_OPERATIONS_ERROR;
1972                 }
1973
1974                 ret = ldb_msg_add_empty(msg, "replPropertyMetaData", LDB_FLAG_MOD_REPLACE, &el);
1975                 if (ret != LDB_SUCCESS) {
1976                         DEBUG(0,(__location__ ": Failed to add updated replPropertyMetaData %s\n",
1977                                  ldb_dn_get_linearized(msg->dn)));
1978                         return ret;
1979                 }
1980
1981                 el->num_values = 1;
1982                 el->values = md_value;
1983         }
1984
1985         return LDB_SUCCESS;
1986 }
1987
1988 static int parsed_dn_compare(struct parsed_dn *pdn1, struct parsed_dn *pdn2)
1989 {
1990         int ret = ndr_guid_compare(&pdn1->guid, &pdn2->guid);
1991         if (ret == 0) {
1992                 return data_blob_cmp(&pdn1->dsdb_dn->extra_part,
1993                                      &pdn2->dsdb_dn->extra_part);
1994         }
1995         return ret;
1996 }
1997
1998 /*
1999   get a series of message element values as an array of DNs and GUIDs
2000   the result is sorted by GUID
2001  */
2002 static int get_parsed_dns(struct ldb_module *module, TALLOC_CTX *mem_ctx,
2003                           struct ldb_message_element *el, struct parsed_dn **pdn,
2004                           const char *ldap_oid, struct ldb_request *parent)
2005 {
2006         unsigned int i;
2007         bool values_are_sorted = true;
2008         struct ldb_context *ldb = ldb_module_get_ctx(module);
2009
2010         if (el == NULL) {
2011                 *pdn = NULL;
2012                 return LDB_SUCCESS;
2013         }
2014
2015         (*pdn) = talloc_array(mem_ctx, struct parsed_dn, el->num_values);
2016         if (!*pdn) {
2017                 ldb_module_oom(module);
2018                 return LDB_ERR_OPERATIONS_ERROR;
2019         }
2020
2021         for (i=0; i<el->num_values; i++) {
2022                 struct ldb_val *v = &el->values[i];
2023                 NTSTATUS status;
2024                 struct ldb_dn *dn;
2025                 struct parsed_dn *p;
2026
2027                 p = &(*pdn)[i];
2028
2029                 p->dsdb_dn = dsdb_dn_parse(*pdn, ldb, v, ldap_oid);
2030                 if (p->dsdb_dn == NULL) {
2031                         return LDB_ERR_INVALID_DN_SYNTAX;
2032                 }
2033
2034                 dn = p->dsdb_dn->dn;
2035
2036                 status = dsdb_get_extended_dn_guid(dn, &p->guid, "GUID");
2037                 if (NT_STATUS_EQUAL(status, NT_STATUS_OBJECT_NAME_NOT_FOUND) ||
2038                     unlikely(GUID_all_zero(&p->guid))) {
2039                         /* we got a DN without a GUID - go find the GUID */
2040                         int ret = dsdb_module_guid_by_dn(module, dn, &p->guid, parent);
2041                         if (ret != LDB_SUCCESS) {
2042                                 char *dn_str = NULL;
2043                                 dn_str = ldb_dn_get_extended_linearized(mem_ctx,
2044                                                                         (dn), 1);
2045                                 ldb_asprintf_errstring(ldb,
2046                                                 "Unable to find GUID for DN %s\n",
2047                                                 dn_str);
2048                                 if (ret == LDB_ERR_NO_SUCH_OBJECT &&
2049                                     LDB_FLAG_MOD_TYPE(el->flags) == LDB_FLAG_MOD_DELETE &&
2050                                     ldb_attr_cmp(el->name, "member") == 0) {
2051                                         return LDB_ERR_UNWILLING_TO_PERFORM;
2052                                 }
2053                                 return ret;
2054                         }
2055                         ret = dsdb_set_extended_dn_guid(dn, &p->guid, "GUID");
2056                         if (ret != LDB_SUCCESS) {
2057                                 return ret;
2058                         }
2059                 } else if (!NT_STATUS_IS_OK(status)) {
2060                         return LDB_ERR_OPERATIONS_ERROR;
2061                 }
2062                 if (i > 0 && values_are_sorted) {
2063                         int cmp = parsed_dn_compare(p, &(*pdn)[i - 1]);
2064                         if (cmp < 0) {
2065                                 values_are_sorted = false;
2066                         }
2067                 }
2068                 /* keep a pointer to the original ldb_val */
2069                 p->v = v;
2070         }
2071         if (! values_are_sorted) {
2072                 TYPESAFE_QSORT(*pdn, el->num_values, parsed_dn_compare);
2073         }
2074         return LDB_SUCCESS;
2075 }
2076
2077 /*
2078  * Get a series of trusted message element values. The result is sorted by
2079  * GUID, even though the GUIDs might not be known. That works because we trust
2080  * the database to give us the elements like that if the
2081  * replmd_private->sorted_links flag is set.
2082  *
2083  * We also ensure that the links are in the Functional Level 2003
2084  * linked attributes format.
2085  */
2086 static int get_parsed_dns_trusted(struct ldb_module *module,
2087                                   struct replmd_private *replmd_private,
2088                                   TALLOC_CTX *mem_ctx,
2089                                   struct ldb_message_element *el,
2090                                   struct parsed_dn **pdn,
2091                                   const char *ldap_oid,
2092                                   struct ldb_request *parent)
2093 {
2094         unsigned int i;
2095         int ret;
2096         if (el == NULL) {
2097                 *pdn = NULL;
2098                 return LDB_SUCCESS;
2099         }
2100
2101         if (!replmd_private->sorted_links) {
2102                 /* We need to sort the list. This is the slow old path we want
2103                    to avoid.
2104                  */
2105                 ret = get_parsed_dns(module, mem_ctx, el, pdn, ldap_oid,
2106                                       parent);
2107                 if (ret != LDB_SUCCESS) {
2108                         return ret;
2109                 }
2110         } else {
2111                 /* Here we get a list of 'struct parsed_dns' without the parsing */
2112                 *pdn = talloc_zero_array(mem_ctx, struct parsed_dn,
2113                                          el->num_values);
2114                 if (!*pdn) {
2115                         ldb_module_oom(module);
2116                         return LDB_ERR_OPERATIONS_ERROR;
2117                 }
2118
2119                 for (i = 0; i < el->num_values; i++) {
2120                         (*pdn)[i].v = &el->values[i];
2121                 }
2122         }
2123
2124         /*
2125          * This upgrades links to FL2003 style, and sorts the result
2126          * if that was needed.
2127          *
2128          * TODO: Add a database feature that asserts we have no FL2000
2129          *       style links to avoid this check or add a feature that
2130          *       uses a similar check to find sorted/unsorted links
2131          *       for an on-the-fly upgrade.
2132          */
2133
2134         ret = replmd_check_upgrade_links(ldb_module_get_ctx(module),
2135                                          *pdn, el->num_values,
2136                                          el,
2137                                          ldap_oid);
2138         if (ret != LDB_SUCCESS) {
2139                 return ret;
2140         }
2141
2142         return LDB_SUCCESS;
2143 }
2144
2145 /*
2146    Return LDB_SUCCESS if a parsed_dn list contains no duplicate values,
2147    otherwise an error code. For compatibility the error code differs depending
2148    on whether or not the attribute is "member".
2149
2150    As always, the parsed_dn list is assumed to be sorted.
2151  */
2152 static int check_parsed_dn_duplicates(struct ldb_module *module,
2153                                       struct ldb_message_element *el,
2154                                       struct parsed_dn *pdn)
2155 {
2156         unsigned int i;
2157         struct ldb_context *ldb = ldb_module_get_ctx(module);
2158
2159         for (i = 1; i < el->num_values; i++) {
2160                 struct parsed_dn *p = &pdn[i];
2161                 if (parsed_dn_compare(p, &pdn[i - 1]) == 0) {
2162                         ldb_asprintf_errstring(ldb,
2163                                                "Linked attribute %s has "
2164                                                "multiple identical values",
2165                                                el->name);
2166                         if (ldb_attr_cmp(el->name, "member") == 0) {
2167                                 return LDB_ERR_ENTRY_ALREADY_EXISTS;
2168                         } else {
2169                                 return LDB_ERR_ATTRIBUTE_OR_VALUE_EXISTS;
2170                         }
2171                 }
2172         }
2173         return LDB_SUCCESS;
2174 }
2175
2176 /*
2177   build a new extended DN, including all meta data fields
2178
2179   RMD_FLAGS           = DSDB_RMD_FLAG_* bits
2180   RMD_ADDTIME         = originating_add_time
2181   RMD_INVOCID         = originating_invocation_id
2182   RMD_CHANGETIME      = originating_change_time
2183   RMD_ORIGINATING_USN = originating_usn
2184   RMD_LOCAL_USN       = local_usn
2185   RMD_VERSION         = version
2186  */
2187 static int replmd_build_la_val(TALLOC_CTX *mem_ctx, struct ldb_val *v,
2188                                struct dsdb_dn *dsdb_dn,
2189                                const struct GUID *invocation_id,
2190                                uint64_t local_usn, NTTIME nttime)
2191 {
2192         return replmd_set_la_val(mem_ctx, v, dsdb_dn, NULL, invocation_id,
2193                                  local_usn, local_usn, nttime,
2194                                  RMD_VERSION_INITIAL, false);
2195 }
2196
2197 static int replmd_update_la_val(TALLOC_CTX *mem_ctx, struct ldb_val *v, struct dsdb_dn *dsdb_dn,
2198                                 struct dsdb_dn *old_dsdb_dn, const struct GUID *invocation_id,
2199                                 uint64_t seq_num, uint64_t local_usn, NTTIME nttime,
2200                                 bool deleted);
2201
2202 /*
2203   check if any links need upgrading from w2k format
2204  */
2205 static int replmd_check_upgrade_links(struct ldb_context *ldb,
2206                                       struct parsed_dn *dns, uint32_t count,
2207                                       struct ldb_message_element *el,
2208                                       const char *ldap_oid)
2209 {
2210         uint32_t i;
2211         const struct GUID *invocation_id = NULL;
2212         for (i=0; i<count; i++) {
2213                 NTSTATUS status;
2214                 uint32_t version;
2215                 int ret;
2216                 if (dns[i].dsdb_dn == NULL) {
2217                         ret = really_parse_trusted_dn(dns, ldb, &dns[i],
2218                                                       ldap_oid);
2219                         if (ret != LDB_SUCCESS) {
2220                                 return LDB_ERR_INVALID_DN_SYNTAX;
2221                         }
2222                 }
2223
2224                 status = dsdb_get_extended_dn_uint32(dns[i].dsdb_dn->dn,
2225                                                      &version, "RMD_VERSION");
2226                 if (!NT_STATUS_EQUAL(status, NT_STATUS_OBJECT_NAME_NOT_FOUND)) {
2227                         /*
2228                          *  We optimistically assume they are all the same; if
2229                          *  the first one is fixed, they are all fixed.
2230                          *
2231                          *  If the first one was *not* fixed and we find a
2232                          *  later one that is, that is an occasion to shout
2233                          *  with DEBUG(0).
2234                          */
2235                         if (i == 0) {
2236                                 return LDB_SUCCESS;
2237                         }
2238                         DEBUG(0, ("Mixed w2k and fixed format "
2239                                   "linked attributes\n"));
2240                         continue;
2241                 }
2242
2243                 if (invocation_id == NULL) {
2244                         invocation_id = samdb_ntds_invocation_id(ldb);
2245                         if (invocation_id == NULL) {
2246                                 return LDB_ERR_OPERATIONS_ERROR;
2247                         }
2248                 }
2249
2250
2251                 /* it's an old one that needs upgrading */
2252                 ret = replmd_update_la_val(el->values, dns[i].v,
2253                                            dns[i].dsdb_dn, dns[i].dsdb_dn,
2254                                            invocation_id, 1, 1, 0, false);
2255                 if (ret != LDB_SUCCESS) {
2256                         return ret;
2257                 }
2258         }
2259
2260         /*
2261          * This sort() is critical for the operation of
2262          * get_parsed_dns_trusted() because callers of this function
2263          * expect a sorted list, and FL2000 style links are not
2264          * sorted.  In particular, as well as the upgrade case,
2265          * get_parsed_dns_trusted() is called from
2266          * replmd_delete_remove_link() even in FL2000 mode
2267          *
2268          * We do not normally pay the cost of the qsort() due to the
2269          * early return in the RMD_VERSION found case.
2270          */
2271         TYPESAFE_QSORT(dns, count, parsed_dn_compare);
2272         return LDB_SUCCESS;
2273 }
2274
2275 /*
2276   Sets the value for a linked attribute, including all meta data fields
2277
2278   see replmd_build_la_val for value names
2279  */
2280 static int replmd_set_la_val(TALLOC_CTX *mem_ctx, struct ldb_val *v, struct dsdb_dn *dsdb_dn,
2281                              struct dsdb_dn *old_dsdb_dn, const struct GUID *invocation_id,
2282                              uint64_t usn, uint64_t local_usn, NTTIME nttime,
2283                              uint32_t version, bool deleted)
2284 {
2285         struct ldb_dn *dn = dsdb_dn->dn;
2286         const char *tstring, *usn_string, *flags_string;
2287         struct ldb_val tval;
2288         struct ldb_val iid;
2289         struct ldb_val usnv, local_usnv;
2290         struct ldb_val vers, flagsv;
2291         const struct ldb_val *old_addtime = NULL;
2292         NTSTATUS status;
2293         int ret;
2294         const char *dnstring;
2295         char *vstring;
2296         uint32_t rmd_flags = deleted?DSDB_RMD_FLAG_DELETED:0;
2297
2298         tstring = talloc_asprintf(mem_ctx, "%llu", (unsigned long long)nttime);
2299         if (!tstring) {
2300                 return LDB_ERR_OPERATIONS_ERROR;
2301         }
2302         tval = data_blob_string_const(tstring);
2303
2304         usn_string = talloc_asprintf(mem_ctx, "%llu", (unsigned long long)usn);
2305         if (!usn_string) {
2306                 return LDB_ERR_OPERATIONS_ERROR;
2307         }
2308         usnv = data_blob_string_const(usn_string);
2309
2310         usn_string = talloc_asprintf(mem_ctx, "%llu", (unsigned long long)local_usn);
2311         if (!usn_string) {
2312                 return LDB_ERR_OPERATIONS_ERROR;
2313         }
2314         local_usnv = data_blob_string_const(usn_string);
2315
2316         status = GUID_to_ndr_blob(invocation_id, dn, &iid);
2317         if (!NT_STATUS_IS_OK(status)) {
2318                 return LDB_ERR_OPERATIONS_ERROR;
2319         }
2320
2321         flags_string = talloc_asprintf(mem_ctx, "%u", rmd_flags);
2322         if (!flags_string) {
2323                 return LDB_ERR_OPERATIONS_ERROR;
2324         }
2325         flagsv = data_blob_string_const(flags_string);
2326
2327         ret = ldb_dn_set_extended_component(dn, "RMD_FLAGS", &flagsv);
2328         if (ret != LDB_SUCCESS) return ret;
2329
2330         /* get the ADDTIME from the original */
2331         if (old_dsdb_dn != NULL) {
2332                 old_addtime = ldb_dn_get_extended_component(old_dsdb_dn->dn,
2333                                                             "RMD_ADDTIME");
2334         }
2335         if (old_addtime == NULL) {
2336                 old_addtime = &tval;
2337         }
2338         if (dsdb_dn != old_dsdb_dn ||
2339             ldb_dn_get_extended_component(dn, "RMD_ADDTIME") == NULL) {
2340                 ret = ldb_dn_set_extended_component(dn, "RMD_ADDTIME", old_addtime);
2341                 if (ret != LDB_SUCCESS) return ret;
2342         }
2343
2344         /* use our invocation id */
2345         ret = ldb_dn_set_extended_component(dn, "RMD_INVOCID", &iid);
2346         if (ret != LDB_SUCCESS) return ret;
2347
2348         /* changetime is the current time */
2349         ret = ldb_dn_set_extended_component(dn, "RMD_CHANGETIME", &tval);
2350         if (ret != LDB_SUCCESS) return ret;
2351
2352         /* update the USN */
2353         ret = ldb_dn_set_extended_component(dn, "RMD_ORIGINATING_USN", &usnv);
2354         if (ret != LDB_SUCCESS) return ret;
2355
2356         ret = ldb_dn_set_extended_component(dn, "RMD_LOCAL_USN", &local_usnv);
2357         if (ret != LDB_SUCCESS) return ret;
2358
2359         vstring = talloc_asprintf(mem_ctx, "%lu", (unsigned long)version);
2360         vers = data_blob_string_const(vstring);
2361         ret = ldb_dn_set_extended_component(dn, "RMD_VERSION", &vers);
2362         if (ret != LDB_SUCCESS) return ret;
2363
2364         dnstring = dsdb_dn_get_extended_linearized(mem_ctx, dsdb_dn, 1);
2365         if (dnstring == NULL) {
2366                 return LDB_ERR_OPERATIONS_ERROR;
2367         }
2368         *v = data_blob_string_const(dnstring);
2369
2370         return LDB_SUCCESS;
2371 }
2372
2373 /**
2374  * Updates the value for a linked attribute, including all meta data fields
2375  */
2376 static int replmd_update_la_val(TALLOC_CTX *mem_ctx, struct ldb_val *v, struct dsdb_dn *dsdb_dn,
2377                                 struct dsdb_dn *old_dsdb_dn, const struct GUID *invocation_id,
2378                                 uint64_t usn, uint64_t local_usn, NTTIME nttime,
2379                                 bool deleted)
2380 {
2381         uint32_t old_version;
2382         uint32_t version = RMD_VERSION_INITIAL;
2383         NTSTATUS status;
2384
2385         /*
2386          * We're updating the linked attribute locally, so increase the version
2387          * by 1 so that other DCs will see the change when it gets replicated out
2388          */
2389         status = dsdb_get_extended_dn_uint32(old_dsdb_dn->dn, &old_version,
2390                                              "RMD_VERSION");
2391
2392         if (NT_STATUS_IS_OK(status)) {
2393                 version = old_version + 1;
2394         }
2395
2396         return replmd_set_la_val(mem_ctx, v, dsdb_dn, old_dsdb_dn, invocation_id,
2397                                  usn, local_usn, nttime, version, deleted);
2398 }
2399
2400 /*
2401   handle adding a linked attribute
2402  */
2403 static int replmd_modify_la_add(struct ldb_module *module,
2404                                 struct replmd_private *replmd_private,
2405                                 struct replmd_replicated_request *ac,
2406                                 struct ldb_message *msg,
2407                                 struct ldb_message_element *el,
2408                                 struct ldb_message_element *old_el,
2409                                 const struct dsdb_attribute *schema_attr,
2410                                 time_t t,
2411                                 struct ldb_dn *msg_dn,
2412                                 struct ldb_request *parent)
2413 {
2414         unsigned int i, j;
2415         struct parsed_dn *dns, *old_dns;
2416         TALLOC_CTX *tmp_ctx = talloc_new(msg);
2417         int ret;
2418         struct ldb_val *new_values = NULL;
2419         unsigned old_num_values = old_el ? old_el->num_values : 0;
2420         unsigned num_values = 0;
2421         unsigned max_num_values;
2422         struct ldb_context *ldb = ldb_module_get_ctx(module);
2423         NTTIME now;
2424         unix_to_nt_time(&now, t);
2425
2426         /* get the DNs to be added, fully parsed.
2427          *
2428          * We need full parsing because they came off the wire and we don't
2429          * trust them, besides which we need their details to know where to put
2430          * them.
2431          */
2432         ret = get_parsed_dns(module, tmp_ctx, el, &dns,
2433                              schema_attr->syntax->ldap_oid, parent);
2434         if (ret != LDB_SUCCESS) {
2435                 talloc_free(tmp_ctx);
2436                 return ret;
2437         }
2438
2439         /* get the existing DNs, lazily parsed */
2440         ret = get_parsed_dns_trusted(module, replmd_private,
2441                                      tmp_ctx, old_el, &old_dns,
2442                                      schema_attr->syntax->ldap_oid, parent);
2443
2444         if (ret != LDB_SUCCESS) {
2445                 talloc_free(tmp_ctx);
2446                 return ret;
2447         }
2448
2449         max_num_values = old_num_values + el->num_values;
2450         if (max_num_values < old_num_values) {
2451                 DEBUG(0, ("we seem to have overflow in replmd_modify_la_add. "
2452                           "old values: %u, new values: %u, sum: %u\n",
2453                           old_num_values, el->num_values, max_num_values));
2454                 talloc_free(tmp_ctx);
2455                 return LDB_ERR_OPERATIONS_ERROR;
2456         }
2457
2458         new_values = talloc_zero_array(tmp_ctx, struct ldb_val, max_num_values);
2459
2460         if (new_values == NULL) {
2461                 ldb_module_oom(module);
2462                 talloc_free(tmp_ctx);
2463                 return LDB_ERR_OPERATIONS_ERROR;
2464         }
2465
2466         /*
2467          * For each new value, find where it would go in the list. If there is
2468          * a matching GUID there, we update the existing value; otherwise we
2469          * put it in place.
2470          */
2471         j = 0;
2472         for (i = 0; i < el->num_values; i++) {
2473                 struct parsed_dn *exact;
2474                 struct parsed_dn *next;
2475                 unsigned offset;
2476                 int err = parsed_dn_find(ldb, old_dns, old_num_values,
2477                                          &dns[i].guid,
2478                                          dns[i].dsdb_dn->dn,
2479                                          dns[i].dsdb_dn->extra_part, 0,
2480                                          &exact, &next,
2481                                          schema_attr->syntax->ldap_oid,
2482                                          true);
2483                 if (err != LDB_SUCCESS) {
2484                         talloc_free(tmp_ctx);
2485                         return err;
2486                 }
2487
2488                 if (exact != NULL) {
2489                         /*
2490                          * We are trying to add one that exists, which is only
2491                          * allowed if it was previously deleted.
2492                          *
2493                          * When we do undelete a link we change it in place.
2494                          * It will be copied across into the right spot in due
2495                          * course.
2496                          */
2497                         uint32_t rmd_flags;
2498                         rmd_flags = dsdb_dn_rmd_flags(exact->dsdb_dn->dn);
2499
2500                         if (!(rmd_flags & DSDB_RMD_FLAG_DELETED)) {
2501                                 struct GUID_txt_buf guid_str;
2502                                 ldb_asprintf_errstring(ldb,
2503                                                        "Attribute %s already "
2504                                                        "exists for target GUID %s",
2505                                                        el->name,
2506                                                        GUID_buf_string(&exact->guid,
2507                                                                        &guid_str));
2508                                 talloc_free(tmp_ctx);
2509                                 /* error codes for 'member' need to be
2510                                    special cased */
2511                                 if (ldb_attr_cmp(el->name, "member") == 0) {
2512                                         return LDB_ERR_ENTRY_ALREADY_EXISTS;
2513                                 } else {
2514                                         return LDB_ERR_ATTRIBUTE_OR_VALUE_EXISTS;
2515                                 }
2516                         }
2517
2518                         ret = replmd_update_la_val(new_values, exact->v,
2519                                                    dns[i].dsdb_dn,
2520                                                    exact->dsdb_dn,
2521                                                    &ac->our_invocation_id,
2522                                                    ac->seq_num, ac->seq_num,
2523                                                    now, false);
2524                         if (ret != LDB_SUCCESS) {
2525                                 talloc_free(tmp_ctx);
2526                                 return ret;
2527                         }
2528
2529                         ret = replmd_add_backlink(module, replmd_private,
2530                                                   ac->schema,
2531                                                   msg_dn,
2532                                                   &dns[i].guid, 
2533                                                   true,
2534                                                   schema_attr,
2535                                                   parent);
2536                         if (ret != LDB_SUCCESS) {
2537                                 talloc_free(tmp_ctx);
2538                                 return ret;
2539                                 }
2540                         continue;
2541                 }
2542                 /*
2543                  * Here we don't have an exact match.
2544                  *
2545                  * If next is NULL, this one goes beyond the end of the
2546                  * existing list, so we need to add all of those ones first.
2547                  *
2548                  * If next is not NULL, we need to add all the ones before
2549                  * next.
2550                  */
2551                 if (next == NULL) {
2552                         offset = old_num_values;
2553                 } else {
2554                         /* next should have been parsed, but let's make sure */
2555                         if (next->dsdb_dn == NULL) {
2556                                 ret = really_parse_trusted_dn(tmp_ctx, ldb, next,
2557                                                               schema_attr->syntax->ldap_oid);
2558                                 if (ret != LDB_SUCCESS) {
2559                                         return ret;
2560                                 }
2561                         }
2562                         offset = MIN(next - old_dns, old_num_values);
2563                 }
2564
2565                 /* put all the old ones before next on the list */
2566                 for (; j < offset; j++) {
2567                         new_values[num_values] = *old_dns[j].v;
2568                         num_values++;
2569                 }
2570
2571                 ret = replmd_add_backlink(module, replmd_private,
2572                                           ac->schema, msg_dn,
2573                                           &dns[i].guid,
2574                                           true, schema_attr,
2575                                           parent);
2576                 /* Make the new linked attribute ldb_val. */
2577                 ret = replmd_build_la_val(new_values, &new_values[num_values],
2578                                           dns[i].dsdb_dn, &ac->our_invocation_id,
2579                                           ac->seq_num, now);
2580                 if (ret != LDB_SUCCESS) {
2581                         talloc_free(tmp_ctx);
2582                         return ret;
2583                 }
2584                 num_values++;
2585                 if (ret != LDB_SUCCESS) {
2586                         talloc_free(tmp_ctx);
2587                         return ret;
2588                 }
2589         }
2590         /* copy the rest of the old ones (if any) */
2591         for (; j < old_num_values; j++) {
2592                 new_values[num_values] = *old_dns[j].v;
2593                 num_values++;
2594         }
2595
2596         talloc_steal(msg->elements, new_values);
2597         if (old_el != NULL) {
2598                 talloc_steal(msg->elements, old_el->values);
2599         }
2600         el->values = new_values;
2601         el->num_values = num_values;
2602
2603         talloc_free(tmp_ctx);
2604
2605         /* we now tell the backend to replace all existing values
2606            with the one we have constructed */
2607         el->flags = LDB_FLAG_MOD_REPLACE;
2608
2609         return LDB_SUCCESS;
2610 }
2611
2612
2613 /*
2614   handle deleting all active linked attributes
2615  */
2616 static int replmd_modify_la_delete(struct ldb_module *module,
2617                                    struct replmd_private *replmd_private,
2618                                    const struct dsdb_schema *schema,
2619                                    struct ldb_message *msg,
2620                                    struct ldb_message_element *el,
2621                                    struct ldb_message_element *old_el,
2622                                    const struct dsdb_attribute *schema_attr,
2623                                    uint64_t seq_num,
2624                                    time_t t,
2625                                    struct ldb_dn *msg_dn,
2626                                    struct ldb_request *parent)
2627 {
2628         unsigned int i;
2629         struct parsed_dn *dns, *old_dns;
2630         TALLOC_CTX *tmp_ctx = NULL;
2631         int ret;
2632         struct ldb_context *ldb = ldb_module_get_ctx(module);
2633         struct ldb_control *vanish_links_ctrl = NULL;
2634         bool vanish_links = false;
2635         unsigned int num_to_delete = el->num_values;
2636         uint32_t rmd_flags;
2637         const struct GUID *invocation_id;
2638         NTTIME now;
2639
2640         unix_to_nt_time(&now, t);
2641
2642         invocation_id = samdb_ntds_invocation_id(ldb);
2643         if (!invocation_id) {
2644                 return LDB_ERR_OPERATIONS_ERROR;
2645         }
2646
2647         if (old_el == NULL || old_el->num_values == 0) {
2648                 /* there is nothing to delete... */
2649                 if (num_to_delete == 0) {
2650                         /* and we're deleting nothing, so that's OK */
2651                         return LDB_SUCCESS;
2652                 }
2653                 return LDB_ERR_NO_SUCH_ATTRIBUTE;
2654         }
2655
2656         tmp_ctx = talloc_new(msg);
2657         if (tmp_ctx == NULL) {
2658                 return LDB_ERR_OPERATIONS_ERROR;
2659         }
2660
2661         ret = get_parsed_dns(module, tmp_ctx, el, &dns,
2662                              schema_attr->syntax->ldap_oid, parent);
2663         if (ret != LDB_SUCCESS) {
2664                 talloc_free(tmp_ctx);
2665                 return ret;
2666         }
2667
2668         ret = get_parsed_dns_trusted(module, replmd_private,
2669                                      tmp_ctx, old_el, &old_dns,
2670                                      schema_attr->syntax->ldap_oid, parent);
2671
2672         if (ret != LDB_SUCCESS) {
2673                 talloc_free(tmp_ctx);
2674                 return ret;
2675         }
2676
2677         if (parent) {
2678                 vanish_links_ctrl = ldb_request_get_control(parent, DSDB_CONTROL_REPLMD_VANISH_LINKS);
2679                 if (vanish_links_ctrl) {
2680                         vanish_links = true;
2681                         vanish_links_ctrl->critical = false;
2682                 }
2683         }
2684
2685         /* we empty out el->values here to avoid damage if we return early. */
2686         el->num_values = 0;
2687         el->values = NULL;
2688
2689         /*
2690          * If vanish links is set, we are actually removing members of
2691          *  old_el->values; otherwise we are just marking them deleted.
2692          *
2693          * There is a special case when no values are given: we remove them
2694          * all. When we have the vanish_links control we just have to remove
2695          * the backlinks and change our element to replace the existing values
2696          * with the empty list.
2697          */
2698
2699         if (num_to_delete == 0) {
2700                 for (i = 0; i < old_el->num_values; i++) {
2701                         struct parsed_dn *p = &old_dns[i];
2702                         if (p->dsdb_dn == NULL) {
2703                                 ret = really_parse_trusted_dn(tmp_ctx, ldb, p,
2704                                                               schema_attr->syntax->ldap_oid);
2705                                 if (ret != LDB_SUCCESS) {
2706                                         return ret;
2707                                 }
2708                         }
2709                         ret = replmd_add_backlink(module, replmd_private,
2710                                                   schema, msg_dn, &p->guid,
2711                                                   false, schema_attr,
2712                                                   parent);
2713                         if (ret != LDB_SUCCESS) {
2714                                 talloc_free(tmp_ctx);
2715                                 return ret;
2716                         }
2717                         if (vanish_links) {
2718                                 continue;
2719                         }
2720
2721                         rmd_flags = dsdb_dn_rmd_flags(p->dsdb_dn->dn);
2722                         if (rmd_flags & DSDB_RMD_FLAG_DELETED) {
2723                                 continue;
2724                         }
2725
2726                         ret = replmd_update_la_val(old_el->values, p->v,
2727                                                    p->dsdb_dn, p->dsdb_dn,
2728                                                    invocation_id, seq_num,
2729                                                    seq_num, now, true);
2730                         if (ret != LDB_SUCCESS) {
2731                                 talloc_free(tmp_ctx);
2732                                 return ret;
2733                         }
2734                 }
2735
2736                 if (vanish_links) {
2737                         el->flags = LDB_FLAG_MOD_REPLACE;
2738                         talloc_free(tmp_ctx);
2739                         return LDB_SUCCESS;
2740                 }
2741         }
2742
2743
2744         for (i = 0; i < num_to_delete; i++) {
2745                 struct parsed_dn *p = &dns[i];
2746                 struct parsed_dn *exact = NULL;
2747                 struct parsed_dn *next = NULL;
2748                 ret = parsed_dn_find(ldb, old_dns, old_el->num_values,
2749                                      &p->guid,
2750                                      NULL,
2751                                      p->dsdb_dn->extra_part, 0,
2752                                      &exact, &next,
2753                                      schema_attr->syntax->ldap_oid,
2754                                      true);
2755                 if (ret != LDB_SUCCESS) {
2756                         talloc_free(tmp_ctx);
2757                         return ret;
2758                 }
2759                 if (exact == NULL) {
2760                         struct GUID_txt_buf buf;
2761                         ldb_asprintf_errstring(ldb, "Attribute %s doesn't "
2762                                                "exist for target GUID %s",
2763                                                el->name,
2764                                                GUID_buf_string(&p->guid, &buf));
2765                         if (ldb_attr_cmp(el->name, "member") == 0) {
2766                                 talloc_free(tmp_ctx);
2767                                 return LDB_ERR_UNWILLING_TO_PERFORM;
2768                         } else {
2769                                 talloc_free(tmp_ctx);
2770                                 return LDB_ERR_NO_SUCH_ATTRIBUTE;
2771                         }
2772                 }
2773
2774                 if (vanish_links) {
2775                         if (CHECK_DEBUGLVL(5)) {
2776                                 rmd_flags = dsdb_dn_rmd_flags(exact->dsdb_dn->dn);
2777                                 if ((rmd_flags & DSDB_RMD_FLAG_DELETED)) {
2778                                         struct GUID_txt_buf buf;
2779                                         const char *guid_str = \
2780                                                 GUID_buf_string(&p->guid, &buf);
2781                                         DEBUG(5, ("Deleting deleted linked "
2782                                                   "attribute %s to %s, because "
2783                                                   "vanish_links control is set\n",
2784                                                   el->name, guid_str));
2785                                 }
2786                         }
2787
2788                         /* remove the backlink */
2789                         ret = replmd_add_backlink(module,
2790                                                   replmd_private,
2791                                                   schema, 
2792                                                   msg_dn,
2793                                                   &p->guid,
2794                                                   false, schema_attr,
2795                                                   parent);
2796                         if (ret != LDB_SUCCESS) {
2797                                 talloc_free(tmp_ctx);
2798                                 return ret;
2799                         }
2800
2801                         /* We flag the deletion and tidy it up later. */
2802                         exact->v = NULL;
2803                         continue;
2804                 }
2805
2806                 rmd_flags = dsdb_dn_rmd_flags(exact->dsdb_dn->dn);
2807
2808                 if (rmd_flags & DSDB_RMD_FLAG_DELETED) {
2809                         struct GUID_txt_buf buf;
2810                         const char *guid_str = GUID_buf_string(&p->guid, &buf);
2811                         ldb_asprintf_errstring(ldb, "Attribute %s already "
2812                                                "deleted for target GUID %s",
2813                                                el->name, guid_str);
2814                         if (ldb_attr_cmp(el->name, "member") == 0) {
2815                                 talloc_free(tmp_ctx);
2816                                 return LDB_ERR_UNWILLING_TO_PERFORM;
2817                         } else {
2818                                 talloc_free(tmp_ctx);
2819                                 return LDB_ERR_NO_SUCH_ATTRIBUTE;
2820                         }
2821                 }
2822
2823                 ret = replmd_update_la_val(old_el->values, exact->v,
2824                                            exact->dsdb_dn, exact->dsdb_dn,
2825                                            invocation_id, seq_num, seq_num,
2826                                            now, true);
2827                 if (ret != LDB_SUCCESS) {
2828                         talloc_free(tmp_ctx);
2829                         return ret;
2830                 }
2831                 ret = replmd_add_backlink(module, replmd_private,
2832                                           schema, msg_dn,
2833                                           &p->guid,
2834                                           false, schema_attr,
2835                                           parent);
2836                 if (ret != LDB_SUCCESS) {
2837                         talloc_free(tmp_ctx);
2838                         return ret;
2839                 }
2840         }
2841
2842         if (vanish_links) {
2843                 unsigned j = 0;
2844                 struct ldb_val *tmp_vals = NULL;
2845
2846                 tmp_vals = talloc_array(tmp_ctx, struct ldb_val,
2847                                         old_el->num_values);
2848                 if (tmp_vals == NULL) {
2849                         talloc_free(tmp_ctx);
2850                         return ldb_module_oom(module);
2851                 }
2852                 for (i = 0; i < old_el->num_values; i++) {
2853                         if (old_dns[i].v == NULL) {
2854                                 continue;
2855                         }
2856                         tmp_vals[j] = *old_dns[i].v;
2857                         j++;
2858                 }
2859                 for (i = 0; i < j; i++) {
2860                         old_el->values[i] = tmp_vals[i];
2861                 }
2862                 old_el->num_values = j;
2863         }
2864
2865         el->values = talloc_steal(msg->elements, old_el->values);
2866         el->num_values = old_el->num_values;
2867
2868         talloc_free(tmp_ctx);
2869
2870         /* we now tell the backend to replace all existing values
2871            with the one we have constructed */
2872         el->flags = LDB_FLAG_MOD_REPLACE;
2873
2874         return LDB_SUCCESS;
2875 }
2876
2877 /*
2878   handle replacing a linked attribute
2879  */
2880 static int replmd_modify_la_replace(struct ldb_module *module,
2881                                     struct replmd_private *replmd_private,
2882                                     const struct dsdb_schema *schema,
2883                                     struct ldb_message *msg,
2884                                     struct ldb_message_element *el,
2885                                     struct ldb_message_element *old_el,
2886                                     const struct dsdb_attribute *schema_attr,
2887                                     uint64_t seq_num,
2888                                     time_t t,
2889                                     struct ldb_dn *msg_dn,
2890                                     struct ldb_request *parent)
2891 {
2892         unsigned int i, old_i, new_i;
2893         struct parsed_dn *dns, *old_dns;
2894         TALLOC_CTX *tmp_ctx = talloc_new(msg);
2895         int ret;
2896         const struct GUID *invocation_id;
2897         struct ldb_context *ldb = ldb_module_get_ctx(module);
2898         struct ldb_val *new_values = NULL;
2899         const char *ldap_oid = schema_attr->syntax->ldap_oid;
2900         unsigned int old_num_values;
2901         unsigned int repl_num_values;
2902         unsigned int max_num_values;
2903         NTTIME now;
2904
2905         unix_to_nt_time(&now, t);
2906
2907         invocation_id = samdb_ntds_invocation_id(ldb);
2908         if (!invocation_id) {
2909                 return LDB_ERR_OPERATIONS_ERROR;
2910         }
2911
2912         /*
2913          * The replace operation is unlike the replace and delete cases in that
2914          * we need to look at every existing link to see whether it is being
2915          * retained or deleted. In other words, we can't avoid parsing the GUIDs.
2916          *
2917          * As we are trying to combine two sorted lists, the algorithm we use
2918          * is akin to the merge phase of a merge sort. We interleave the two
2919          * lists, doing different things depending on which side the current
2920          * item came from.
2921          *
2922          * There are three main cases, with some sub-cases.
2923          *
2924          *  - a DN is in the old list but not the new one. It needs to be
2925          *    marked as deleted (but left in the list).
2926          *     - maybe it is already deleted, and we have less to do.
2927          *
2928          *  - a DN is in both lists. The old data gets replaced by the new,
2929          *    and the list doesn't grow. The old link may have been marked as
2930          *    deleted, in which case we undelete it.
2931          *
2932          *  - a DN is in the new list only. We add it in the right place.
2933          */
2934
2935         old_num_values = old_el ? old_el->num_values : 0;
2936         repl_num_values = el->num_values;
2937         max_num_values = old_num_values + repl_num_values;
2938
2939         if (max_num_values == 0) {
2940                 /* There is nothing to do! */
2941                 return LDB_SUCCESS;
2942         }
2943
2944         ret = get_parsed_dns(module, tmp_ctx, el, &dns, ldap_oid, parent);
2945         if (ret != LDB_SUCCESS) {
2946                 talloc_free(tmp_ctx);
2947                 return ret;
2948         }
2949
2950         ret = check_parsed_dn_duplicates(module, el, dns);
2951         if (ret != LDB_SUCCESS) {
2952                 talloc_free(tmp_ctx);
2953                 return ret;
2954         }
2955
2956         ret = get_parsed_dns(module, tmp_ctx, old_el, &old_dns,
2957                              ldap_oid, parent);
2958         if (ret != LDB_SUCCESS) {
2959                 talloc_free(tmp_ctx);
2960                 return ret;
2961         }
2962
2963         ret = replmd_check_upgrade_links(ldb, old_dns, old_num_values,
2964                                          old_el, ldap_oid);
2965         if (ret != LDB_SUCCESS) {
2966                 talloc_free(tmp_ctx);
2967                 return ret;
2968         }
2969
2970         new_values = talloc_array(tmp_ctx, struct ldb_val, max_num_values);
2971         if (new_values == NULL) {
2972                 ldb_module_oom(module);
2973                 talloc_free(tmp_ctx);
2974                 return LDB_ERR_OPERATIONS_ERROR;
2975         }
2976
2977         old_i = 0;
2978         new_i = 0;
2979         for (i = 0; i < max_num_values; i++) {
2980                 int cmp;
2981                 struct parsed_dn *old_p, *new_p;
2982                 if (old_i < old_num_values && new_i < repl_num_values) {
2983                         old_p = &old_dns[old_i];
2984                         new_p = &dns[new_i];
2985                         cmp = parsed_dn_compare(old_p, new_p);
2986                 } else if (old_i < old_num_values) {
2987                         /* the new list is empty, read the old list */
2988                         old_p = &old_dns[old_i];
2989                         new_p = NULL;
2990                         cmp = -1;
2991                 } else if (new_i < repl_num_values) {
2992                         /* the old list is empty, read new list */
2993                         old_p = NULL;
2994                         new_p = &dns[new_i];
2995                         cmp = 1;
2996                 } else {
2997                         break;
2998                 }
2999
3000                 if (cmp < 0) {
3001                         /*
3002                          * An old ones that come before the next replacement
3003                          * (if any). We mark it as deleted and add it to the
3004                          * final list.
3005                          */
3006                         uint32_t rmd_flags = dsdb_dn_rmd_flags(old_p->dsdb_dn->dn);
3007                         if ((rmd_flags & DSDB_RMD_FLAG_DELETED) == 0) {
3008                                 ret = replmd_update_la_val(new_values, old_p->v,
3009                                                            old_p->dsdb_dn,
3010                                                            old_p->dsdb_dn,
3011                                                            invocation_id,
3012                                                            seq_num, seq_num,
3013                                                            now, true);
3014                                 if (ret != LDB_SUCCESS) {
3015                                         talloc_free(tmp_ctx);
3016                                         return ret;
3017                                 }
3018
3019                                 ret = replmd_add_backlink(module, replmd_private,
3020                                                           schema, 
3021                                                           msg_dn,
3022                                                           &old_p->guid, false,
3023                                                           schema_attr,
3024                                                           parent);
3025                                 if (ret != LDB_SUCCESS) {
3026                                         talloc_free(tmp_ctx);
3027                                         return ret;
3028                                 }
3029                         }
3030                         new_values[i] = *old_p->v;
3031                         old_i++;
3032                 } else if (cmp == 0) {
3033                         /*
3034                          * We are overwriting one. If it was previously
3035                          * deleted, we need to add a backlink.
3036                          *
3037                          * Note that if any RMD_FLAGs in an extended new DN
3038                          * will be ignored.
3039                          */
3040                         uint32_t rmd_flags;
3041
3042                         ret = replmd_update_la_val(new_values, old_p->v,
3043                                                    new_p->dsdb_dn,
3044                                                    old_p->dsdb_dn,
3045                                                    invocation_id,
3046                                                    seq_num, seq_num,
3047                                                    now, false);
3048                         if (ret != LDB_SUCCESS) {
3049                                 talloc_free(tmp_ctx);
3050                                 return ret;
3051                         }
3052
3053                         rmd_flags = dsdb_dn_rmd_flags(old_p->dsdb_dn->dn);
3054                         if ((rmd_flags & DSDB_RMD_FLAG_DELETED) != 0) {
3055                                 ret = replmd_add_backlink(module, replmd_private,
3056                                                           schema, 
3057                                                           msg_dn,
3058                                                           &new_p->guid, true,
3059                                                           schema_attr,
3060                                                           parent);
3061                                 if (ret != LDB_SUCCESS) {
3062                                         talloc_free(tmp_ctx);
3063                                         return ret;
3064                                 }
3065                         }
3066
3067                         new_values[i] = *old_p->v;
3068                         old_i++;
3069                         new_i++;
3070                 } else {
3071                         /*
3072                          * Replacements that don't match an existing one. We
3073                          * just add them to the final list.
3074                          */
3075                         ret = replmd_build_la_val(new_values,
3076                                                   new_p->v,
3077                                                   new_p->dsdb_dn,
3078                                                   invocation_id,
3079                                                   seq_num, now);
3080                         if (ret != LDB_SUCCESS) {
3081                                 talloc_free(tmp_ctx);
3082                                 return ret;
3083                         }
3084                         ret = replmd_add_backlink(module, replmd_private,
3085                                                   schema,
3086                                                   msg_dn,
3087                                                   &new_p->guid, true,
3088                                                   schema_attr,
3089                                                   parent);
3090                         if (ret != LDB_SUCCESS) {
3091                                 talloc_free(tmp_ctx);
3092                                 return ret;
3093                         }
3094                         new_values[i] = *new_p->v;
3095                         new_i++;
3096                 }
3097         }
3098         if (old_el != NULL) {
3099                 talloc_steal(msg->elements, old_el->values);
3100         }
3101         el->values = talloc_steal(msg->elements, new_values);
3102         el->num_values = i;
3103         talloc_free(tmp_ctx);
3104
3105         el->flags = LDB_FLAG_MOD_REPLACE;
3106
3107         return LDB_SUCCESS;
3108 }
3109
3110
3111 /*
3112   handle linked attributes in modify requests
3113  */
3114 static int replmd_modify_handle_linked_attribs(struct ldb_module *module,
3115                                                struct replmd_private *replmd_private,
3116                                                struct replmd_replicated_request *ac,
3117                                                struct ldb_message *msg,
3118                                                time_t t,
3119                                                struct ldb_request *parent)
3120 {
3121         struct ldb_result *res;
3122         unsigned int i;
3123         int ret;
3124         struct ldb_context *ldb = ldb_module_get_ctx(module);
3125         struct ldb_message *old_msg;
3126
3127         if (dsdb_functional_level(ldb) == DS_DOMAIN_FUNCTION_2000) {
3128                 /*
3129                  * Nothing special is required for modifying or vanishing links
3130                  * in fl2000 since they are just strings in a multi-valued
3131                  * attribute.
3132                  */
3133                 struct ldb_control *ctrl = ldb_request_get_control(parent,
3134                                                                    DSDB_CONTROL_REPLMD_VANISH_LINKS);
3135                 if (ctrl) {
3136                         ctrl->critical = false;
3137                 }
3138                 return LDB_SUCCESS;
3139         }
3140
3141         /*
3142          * TODO:
3143          *
3144          * We should restrict this to the intersection of the list of
3145          * linked attributes in the schema and the list of attributes
3146          * being modified.
3147          *
3148          * This will help performance a little, as otherwise we have
3149          * to allocate the entire object value-by-value.
3150          */
3151         ret = dsdb_module_search_dn(module, msg, &res, msg->dn, NULL,
3152                                     DSDB_FLAG_NEXT_MODULE |
3153                                     DSDB_SEARCH_SHOW_RECYCLED |
3154                                     DSDB_SEARCH_REVEAL_INTERNALS |
3155                                     DSDB_SEARCH_SHOW_DN_IN_STORAGE_FORMAT,
3156                                     parent);
3157         if (ret != LDB_SUCCESS) {
3158                 return ret;
3159         }
3160
3161         old_msg = res->msgs[0];
3162
3163         for (i=0; i<msg->num_elements; i++) {
3164                 struct ldb_message_element *el = &msg->elements[i];
3165                 struct ldb_message_element *old_el, *new_el;
3166                 unsigned int mod_type = LDB_FLAG_MOD_TYPE(el->flags);
3167                 const struct dsdb_attribute *schema_attr
3168                         = dsdb_attribute_by_lDAPDisplayName(ac->schema, el->name);
3169                 if (!schema_attr) {
3170                         ldb_asprintf_errstring(ldb,
3171                                                "%s: attribute %s is not a valid attribute in schema",
3172                                                __FUNCTION__, el->name);
3173                         return LDB_ERR_OBJECT_CLASS_VIOLATION;
3174                 }
3175                 if (schema_attr->linkID == 0) {
3176                         continue;
3177                 }
3178                 if ((schema_attr->linkID & 1) == 1) {
3179                         if (parent) {
3180                                 struct ldb_control *ctrl;
3181
3182                                 ctrl = ldb_request_get_control(parent,
3183                                                 DSDB_CONTROL_REPLMD_VANISH_LINKS);
3184                                 if (ctrl != NULL) {
3185                                         ctrl->critical = false;
3186                                         continue;
3187                                 }
3188                                 ctrl = ldb_request_get_control(parent,
3189                                                 DSDB_CONTROL_DBCHECK);
3190                                 if (ctrl != NULL) {
3191                                         continue;
3192                                 }
3193                         }
3194
3195                         /* Odd is for the target.  Illegal to modify */
3196                         ldb_asprintf_errstring(ldb,
3197                                                "attribute %s must not be modified directly, it is a linked attribute", el->name);
3198                         return LDB_ERR_UNWILLING_TO_PERFORM;
3199                 }
3200                 old_el = ldb_msg_find_element(old_msg, el->name);
3201                 switch (mod_type) {
3202                 case LDB_FLAG_MOD_REPLACE:
3203                         ret = replmd_modify_la_replace(module, replmd_private,
3204                                                        ac->schema, msg, el, old_el,
3205                                                        schema_attr, ac->seq_num, t,
3206                                                        old_msg->dn,
3207                                                        parent);
3208                         break;
3209                 case LDB_FLAG_MOD_DELETE:
3210                         ret = replmd_modify_la_delete(module, replmd_private,
3211                                                       ac->schema, msg, el, old_el,
3212                                                       schema_attr, ac->seq_num, t,
3213                                                       old_msg->dn,
3214                                                       parent);
3215                         break;
3216                 case LDB_FLAG_MOD_ADD:
3217                         ret = replmd_modify_la_add(module, replmd_private,
3218                                                    ac, msg, el, old_el,
3219                                                    schema_attr, t,
3220                                                    old_msg->dn,
3221                                                    parent);
3222                         break;
3223                 default:
3224                         ldb_asprintf_errstring(ldb,
3225                                                "invalid flags 0x%x for %s linked attribute",
3226                                                el->flags, el->name);
3227                         return LDB_ERR_UNWILLING_TO_PERFORM;
3228                 }
3229                 if (dsdb_check_single_valued_link(schema_attr, el) != LDB_SUCCESS) {
3230                         ldb_asprintf_errstring(ldb,
3231                                                "Attribute %s is single valued but more than one value has been supplied",
3232                                                el->name);
3233                         /* Return codes as found on Windows 2012r2 */
3234                         if (mod_type == LDB_FLAG_MOD_REPLACE) {
3235                                 return LDB_ERR_CONSTRAINT_VIOLATION;
3236                         } else {
3237                                 return LDB_ERR_ATTRIBUTE_OR_VALUE_EXISTS;
3238                         }
3239                 } else {
3240                         el->flags |= LDB_FLAG_INTERNAL_DISABLE_SINGLE_VALUE_CHECK;
3241                 }
3242
3243                 if (ret != LDB_SUCCESS) {
3244                         return ret;
3245                 }
3246                 if (old_el) {
3247                         ldb_msg_remove_attr(old_msg, el->name);
3248                 }
3249                 ldb_msg_add_empty(old_msg, el->name, 0, &new_el);
3250                 new_el->num_values = el->num_values;
3251                 new_el->values = talloc_steal(msg->elements, el->values);
3252
3253                 /* TODO: this relises a bit too heavily on the exact
3254                    behaviour of ldb_msg_find_element and
3255                    ldb_msg_remove_element */
3256                 old_el = ldb_msg_find_element(msg, el->name);
3257                 if (old_el != el) {
3258                         ldb_msg_remove_element(msg, old_el);
3259                         i--;
3260                 }
3261         }
3262
3263         talloc_free(res);
3264         return ret;
3265 }
3266
3267
3268 static int send_rodc_referral(struct ldb_request *req,
3269                               struct ldb_context *ldb,
3270                               struct ldb_dn *dn)
3271 {
3272         char *referral = NULL;
3273         struct loadparm_context *lp_ctx = NULL;
3274         struct ldb_dn *fsmo_role_dn = NULL;
3275         struct ldb_dn *role_owner_dn = NULL;
3276         const char *domain = NULL;
3277         WERROR werr;
3278
3279         lp_ctx = talloc_get_type(ldb_get_opaque(ldb, "loadparm"),
3280                                  struct loadparm_context);
3281
3282         werr = dsdb_get_fsmo_role_info(req, ldb, DREPL_PDC_MASTER,
3283                                        &fsmo_role_dn, &role_owner_dn);
3284
3285         if (W_ERROR_IS_OK(werr)) {
3286                 struct ldb_dn *server_dn = ldb_dn_copy(req, role_owner_dn);
3287                 if (server_dn != NULL) {
3288                         ldb_dn_remove_child_components(server_dn, 1);
3289                         domain = samdb_dn_to_dnshostname(ldb, req,
3290                                                          server_dn);
3291                 }
3292         }
3293
3294         if (domain == NULL) {
3295                 domain = lpcfg_dnsdomain(lp_ctx);
3296         }
3297
3298         referral = talloc_asprintf(req, "ldap://%s/%s",
3299                                    domain,
3300                                    ldb_dn_get_linearized(dn));
3301         if (referral == NULL) {
3302                 ldb_oom(ldb);
3303                 return LDB_ERR_OPERATIONS_ERROR;
3304         }
3305
3306         return ldb_module_send_referral(req, referral);
3307 }
3308
3309
3310 static int replmd_modify(struct ldb_module *module, struct ldb_request *req)
3311 {
3312         struct ldb_context *ldb;
3313         struct replmd_replicated_request *ac;
3314         struct ldb_request *down_req;
3315         struct ldb_message *msg;
3316         time_t t = time(NULL);
3317         int ret;
3318         bool is_urgent = false, rodc = false;
3319         bool is_schema_nc = false;
3320         unsigned int functional_level;
3321         const struct ldb_message_element *guid_el = NULL;
3322         struct ldb_control *sd_propagation_control;
3323         struct ldb_control *fix_links_control = NULL;
3324         struct ldb_control *fix_dn_name_control = NULL;
3325         struct replmd_private *replmd_private =
3326                 talloc_get_type(ldb_module_get_private(module), struct replmd_private);
3327
3328         /* do not manipulate our control entries */
3329         if (ldb_dn_is_special(req->op.mod.message->dn)) {
3330                 return ldb_next_request(module, req);
3331         }
3332
3333         sd_propagation_control = ldb_request_get_control(req,
3334                                         DSDB_CONTROL_SEC_DESC_PROPAGATION_OID);
3335         if (sd_propagation_control != NULL) {
3336                 if (req->op.mod.message->num_elements != 1) {
3337                         return ldb_module_operr(module);
3338                 }
3339                 ret = strcmp(req->op.mod.message->elements[0].name,
3340                              "nTSecurityDescriptor");
3341                 if (ret != 0) {
3342                         return ldb_module_operr(module);
3343                 }
3344
3345                 return ldb_next_request(module, req);
3346         }
3347
3348         ldb = ldb_module_get_ctx(module);
3349
3350         fix_links_control = ldb_request_get_control(req,
3351                                         DSDB_CONTROL_DBCHECK_FIX_DUPLICATE_LINKS);
3352         if (fix_links_control != NULL) {
3353                 struct dsdb_schema *schema = NULL;
3354                 const struct dsdb_attribute *sa = NULL;
3355
3356                 if (req->op.mod.message->num_elements != 1) {
3357                         return ldb_module_operr(module);
3358                 }
3359
3360                 if (req->op.mod.message->elements[0].flags != LDB_FLAG_MOD_REPLACE) {
3361                         return ldb_module_operr(module);
3362                 }
3363
3364                 schema = dsdb_get_schema(ldb, req);
3365                 if (schema == NULL) {
3366                         return ldb_module_operr(module);
3367                 }
3368
3369                 sa = dsdb_attribute_by_lDAPDisplayName(schema,
3370                                 req->op.mod.message->elements[0].name);
3371                 if (sa == NULL) {
3372                         return ldb_module_operr(module);
3373                 }
3374
3375                 if (sa->linkID == 0) {
3376                         return ldb_module_operr(module);
3377                 }
3378
3379                 fix_links_control->critical = false;
3380                 return ldb_next_request(module, req);
3381         }
3382
3383         fix_dn_name_control = ldb_request_get_control(req,
3384                                         DSDB_CONTROL_DBCHECK_FIX_LINK_DN_NAME);
3385         if (fix_dn_name_control != NULL) {
3386                 struct dsdb_schema *schema = NULL;
3387                 const struct dsdb_attribute *sa = NULL;
3388
3389                 if (req->op.mod.message->num_elements != 2) {
3390                         return ldb_module_operr(module);
3391                 }
3392
3393                 if (req->op.mod.message->elements[0].flags != LDB_FLAG_MOD_DELETE) {
3394                         return ldb_module_operr(module);
3395                 }
3396
3397                 if (req->op.mod.message->elements[1].flags != LDB_FLAG_MOD_ADD) {
3398                         return ldb_module_operr(module);
3399                 }
3400
3401                 if (req->op.mod.message->elements[0].num_values != 1) {
3402                         return ldb_module_operr(module);
3403                 }
3404
3405                 if (req->op.mod.message->elements[1].num_values != 1) {
3406                         return ldb_module_operr(module);
3407                 }
3408
3409                 schema = dsdb_get_schema(ldb, req);
3410                 if (schema == NULL) {
3411                         return ldb_module_operr(module);
3412                 }
3413
3414                 if (ldb_attr_cmp(req->op.mod.message->elements[0].name,
3415                                  req->op.mod.message->elements[1].name) != 0) {
3416                         return ldb_module_operr(module);
3417                 }
3418
3419                 sa = dsdb_attribute_by_lDAPDisplayName(schema,
3420                                 req->op.mod.message->elements[0].name);
3421                 if (sa == NULL) {
3422                         return ldb_module_operr(module);
3423                 }
3424
3425                 if (sa->dn_format == DSDB_INVALID_DN) {
3426                         return ldb_module_operr(module);
3427                 }
3428
3429                 if (sa->linkID != 0) {
3430                         return ldb_module_operr(module);
3431                 }
3432
3433                 /*
3434                  * If we are run from dbcheck and we are not updating
3435                  * a link (as these would need to be sorted and so
3436                  * can't go via such a simple update, then do not
3437                  * trigger replicated updates and a new USN from this
3438                  * change, it wasn't a real change, just a new
3439                  * (correct) string DN
3440                  */
3441
3442                 fix_dn_name_control->critical = false;
3443                 return ldb_next_request(module, req);
3444         }
3445
3446         ldb_debug(ldb, LDB_DEBUG_TRACE, "replmd_modify\n");
3447
3448         guid_el = ldb_msg_find_element(req->op.mod.message, "objectGUID");
3449         if (guid_el != NULL) {
3450                 ldb_set_errstring(ldb,
3451                                   "replmd_modify: it's not allowed to change the objectGUID!");
3452                 return LDB_ERR_CONSTRAINT_VIOLATION;
3453         }
3454
3455         ac = replmd_ctx_init(module, req);
3456         if (ac == NULL) {
3457                 return ldb_module_oom(module);
3458         }
3459
3460         functional_level = dsdb_functional_level(ldb);
3461
3462         /* we have to copy the message as the caller might have it as a const */
3463         msg = ldb_msg_copy_shallow(ac, req->op.mod.message);
3464         if (msg == NULL) {
3465                 ldb_oom(ldb);
3466                 talloc_free(ac);
3467                 return LDB_ERR_OPERATIONS_ERROR;
3468         }
3469
3470         ldb_msg_remove_attr(msg, "whenChanged");
3471         ldb_msg_remove_attr(msg, "uSNChanged");
3472
3473         is_schema_nc = ldb_dn_compare_base(replmd_private->schema_dn, msg->dn) == 0;
3474
3475         ret = replmd_update_rpmd(module, ac->schema, req, NULL,
3476                                  msg, &ac->seq_num, t, is_schema_nc,
3477                                  &is_urgent, &rodc);
3478         if (rodc && (ret == LDB_ERR_REFERRAL)) {
3479                 ret = send_rodc_referral(req, ldb, msg->dn);
3480                 talloc_free(ac);
3481                 return ret;
3482
3483         }
3484
3485         if (ret != LDB_SUCCESS) {
3486                 talloc_free(ac);
3487                 return ret;
3488         }
3489
3490         ret = replmd_modify_handle_linked_attribs(module, replmd_private,
3491                                                   ac, msg, t, req);
3492         if (ret != LDB_SUCCESS) {
3493                 talloc_free(ac);
3494                 return ret;
3495         }
3496
3497         /* TODO:
3498          * - replace the old object with the newly constructed one
3499          */
3500
3501         ac->is_urgent = is_urgent;
3502
3503         ret = ldb_build_mod_req(&down_req, ldb, ac,
3504                                 msg,
3505                                 req->controls,
3506                                 ac, replmd_op_callback,
3507                                 req);
3508         LDB_REQ_SET_LOCATION(down_req);
3509         if (ret != LDB_SUCCESS) {
3510                 talloc_free(ac);
3511                 return ret;
3512         }
3513
3514         /* current partition control is needed by "replmd_op_callback" */
3515         if (ldb_request_get_control(req, DSDB_CONTROL_CURRENT_PARTITION_OID) == NULL) {
3516                 ret = ldb_request_add_control(down_req,
3517                                               DSDB_CONTROL_CURRENT_PARTITION_OID,
3518                                               false, NULL);
3519                 if (ret != LDB_SUCCESS) {
3520                         talloc_free(ac);
3521                         return ret;
3522                 }
3523         }
3524
3525         /* If we are in functional level 2000, then
3526          * replmd_modify_handle_linked_attribs will have done
3527          * nothing */
3528         if (functional_level == DS_DOMAIN_FUNCTION_2000) {
3529                 ret = ldb_request_add_control(down_req, DSDB_CONTROL_APPLY_LINKS, false, NULL);
3530                 if (ret != LDB_SUCCESS) {
3531                         talloc_free(ac);
3532                         return ret;
3533                 }
3534         }
3535
3536         talloc_steal(down_req, msg);
3537
3538         /* we only change whenChanged and uSNChanged if the seq_num
3539            has changed */
3540         if (ac->seq_num != 0) {
3541                 ret = add_time_element(msg, "whenChanged", t);
3542                 if (ret != LDB_SUCCESS) {
3543                         talloc_free(ac);
3544                         ldb_operr(ldb);
3545                         return ret;
3546                 }
3547
3548                 ret = add_uint64_element(ldb, msg, "uSNChanged", ac->seq_num);
3549                 if (ret != LDB_SUCCESS) {
3550                         talloc_free(ac);
3551                         ldb_operr(ldb);
3552                         return ret;
3553                 }
3554         }
3555
3556         /* go on with the call chain */
3557         return ldb_next_request(module, down_req);
3558 }
3559
3560 static int replmd_rename_callback(struct ldb_request *req, struct ldb_reply *ares);
3561
3562 /*
3563   handle a rename request
3564
3565   On a rename we need to do an extra ldb_modify which sets the
3566   whenChanged and uSNChanged attributes.  We do this in a callback after the success.
3567  */
3568 static int replmd_rename(struct ldb_module *module, struct ldb_request *req)
3569 {
3570         struct ldb_context *ldb;
3571         struct replmd_replicated_request *ac;
3572         int ret;
3573         struct ldb_request *down_req;
3574
3575         /* do not manipulate our control entries */
3576         if (ldb_dn_is_special(req->op.mod.message->dn)) {
3577                 return ldb_next_request(module, req);
3578         }
3579
3580         ldb = ldb_module_get_ctx(module);
3581
3582         ldb_debug(ldb, LDB_DEBUG_TRACE, "replmd_rename\n");
3583
3584         ac = replmd_ctx_init(module, req);
3585         if (ac == NULL) {
3586                 return ldb_module_oom(module);
3587         }
3588
3589         ret = ldb_build_rename_req(&down_req, ldb, ac,
3590                                    ac->req->op.rename.olddn,
3591                                    ac->req->op.rename.newdn,
3592                                    ac->req->controls,
3593                                    ac, replmd_rename_callback,
3594                                    ac->req);
3595         LDB_REQ_SET_LOCATION(down_req);
3596         if (ret != LDB_SUCCESS) {
3597                 talloc_free(ac);
3598                 return ret;
3599         }
3600
3601         /* go on with the call chain */
3602         return ldb_next_request(module, down_req);
3603 }
3604
3605 /* After the rename is compleated, update the whenchanged etc */
3606 static int replmd_rename_callback(struct ldb_request *req, struct ldb_reply *ares)
3607 {
3608         struct ldb_context *ldb;
3609         struct ldb_request *down_req;
3610         struct ldb_message *msg;
3611         const struct dsdb_attribute *rdn_attr;
3612         const char *rdn_name;
3613         const struct ldb_val *rdn_val;
3614         const char *attrs[5] = { NULL, };
3615         time_t t = time(NULL);
3616         int ret;
3617         bool is_urgent = false, rodc = false;
3618         bool is_schema_nc;
3619         struct replmd_replicated_request *ac =
3620                 talloc_get_type(req->context, struct replmd_replicated_request);
3621         struct replmd_private *replmd_private =
3622                 talloc_get_type(ldb_module_get_private(ac->module),
3623                                 struct replmd_private);
3624
3625         ldb = ldb_module_get_ctx(ac->module);
3626
3627         if (ares->error != LDB_SUCCESS) {
3628                 return ldb_module_done(ac->req, ares->controls,
3629                                         ares->response, ares->error);
3630         }
3631
3632         if (ares->type != LDB_REPLY_DONE) {
3633                 ldb_set_errstring(ldb,
3634                                   "invalid ldb_reply_type in callback");
3635                 talloc_free(ares);
3636                 return ldb_module_done(ac->req, NULL, NULL,
3637                                         LDB_ERR_OPERATIONS_ERROR);
3638         }
3639
3640         /* TODO:
3641          * - replace the old object with the newly constructed one
3642          */
3643
3644         msg = ldb_msg_new(ac);
3645         if (msg == NULL) {
3646                 ldb_oom(ldb);
3647                 return LDB_ERR_OPERATIONS_ERROR;
3648         }
3649
3650         msg->dn = ac->req->op.rename.newdn;
3651
3652         is_schema_nc = ldb_dn_compare_base(replmd_private->schema_dn, msg->dn) == 0;
3653
3654         rdn_name = ldb_dn_get_rdn_name(msg->dn);
3655         if (rdn_name == NULL) {
3656                 talloc_free(ares);
3657                 return ldb_module_done(ac->req, NULL, NULL,
3658                                        ldb_operr(ldb));
3659         }
3660
3661         /* normalize the rdn attribute name */
3662         rdn_attr = dsdb_attribute_by_lDAPDisplayName(ac->schema, rdn_name);
3663         if (rdn_attr == NULL) {
3664                 talloc_free(ares);
3665                 return ldb_module_done(ac->req, NULL, NULL,
3666                                        ldb_operr(ldb));
3667         }
3668         rdn_name = rdn_attr->lDAPDisplayName;
3669
3670         rdn_val = ldb_dn_get_rdn_val(msg->dn);
3671         if (rdn_val == NULL) {
3672                 talloc_free(ares);
3673                 return ldb_module_done(ac->req, NULL, NULL,
3674                                        ldb_operr(ldb));
3675         }
3676
3677         if (ldb_msg_add_empty(msg, rdn_name, LDB_FLAG_MOD_REPLACE, NULL) != 0) {
3678                 talloc_free(ares);
3679                 return ldb_module_done(ac->req, NULL, NULL,
3680                                        ldb_oom(ldb));
3681         }
3682         if (ldb_msg_add_value(msg, rdn_name, rdn_val, NULL) != 0) {
3683                 talloc_free(ares);
3684                 return ldb_module_done(ac->req, NULL, NULL,
3685                                        ldb_oom(ldb));
3686         }
3687         if (ldb_msg_add_empty(msg, "name", LDB_FLAG_MOD_REPLACE, NULL) != 0) {
3688                 talloc_free(ares);
3689                 return ldb_module_done(ac->req, NULL, NULL,
3690                                        ldb_oom(ldb));
3691         }
3692         if (ldb_msg_add_value(msg, "name", rdn_val, NULL) != 0) {
3693                 talloc_free(ares);
3694                 return ldb_module_done(ac->req, NULL, NULL,
3695                                        ldb_oom(ldb));
3696         }
3697
3698         /*
3699          * here we let replmd_update_rpmd() only search for
3700          * the existing "replPropertyMetaData" and rdn_name attributes.
3701          *
3702          * We do not want the existing "name" attribute as
3703          * the "name" attribute needs to get the version
3704          * updated on rename even if the rdn value hasn't changed.
3705          *
3706          * This is the diff of the meta data, for a moved user
3707          * on a w2k8r2 server:
3708          *
3709          * # record 1
3710          * -dn: CN=sdf df,CN=Users,DC=bla,DC=base
3711          * +dn: CN=sdf df,OU=TestOU,DC=bla,DC=base
3712          *  replPropertyMetaData:     NDR: struct replPropertyMetaDataBlob
3713          *         version                  : 0x00000001 (1)
3714          *         reserved                 : 0x00000000 (0)
3715          * @@ -66,11 +66,11 @@ replPropertyMetaData:     NDR: struct re
3716          *                      local_usn                : 0x00000000000037a5 (14245)
3717          *                 array: struct replPropertyMetaData1
3718          *                      attid                    : DRSUAPI_ATTID_name (0x90001)
3719          * -                    version                  : 0x00000001 (1)
3720          * -                    originating_change_time  : Wed Feb  9 17:20:49 2011 CET
3721          * +                    version                  : 0x00000002 (2)
3722          * +                    originating_change_time  : Wed Apr  6 15:21:01 2011 CEST
3723          *                      originating_invocation_id: 0d36ca05-5507-4e62-aca3-354bab0d39e1
3724          * -                    originating_usn          : 0x00000000000037a5 (14245)
3725          * -                    local_usn                : 0x00000000000037a5 (14245)
3726          * +                    originating_usn          : 0x0000000000003834 (14388)
3727          * +                    local_usn                : 0x0000000000003834 (14388)
3728          *                 array: struct replPropertyMetaData1
3729          *                      attid                    : DRSUAPI_ATTID_userAccountControl (0x90008)
3730          *                      version                  : 0x00000004 (4)
3731          */
3732         attrs[0] = "replPropertyMetaData";
3733         attrs[1] = "objectClass";
3734         attrs[2] = "instanceType";
3735         attrs[3] = rdn_name;
3736         attrs[4] = NULL;
3737
3738         ret = replmd_update_rpmd(ac->module, ac->schema, req, attrs,
3739                                  msg, &ac->seq_num, t,
3740                                  is_schema_nc, &is_urgent, &rodc);
3741         if (rodc && (ret == LDB_ERR_REFERRAL)) {
3742                 ret = send_rodc_referral(req, ldb, ac->req->op.rename.olddn);
3743                 talloc_free(ares);
3744                 return ldb_module_done(req, NULL, NULL, ret);
3745         }
3746
3747         if (ret != LDB_SUCCESS) {
3748                 talloc_free(ares);
3749                 return ldb_module_done(ac->req, NULL, NULL, ret);
3750         }
3751
3752         if (ac->seq_num == 0) {
3753                 talloc_free(ares);
3754                 return ldb_module_done(ac->req, NULL, NULL,
3755                                        ldb_error(ldb, ret,
3756                                         "internal error seq_num == 0"));
3757         }
3758         ac->is_urgent = is_urgent;
3759
3760         ret = ldb_build_mod_req(&down_req, ldb, ac,
3761                                 msg,
3762                                 req->controls,
3763                                 ac, replmd_op_callback,
3764                                 req);
3765         LDB_REQ_SET_LOCATION(down_req);
3766         if (ret != LDB_SUCCESS) {
3767                 talloc_free(ac);
3768                 return ret;
3769         }
3770
3771         /* current partition control is needed by "replmd_op_callback" */
3772         if (ldb_request_get_control(req, DSDB_CONTROL_CURRENT_PARTITION_OID) == NULL) {
3773                 ret = ldb_request_add_control(down_req,
3774                                               DSDB_CONTROL_CURRENT_PARTITION_OID,
3775                                               false, NULL);
3776                 if (ret != LDB_SUCCESS) {
3777                         talloc_free(ac);
3778                         return ret;
3779                 }
3780         }
3781
3782         talloc_steal(down_req, msg);
3783
3784         ret = add_time_element(msg, "whenChanged", t);
3785         if (ret != LDB_SUCCESS) {
3786                 talloc_free(ac);
3787                 ldb_operr(ldb);
3788                 return ret;
3789         }
3790
3791         ret = add_uint64_element(ldb, msg, "uSNChanged", ac->seq_num);
3792         if (ret != LDB_SUCCESS) {
3793                 talloc_free(ac);
3794                 ldb_operr(ldb);
3795                 return ret;
3796         }
3797
3798         /* go on with the call chain - do the modify after the rename */
3799         return ldb_next_request(ac->module, down_req);
3800 }
3801
3802 /*
3803  * remove links from objects that point at this object when an object
3804  * is deleted.  We remove it from the NEXT module per MS-DRSR 5.160
3805  * RemoveObj which states that link removal due to the object being
3806  * deleted is NOT an originating update - they just go away!
3807  *
3808  */
3809 static int replmd_delete_remove_link(struct ldb_module *module,
3810                                      const struct dsdb_schema *schema,
3811                                      struct replmd_private *replmd_private,
3812                                      struct ldb_dn *dn,
3813                                      struct GUID *guid,
3814                                      struct ldb_message_element *el,
3815                                      const struct dsdb_attribute *sa,
3816                                      struct ldb_request *parent)
3817 {
3818         unsigned int i;
3819         TALLOC_CTX *tmp_ctx = talloc_new(module);
3820         struct ldb_context *ldb = ldb_module_get_ctx(module);
3821
3822         for (i=0; i<el->num_values; i++) {
3823                 struct dsdb_dn *dsdb_dn;
3824                 int ret;
3825                 struct ldb_message *msg;
3826                 const struct dsdb_attribute *target_attr;
3827                 struct ldb_message_element *el2;
3828                 const char *dn_str;
3829                 struct ldb_val dn_val;
3830                 uint32_t dsdb_flags = 0;
3831                 const char *attrs[] = { NULL, NULL };
3832                 struct ldb_result *link_res;
3833                 struct ldb_message *link_msg;
3834                 struct ldb_message_element *link_el;
3835                 struct parsed_dn *link_dns;
3836                 struct parsed_dn *p = NULL, *unused = NULL;
3837
3838                 if (dsdb_dn_is_deleted_val(&el->values[i])) {
3839                         continue;
3840                 }
3841
3842                 dsdb_dn = dsdb_dn_parse(tmp_ctx, ldb, &el->values[i], sa->syntax->ldap_oid);
3843                 if (!dsdb_dn) {
3844                         talloc_free(tmp_ctx);
3845                         return LDB_ERR_OPERATIONS_ERROR;
3846                 }
3847
3848                 /* remove the link */
3849                 msg = ldb_msg_new(tmp_ctx);
3850                 if (!msg) {
3851                         ldb_module_oom(module);
3852                         talloc_free(tmp_ctx);
3853                         return LDB_ERR_OPERATIONS_ERROR;
3854                 }
3855
3856
3857                 msg->dn = dsdb_dn->dn;
3858
3859                 target_attr = dsdb_attribute_by_linkID(schema, sa->linkID ^ 1);
3860                 if (target_attr == NULL) {
3861                         continue;
3862                 }
3863                 attrs[0] = target_attr->lDAPDisplayName;
3864
3865                 ret = ldb_msg_add_empty(msg, target_attr->lDAPDisplayName,
3866                                         LDB_FLAG_MOD_DELETE, &el2);
3867                 if (ret != LDB_SUCCESS) {
3868                         ldb_module_oom(module);
3869                         talloc_free(tmp_ctx);
3870                         return LDB_ERR_OPERATIONS_ERROR;
3871                 }
3872
3873                 ret = dsdb_module_search_dn(module, tmp_ctx, &link_res,
3874                                             msg->dn, attrs,
3875                                             DSDB_FLAG_NEXT_MODULE |
3876                                             DSDB_SEARCH_SHOW_EXTENDED_DN |
3877                                             DSDB_SEARCH_SHOW_RECYCLED,
3878                                             parent);
3879
3880                 if (ret != LDB_SUCCESS) {
3881                         talloc_free(tmp_ctx);
3882                         return ret;
3883                 }
3884
3885                 link_msg = link_res->msgs[0];
3886                 link_el = ldb_msg_find_element(link_msg,
3887                                                target_attr->lDAPDisplayName);
3888                 if (link_el == NULL) {
3889                         talloc_free(tmp_ctx);
3890                         return LDB_ERR_NO_SUCH_ATTRIBUTE;
3891                 }
3892
3893                 /*
3894                  * This call 'upgrades' the links in link_dns, but we
3895                  * do not commit the result back into the database, so
3896                  * this is safe to call in FL2000 or on databases that
3897                  * have been run at that level in the past.
3898                  */
3899                 ret = get_parsed_dns_trusted(module, replmd_private, tmp_ctx,
3900                                              link_el, &link_dns,
3901                                              target_attr->syntax->ldap_oid, parent);
3902                 if (ret != LDB_SUCCESS) {
3903                         talloc_free(tmp_ctx);
3904                         return ret;
3905                 }
3906
3907                 ret = parsed_dn_find(ldb, link_dns, link_el->num_values,
3908                                      guid, dn,
3909                                      data_blob_null, 0,
3910                                      &p, &unused,
3911                                      target_attr->syntax->ldap_oid, false);
3912                 if (ret != LDB_SUCCESS) {
3913                         talloc_free(tmp_ctx);
3914                         return ret;
3915                 }
3916
3917                 if (p == NULL) {
3918                         ldb_asprintf_errstring(ldb_module_get_ctx(module),
3919                                                "Failed to find forward link on %s "
3920                                                "as %s to remove backlink %s on %s",
3921                                                ldb_dn_get_linearized(msg->dn),
3922                                                target_attr->lDAPDisplayName,
3923                                                sa->lDAPDisplayName,
3924                                                ldb_dn_get_linearized(dn));
3925                         talloc_free(tmp_ctx);
3926                         return LDB_ERR_NO_SUCH_ATTRIBUTE;
3927                 }
3928
3929
3930                 /* This needs to get the Binary DN, by first searching */
3931                 dn_str = dsdb_dn_get_linearized(tmp_ctx,
3932                                                 p->dsdb_dn);
3933
3934                 dn_val = data_blob_string_const(dn_str);
3935                 el2->values = &dn_val;
3936                 el2->num_values = 1;
3937
3938                 /*
3939                  * Ensure that we tell the modification to vanish any linked
3940                  * attributes (not simply mark them as isDeleted = TRUE)
3941                  */
3942                 dsdb_flags |= DSDB_REPLMD_VANISH_LINKS;
3943
3944                 ret = dsdb_module_modify(module, msg, dsdb_flags|DSDB_FLAG_OWN_MODULE, parent);
3945                 if (ret != LDB_SUCCESS) {
3946                         talloc_free(tmp_ctx);
3947                         return ret;
3948                 }
3949         }
3950         talloc_free(tmp_ctx);
3951         return LDB_SUCCESS;
3952 }
3953
3954
3955 /*
3956   handle update of replication meta data for deletion of objects
3957
3958   This also handles the mapping of delete to a rename operation
3959   to allow deletes to be replicated.
3960
3961   It also handles the incoming deleted objects, to ensure they are
3962   fully deleted here.  In that case re_delete is true, and we do not
3963   use this as a signal to change the deleted state, just reinforce it.
3964
3965  */
3966 static int replmd_delete_internals(struct ldb_module *module, struct ldb_request *req, bool re_delete)
3967 {
3968         int ret = LDB_ERR_OTHER;
3969         bool retb, disallow_move_on_delete;
3970         struct ldb_dn *old_dn = NULL, *new_dn = NULL;
3971         const char *rdn_name;
3972         const struct ldb_val *rdn_value, *new_rdn_value;
3973         struct GUID guid;
3974         struct ldb_context *ldb = ldb_module_get_ctx(module);
3975         const struct dsdb_schema *schema;
3976         struct ldb_message *msg, *old_msg;
3977         struct ldb_message_element *el;
3978         TALLOC_CTX *tmp_ctx;
3979         struct ldb_result *res, *parent_res;
3980         static const char * const preserved_attrs[] = {
3981                 /* yes, this really is a hard coded list. See MS-ADTS
3982                    section 3.1.1.5.5.1.1 */
3983                 "attributeID",
3984                 "attributeSyntax",
3985                 "dNReferenceUpdate",
3986                 "dNSHostName",
3987                 "flatName",
3988                 "governsID",
3989                 "groupType",
3990                 "instanceType",
3991                 "lDAPDisplayName",
3992                 "legacyExchangeDN",
3993                 "isDeleted",
3994                 "isRecycled",
3995                 "lastKnownParent",
3996                 "msDS-LastKnownRDN",
3997                 "msDS-PortLDAP",
3998                 "mS-DS-CreatorSID",
3999                 "mSMQOwnerID",
4000                 "nCName",
4001                 "objectClass",
4002                 "distinguishedName",
4003                 "objectGUID",
4004                 "objectSid",
4005                 "oMSyntax",
4006                 "proxiedObjectName",
4007                 "name",
4008                 "nTSecurityDescriptor",
4009                 "replPropertyMetaData",
4010                 "sAMAccountName",
4011                 "securityIdentifier",
4012                 "sIDHistory",
4013                 "subClassOf",
4014                 "systemFlags",
4015                 "trustPartner",
4016                 "trustDirection",
4017                 "trustType",
4018                 "trustAttributes",
4019                 "userAccountControl",
4020                 "uSNChanged",
4021                 "uSNCreated",
4022                 "whenCreated",
4023                 "whenChanged",
4024                 NULL
4025         };
4026         static const char * const all_attrs[] = {
4027                 DSDB_SECRET_ATTRIBUTES,
4028                 "*",
4029                 NULL
4030         };
4031         static const struct ldb_val true_val = {
4032                 .data = discard_const_p(uint8_t, "TRUE"),
4033                 .length = 4
4034         };
4035         
4036         unsigned int i;
4037         uint32_t dsdb_flags = 0;
4038         struct replmd_private *replmd_private;
4039         enum deletion_state deletion_state, next_deletion_state;
4040
4041         if (ldb_dn_is_special(req->op.del.dn)) {
4042                 return ldb_next_request(module, req);
4043         }
4044
4045         /*
4046          * We have to allow dbcheck to remove an object that
4047          * is beyond repair, and to do so totally.  This could
4048          * mean we we can get a partial object from the other
4049          * DC, causing havoc, so dbcheck suggests
4050          * re-replication first.  dbcheck sets both DBCHECK
4051          * and RELAX in this situation.
4052          */
4053         if (ldb_request_get_control(req, LDB_CONTROL_RELAX_OID)
4054             && ldb_request_get_control(req, DSDB_CONTROL_DBCHECK)) {
4055                 /* really, really remove it */
4056                 return ldb_next_request(module, req);
4057         }
4058
4059         tmp_ctx = talloc_new(ldb);
4060         if (!tmp_ctx) {
4061                 ldb_oom(ldb);
4062                 return LDB_ERR_OPERATIONS_ERROR;
4063         }
4064
4065         schema = dsdb_get_schema(ldb, tmp_ctx);
4066         if (!schema) {
4067                 talloc_free(tmp_ctx);
4068                 return LDB_ERR_OPERATIONS_ERROR;
4069         }
4070
4071         old_dn = ldb_dn_copy(tmp_ctx, req->op.del.dn);
4072
4073         /* we need the complete msg off disk, so we can work out which
4074            attributes need to be removed */
4075         ret = dsdb_module_search_dn(module, tmp_ctx, &res, old_dn, all_attrs,
4076                                     DSDB_FLAG_NEXT_MODULE |
4077                                     DSDB_SEARCH_SHOW_RECYCLED |
4078                                     DSDB_SEARCH_REVEAL_INTERNALS |
4079                                     DSDB_SEARCH_SHOW_DN_IN_STORAGE_FORMAT, req);
4080         if (ret != LDB_SUCCESS) {
4081                 ldb_asprintf_errstring(ldb_module_get_ctx(module),
4082                                        "repmd_delete: Failed to %s %s, because we failed to find it: %s",
4083                                        re_delete ? "re-delete" : "delete",
4084                                        ldb_dn_get_linearized(old_dn),
4085                                        ldb_errstring(ldb_module_get_ctx(module)));
4086                 talloc_free(tmp_ctx);
4087                 return ret;
4088         }
4089         old_msg = res->msgs[0];
4090
4091         replmd_deletion_state(module, old_msg,
4092                               &deletion_state,
4093                               &next_deletion_state);
4094
4095         /* This supports us noticing an incoming isDeleted and acting on it */
4096         if (re_delete) {
4097                 SMB_ASSERT(deletion_state > OBJECT_NOT_DELETED);
4098                 next_deletion_state = deletion_state;
4099         }
4100
4101         if (next_deletion_state == OBJECT_REMOVED) {
4102                 /*
4103                  * We have to prevent objects being deleted, even if
4104                  * the administrator really wants them gone, as
4105                  * without the tombstone, we can get a partial object
4106                  * from the other DC, causing havoc.
4107                  *
4108                  * The only other valid case is when the 180 day
4109                  * timeout has expired, when relax is specified.
4110                  */
4111                 if (ldb_request_get_control(req, LDB_CONTROL_RELAX_OID)) {
4112                         /* it is already deleted - really remove it this time */
4113                         talloc_free(tmp_ctx);
4114                         return ldb_next_request(module, req);
4115                 }
4116
4117                 ldb_asprintf_errstring(ldb, "Refusing to delete tombstone object %s.  "
4118                                        "This check is to prevent corruption of the replicated state.",
4119                                        ldb_dn_get_linearized(old_msg->dn));
4120                 return LDB_ERR_UNWILLING_TO_PERFORM;
4121         }
4122
4123         rdn_name = ldb_dn_get_rdn_name(old_dn);
4124         rdn_value = ldb_dn_get_rdn_val(old_dn);
4125         if ((rdn_name == NULL) || (rdn_value == NULL)) {
4126                 talloc_free(tmp_ctx);
4127                 return ldb_operr(ldb);
4128         }
4129
4130         msg = ldb_msg_new(tmp_ctx);
4131         if (msg == NULL) {
4132                 ldb_module_oom(module);
4133                 talloc_free(tmp_ctx);
4134                 return LDB_ERR_OPERATIONS_ERROR;
4135         }
4136
4137         msg->dn = old_dn;
4138
4139         /* consider the SYSTEM_FLAG_DISALLOW_MOVE_ON_DELETE flag */
4140         disallow_move_on_delete =
4141                 (ldb_msg_find_attr_as_int(old_msg, "systemFlags", 0)
4142                  & SYSTEM_FLAG_DISALLOW_MOVE_ON_DELETE);
4143
4144         /* work out where we will be renaming this object to */
4145         if (!disallow_move_on_delete) {
4146                 struct ldb_dn *deleted_objects_dn;
4147                 ret = dsdb_get_deleted_objects_dn(ldb, tmp_ctx, old_dn,
4148                                                   &deleted_objects_dn);
4149
4150                 /*
4151                  * We should not move objects if we can't find the
4152                  * deleted objects DN.  Not moving (or otherwise
4153                  * harming) the Deleted Objects DN itself is handled
4154                  * in the caller.
4155                  */
4156                 if (re_delete && (ret != LDB_SUCCESS)) {
4157                         new_dn = ldb_dn_get_parent(tmp_ctx, old_dn);
4158                         if (new_dn == NULL) {
4159                                 ldb_module_oom(module);
4160                                 talloc_free(tmp_ctx);
4161                                 return LDB_ERR_OPERATIONS_ERROR;
4162                         }
4163                 } else if (ret != LDB_SUCCESS) {
4164                         /* this is probably an attempted delete on a partition
4165                          * that doesn't allow delete operations, such as the
4166                          * schema partition */
4167                         ldb_asprintf_errstring(ldb, "No Deleted Objects container for DN %s",
4168                                                ldb_dn_get_linearized(old_dn));
4169                         talloc_free(tmp_ctx);
4170                         return LDB_ERR_UNWILLING_TO_PERFORM;
4171                 } else {
4172                         new_dn = deleted_objects_dn;
4173                 }
4174         } else {
4175                 new_dn = ldb_dn_get_parent(tmp_ctx, old_dn);
4176                 if (new_dn == NULL) {
4177                         ldb_module_oom(module);
4178                         talloc_free(tmp_ctx);
4179                         return LDB_ERR_OPERATIONS_ERROR;
4180                 }
4181         }
4182
4183         /* get the objects GUID from the search we just did */
4184         guid = samdb_result_guid(old_msg, "objectGUID");
4185
4186         if (deletion_state == OBJECT_NOT_DELETED) {
4187                 struct ldb_message_element *is_deleted_el;
4188
4189                 ret = replmd_make_deleted_child_dn(tmp_ctx,
4190                                                    ldb,
4191                                                    new_dn,
4192                                                    rdn_name, rdn_value,
4193                                                    guid);
4194
4195                 if (ret != LDB_SUCCESS) {
4196                         talloc_free(tmp_ctx);
4197                         return ret;
4198                 }
4199
4200                 ret = ldb_msg_add_value(msg, "isDeleted", &true_val,
4201                                         &is_deleted_el);
4202                 if (ret != LDB_SUCCESS) {
4203                         ldb_asprintf_errstring(ldb, __location__
4204                                                ": Failed to add isDeleted string to the msg");
4205                         talloc_free(tmp_ctx);
4206                         return ret;
4207                 }
4208                 is_deleted_el->flags = LDB_FLAG_MOD_REPLACE;
4209         } else {
4210                 /*
4211                  * No matter what has happened with other renames etc, try again to
4212                  * get this to be under the deleted DN. See MS-DRSR 5.160 RemoveObj
4213                  */
4214
4215                 struct ldb_dn *rdn = ldb_dn_copy(tmp_ctx, old_dn);
4216                 retb = ldb_dn_remove_base_components(rdn, ldb_dn_get_comp_num(rdn) - 1);
4217                 if (!retb) {
4218                         ldb_asprintf_errstring(ldb, __location__
4219                                                ": Unable to add a prepare rdn of %s",
4220                                                ldb_dn_get_linearized(rdn));
4221                         talloc_free(tmp_ctx);
4222                         return LDB_ERR_OPERATIONS_ERROR;
4223                 }
4224                 SMB_ASSERT(ldb_dn_get_comp_num(rdn) == 1);
4225
4226                 retb = ldb_dn_add_child(new_dn, rdn);
4227                 if (!retb) {
4228                         ldb_asprintf_errstring(ldb, __location__
4229                                                ": Unable to add rdn %s to base dn: %s",
4230                                                ldb_dn_get_linearized(rdn),
4231                                                ldb_dn_get_linearized(new_dn));
4232                         talloc_free(tmp_ctx);
4233                         return LDB_ERR_OPERATIONS_ERROR;
4234                 }
4235         }
4236
4237         /*
4238           now we need to modify the object in the following ways:
4239
4240           - add isDeleted=TRUE
4241           - update rDN and name, with new rDN
4242           - remove linked attributes
4243           - remove objectCategory and sAMAccountType
4244           - remove attribs not on the preserved list
4245              - preserved if in above list, or is rDN
4246           - remove all linked attribs from this object
4247           - remove all links from other objects to this object
4248           - add lastKnownParent
4249           - update replPropertyMetaData?
4250
4251           see MS-ADTS "Tombstone Requirements" section 3.1.1.5.5.1.1
4252          */
4253
4254         if (deletion_state == OBJECT_NOT_DELETED) {
4255                 struct ldb_dn *parent_dn = ldb_dn_get_parent(tmp_ctx, old_dn);
4256                 char *parent_dn_str = NULL;
4257                 struct ldb_message_element *p_el;
4258
4259                 /* we need the storage form of the parent GUID */
4260                 ret = dsdb_module_search_dn(module, tmp_ctx, &parent_res,
4261                                             parent_dn, NULL,
4262                                             DSDB_FLAG_NEXT_MODULE |
4263                                             DSDB_SEARCH_SHOW_DN_IN_STORAGE_FORMAT |
4264                                             DSDB_SEARCH_REVEAL_INTERNALS|
4265                                             DSDB_SEARCH_SHOW_RECYCLED, req);
4266                 if (ret != LDB_SUCCESS) {
4267                         ldb_asprintf_errstring(ldb_module_get_ctx(module),
4268                                                "repmd_delete: Failed to %s %s, "
4269                                                "because we failed to find it's parent (%s): %s",
4270                                                re_delete ? "re-delete" : "delete",
4271                                                ldb_dn_get_linearized(old_dn),
4272                                                ldb_dn_get_linearized(parent_dn),
4273                                                ldb_errstring(ldb_module_get_ctx(module)));
4274                         talloc_free(tmp_ctx);
4275                         return ret;
4276                 }
4277
4278                 /*
4279                  * Now we can use the DB version,
4280                  * it will have the extended DN info in it
4281                  */
4282                 parent_dn = parent_res->msgs[0]->dn;
4283                 parent_dn_str = ldb_dn_get_extended_linearized(tmp_ctx,
4284                                                                parent_dn,
4285                                                                1);
4286                 if (parent_dn_str == NULL) {
4287                         talloc_free(tmp_ctx);
4288                         return ldb_module_oom(module);
4289                 }
4290
4291                 ret = ldb_msg_add_steal_string(msg, "lastKnownParent",
4292                                                parent_dn_str);
4293                 if (ret != LDB_SUCCESS) {
4294                         ldb_asprintf_errstring(ldb, __location__
4295                                                ": Failed to add lastKnownParent "
4296                                                "string when deleting %s",
4297                                                ldb_dn_get_linearized(old_dn));
4298                         talloc_free(tmp_ctx);
4299                         return ret;
4300                 }
4301                 p_el = ldb_msg_find_element(msg,
4302                                             "lastKnownParent");
4303                 if (p_el == NULL) {
4304                         talloc_free(tmp_ctx);
4305                         return ldb_module_operr(module);
4306                 }
4307                 p_el->flags = LDB_FLAG_MOD_REPLACE;
4308
4309                 if (next_deletion_state == OBJECT_DELETED) {
4310                         ret = ldb_msg_add_value(msg, "msDS-LastKnownRDN", rdn_value, NULL);
4311                         if (ret != LDB_SUCCESS) {
4312                                 ldb_asprintf_errstring(ldb, __location__
4313                                                        ": Failed to add msDS-LastKnownRDN "
4314                                                        "string when deleting %s",
4315                                                        ldb_dn_get_linearized(old_dn));
4316                                 talloc_free(tmp_ctx);
4317                                 return ret;
4318                         }
4319                         p_el = ldb_msg_find_element(msg,
4320                                                     "msDS-LastKnownRDN");
4321                         if (p_el == NULL) {
4322                                 talloc_free(tmp_ctx);
4323                                 return ldb_module_operr(module);
4324                         }
4325                         p_el->flags = LDB_FLAG_MOD_ADD;
4326                 }
4327         }
4328
4329         switch (next_deletion_state) {
4330
4331         case OBJECT_RECYCLED:
4332         case OBJECT_TOMBSTONE:
4333
4334                 /*
4335                  * MS-ADTS 3.1.1.5.5.1.1 Tombstone Requirements
4336                  * describes what must be removed from a tombstone
4337                  * object
4338                  *
4339                  * MS-ADTS 3.1.1.5.5.1.3 Recycled-Object Requirements
4340                  * describes what must be removed from a recycled
4341                  * object
4342                  *
4343                  */
4344
4345                 /*
4346                  * we also mark it as recycled, meaning this object can't be
4347                  * recovered (we are stripping its attributes).
4348                  * This is done only if we have this schema object of course ...
4349                  * This behavior is identical to the one of Windows 2008R2 which
4350                  * always set the isRecycled attribute, even if the recycle-bin is
4351                  * not activated and what ever the forest level is.
4352                  */
4353                 if (dsdb_attribute_by_lDAPDisplayName(schema, "isRecycled") != NULL) {
4354                         struct ldb_message_element *is_recycled_el;
4355
4356                         ret = ldb_msg_add_value(msg, "isRecycled", &true_val,
4357                                                 &is_recycled_el);
4358                         if (ret != LDB_SUCCESS) {
4359                                 DEBUG(0,(__location__ ": Failed to add isRecycled string to the msg\n"));
4360                                 ldb_module_oom(module);
4361                                 talloc_free(tmp_ctx);
4362                                 return ret;
4363                         }
4364                         is_recycled_el->flags = LDB_FLAG_MOD_REPLACE;
4365                 }
4366
4367                 replmd_private = talloc_get_type(ldb_module_get_private(module),
4368                                                  struct replmd_private);
4369                 /* work out which of the old attributes we will be removing */
4370                 for (i=0; i<old_msg->num_elements; i++) {
4371                         const struct dsdb_attribute *sa;
4372                         el = &old_msg->elements[i];
4373                         sa = dsdb_attribute_by_lDAPDisplayName(schema, el->name);
4374                         if (!sa) {
4375                                 talloc_free(tmp_ctx);
4376                                 return LDB_ERR_OPERATIONS_ERROR;
4377                         }
4378                         if (ldb_attr_cmp(el->name, rdn_name) == 0) {
4379                                 /* don't remove the rDN */
4380                                 continue;
4381                         }
4382
4383                         if (sa->linkID & 1) {
4384                                 /*
4385                                   we have a backlink in this object
4386                                   that needs to be removed. We're not
4387                                   allowed to remove it directly
4388                                   however, so we instead setup a
4389                                   modify to delete the corresponding
4390                                   forward link
4391                                  */
4392                                 ret = replmd_delete_remove_link(module, schema,
4393                                                                 replmd_private,
4394                                                                 old_dn, &guid,
4395                                                                 el, sa, req);
4396                                 if (ret == LDB_SUCCESS) {
4397                                         /*
4398                                          * now we continue, which means we
4399                                          * won't remove this backlink
4400                                          * directly
4401                                          */
4402                                         continue;
4403                                 }
4404
4405                                 if (ret != LDB_ERR_NO_SUCH_ATTRIBUTE) {
4406                                         const char *old_dn_str
4407                                                 = ldb_dn_get_linearized(old_dn);
4408                                         ldb_asprintf_errstring(ldb,
4409                                                                __location__
4410                                                                ": Failed to remove backlink of "
4411                                                                "%s when deleting %s: %s",
4412                                                                el->name,
4413                                                                old_dn_str,
4414                                                                ldb_errstring(ldb));
4415                                         talloc_free(tmp_ctx);
4416                                         return LDB_ERR_OPERATIONS_ERROR;
4417                                 }
4418
4419                                 /*
4420                                  * Otherwise vanish the link, we are
4421                                  * out of sync and the controlling
4422                                  * object does not have the source
4423                                  * link any more
4424                                  */
4425
4426                                 dsdb_flags |= DSDB_REPLMD_VANISH_LINKS;
4427
4428                         } else if (sa->linkID == 0) {
4429                                 if (ldb_attr_in_list(preserved_attrs, el->name)) {
4430                                         continue;
4431                                 }
4432                                 if (sa->searchFlags & SEARCH_FLAG_PRESERVEONDELETE) {
4433                                         continue;
4434                                 }
4435                         } else {
4436                                 /*
4437                                  * Ensure that we tell the modification to vanish any linked
4438                                  * attributes (not simply mark them as isDeleted = TRUE)
4439                                  */
4440                                 dsdb_flags |= DSDB_REPLMD_VANISH_LINKS;
4441                         }
4442                         ret = ldb_msg_add_empty(msg, el->name, LDB_FLAG_MOD_DELETE, &el);
4443                         if (ret != LDB_SUCCESS) {
4444                                 talloc_free(tmp_ctx);
4445                                 ldb_module_oom(module);
4446                                 return ret;
4447                         }
4448                 }
4449
4450                 break;
4451
4452         case OBJECT_DELETED:
4453                 /*
4454                  * MS-ADTS 3.1.1.5.5.1.2 Deleted-Object Requirements
4455                  * describes what must be removed from a deleted
4456                  * object
4457                  */
4458
4459                 ret = ldb_msg_add_empty(msg, "objectCategory", LDB_FLAG_MOD_REPLACE, NULL);
4460                 if (ret != LDB_SUCCESS) {
4461                         talloc_free(tmp_ctx);
4462                         ldb_module_oom(module);
4463                         return ret;
4464                 }
4465
4466                 ret = ldb_msg_add_empty(msg, "sAMAccountType", LDB_FLAG_MOD_REPLACE, NULL);
4467                 if (ret != LDB_SUCCESS) {
4468                         talloc_free(tmp_ctx);
4469                         ldb_module_oom(module);
4470                         return ret;
4471                 }
4472
4473                 break;
4474
4475         default:
4476                 break;
4477         }
4478
4479         if (deletion_state == OBJECT_NOT_DELETED) {
4480                 const struct dsdb_attribute *sa;
4481
4482                 /* work out what the new rdn value is, for updating the
4483                    rDN and name fields */
4484                 new_rdn_value = ldb_dn_get_rdn_val(new_dn);
4485                 if (new_rdn_value == NULL) {
4486                         talloc_free(tmp_ctx);
4487                         return ldb_operr(ldb);
4488                 }
4489
4490                 sa = dsdb_attribute_by_lDAPDisplayName(schema, rdn_name);
4491                 if (!sa) {
4492                         talloc_free(tmp_ctx);
4493                         return LDB_ERR_OPERATIONS_ERROR;
4494                 }
4495
4496                 ret = ldb_msg_add_value(msg, sa->lDAPDisplayName, new_rdn_value,
4497                                         &el);
4498                 if (ret != LDB_SUCCESS) {
4499                         talloc_free(tmp_ctx);
4500                         return ret;
4501                 }
4502                 el->flags = LDB_FLAG_MOD_REPLACE;
4503
4504                 el = ldb_msg_find_element(old_msg, "name");
4505                 if (el) {
4506                         ret = ldb_msg_add_value(msg, "name", new_rdn_value, &el);
4507                         if (ret != LDB_SUCCESS) {
4508                                 talloc_free(tmp_ctx);
4509                                 return ret;
4510                         }
4511                         el->flags = LDB_FLAG_MOD_REPLACE;
4512                 }
4513         }
4514
4515         /*
4516          * TODO: Per MS-DRSR 5.160 RemoveObj we should remove links directly, not as an originating update!
4517          *
4518          */
4519
4520         /*
4521          * No matter what has happned with other renames, try again to
4522          * get this to be under the deleted DN.
4523          */
4524         if (strcmp(ldb_dn_get_linearized(old_dn), ldb_dn_get_linearized(new_dn)) != 0) {
4525                 /* now rename onto the new DN */
4526                 ret = dsdb_module_rename(module, old_dn, new_dn, DSDB_FLAG_NEXT_MODULE, req);
4527                 if (ret != LDB_SUCCESS){
4528                         DEBUG(0,(__location__ ": Failed to rename object from '%s' to '%s' - %s\n",
4529                                  ldb_dn_get_linearized(old_dn),
4530                                  ldb_dn_get_linearized(new_dn),
4531                                  ldb_errstring(ldb)));
4532                         talloc_free(tmp_ctx);
4533                         return ret;
4534                 }
4535                 msg->dn = new_dn;
4536         }
4537
4538         ret = dsdb_module_modify(module, msg, dsdb_flags|DSDB_FLAG_OWN_MODULE, req);
4539         if (ret != LDB_SUCCESS) {
4540                 ldb_asprintf_errstring(ldb, "replmd_delete: Failed to modify object %s in delete - %s",
4541                                        ldb_dn_get_linearized(old_dn), ldb_errstring(ldb));
4542                 talloc_free(tmp_ctx);
4543                 return ret;
4544         }
4545
4546         talloc_free(tmp_ctx);
4547
4548         return ldb_module_done(req, NULL, NULL, LDB_SUCCESS);
4549 }
4550
4551 static int replmd_delete(struct ldb_module *module, struct ldb_request *req)
4552 {
4553         return replmd_delete_internals(module, req, false);
4554 }
4555
4556
4557 static int replmd_replicated_request_error(struct replmd_replicated_request *ar, int ret)
4558 {
4559         return ret;
4560 }
4561
4562 static int replmd_replicated_request_werror(struct replmd_replicated_request *ar, WERROR status)
4563 {
4564         int ret = LDB_ERR_OTHER;
4565         /* TODO: do some error mapping */
4566
4567         /* Let the caller know the full WERROR */
4568         ar->objs->error = status;
4569
4570         return ret;
4571 }
4572
4573
4574 static struct replPropertyMetaData1 *
4575 replmd_replPropertyMetaData1_find_attid(struct replPropertyMetaDataBlob *md_blob,
4576                                         enum drsuapi_DsAttributeId attid)
4577 {
4578         uint32_t i;
4579         struct replPropertyMetaDataCtr1 *rpmd_ctr = &md_blob->ctr.ctr1;
4580
4581         for (i = 0; i < rpmd_ctr->count; i++) {
4582                 if (rpmd_ctr->array[i].attid == attid) {
4583                         return &rpmd_ctr->array[i];
4584                 }
4585         }
4586         return NULL;
4587 }
4588
4589
4590 /*
4591    return true if an update is newer than an existing entry
4592    see section 5.11 of MS-ADTS
4593 */
4594 static bool replmd_update_is_newer(const struct GUID *current_invocation_id,
4595                                    const struct GUID *update_invocation_id,
4596                                    uint32_t current_version,
4597                                    uint32_t update_version,
4598                                    NTTIME current_change_time,
4599                                    NTTIME update_change_time)
4600 {
4601         if (update_version != current_version) {
4602                 return update_version > current_version;
4603         }
4604         if (update_change_time != current_change_time) {
4605                 return update_change_time > current_change_time;
4606         }
4607         return GUID_compare(update_invocation_id, current_invocation_id) > 0;
4608 }
4609
4610 static bool replmd_replPropertyMetaData1_is_newer(struct replPropertyMetaData1 *cur_m,
4611                                                   struct replPropertyMetaData1 *new_m)
4612 {
4613         return replmd_update_is_newer(&cur_m->originating_invocation_id,
4614                                       &new_m->originating_invocation_id,
4615                                       cur_m->version,
4616                                       new_m->version,
4617                                       cur_m->originating_change_time,
4618                                       new_m->originating_change_time);
4619 }
4620
4621 static bool replmd_replPropertyMetaData1_new_should_be_taken(uint32_t dsdb_repl_flags,
4622                                                              struct replPropertyMetaData1 *cur_m,
4623                                                              struct replPropertyMetaData1 *new_m)
4624 {
4625         bool cmp;
4626
4627         /*
4628          * If the new replPropertyMetaData entry for this attribute is
4629          * not provided (this happens in the case where we look for
4630          * ATTID_name, but the name was not changed), then the local
4631          * state is clearly still current, as the remote
4632          * server didn't send it due to being older the high watermark
4633          * USN we sent.
4634          */
4635         if (new_m == NULL) {
4636                 return false;
4637         }
4638
4639         if (dsdb_repl_flags & DSDB_REPL_FLAG_PRIORITISE_INCOMING) {
4640                 /*
4641                  * if we compare equal then do an
4642                  * update. This is used when a client
4643                  * asks for a FULL_SYNC, and can be
4644                  * used to recover a corrupt
4645                  * replica.
4646                  *
4647                  * This call is a bit tricky, what we
4648                  * are doing it turning the 'is_newer'
4649                  * call into a 'not is older' by
4650                  * swapping cur_m and new_m, and negating the
4651                  * outcome.
4652                  */
4653                 cmp = !replmd_replPropertyMetaData1_is_newer(new_m,
4654                                                              cur_m);
4655         } else {
4656                 cmp = replmd_replPropertyMetaData1_is_newer(cur_m,
4657                                                             new_m);
4658         }
4659         return cmp;
4660 }
4661
4662
4663 /*
4664   form a DN for a deleted (DEL:) or conflict (CNF:) DN
4665  */
4666 static int replmd_make_prefix_child_dn(TALLOC_CTX *tmp_ctx,
4667                                        struct ldb_context *ldb,
4668                                        struct ldb_dn *dn,
4669                                        const char *four_char_prefix,
4670                                        const char *rdn_name,
4671                                        const struct ldb_val *rdn_value,
4672                                        struct GUID guid)
4673 {
4674         struct ldb_val deleted_child_rdn_val;
4675         struct GUID_txt_buf guid_str;
4676         int ret;
4677         bool retb;
4678
4679         GUID_buf_string(&guid, &guid_str);
4680
4681         retb = ldb_dn_add_child_fmt(dn, "X=Y");
4682         if (!retb) {
4683                 ldb_asprintf_errstring(ldb, __location__
4684                                        ": Unable to add a formatted child to dn: %s",
4685                                        ldb_dn_get_linearized(dn));
4686                 return LDB_ERR_OPERATIONS_ERROR;
4687         }
4688
4689         /*
4690          * TODO: Per MS-ADTS 3.1.1.5.5 Delete Operation
4691          * we should truncate this value to ensure the RDN is not more than 255 chars.
4692          *
4693          * However we MS-ADTS 3.1.1.5.1.2 Naming Constraints indicates that:
4694          *
4695          * "Naming constraints are not enforced for replicated
4696          * updates." so this is safe and we don't have to work out not
4697          * splitting a UTF8 char right now.
4698          */
4699         deleted_child_rdn_val = ldb_val_dup(tmp_ctx, rdn_value);
4700
4701         /*
4702          * sizeof(guid_str.buf) will always be longer than
4703          * strlen(guid_str.buf) but we allocate using this and
4704          * waste the trailing bytes to avoid scaring folks
4705          * with memcpy() using strlen() below
4706          */
4707
4708         deleted_child_rdn_val.data
4709                 = talloc_realloc(tmp_ctx, deleted_child_rdn_val.data,
4710                                  uint8_t,
4711                                  rdn_value->length + 5
4712                                  + sizeof(guid_str.buf));
4713         if (!deleted_child_rdn_val.data) {
4714                 ldb_asprintf_errstring(ldb, __location__
4715                                        ": Unable to add a formatted child to dn: %s",
4716                                        ldb_dn_get_linearized(dn));
4717                 return LDB_ERR_OPERATIONS_ERROR;
4718         }
4719
4720         deleted_child_rdn_val.length =
4721                 rdn_value->length + 5
4722                 + strlen(guid_str.buf);
4723
4724         SMB_ASSERT(deleted_child_rdn_val.length <
4725                    talloc_get_size(deleted_child_rdn_val.data));
4726
4727         /*
4728          * talloc won't allocate more than 256MB so we can't
4729          * overflow but just to be sure
4730          */
4731         if (deleted_child_rdn_val.length < rdn_value->length) {
4732                 return LDB_ERR_OPERATIONS_ERROR;
4733         }
4734
4735         deleted_child_rdn_val.data[rdn_value->length] = 0x0a;
4736         memcpy(&deleted_child_rdn_val.data[rdn_value->length + 1],
4737                four_char_prefix, 4);
4738         memcpy(&deleted_child_rdn_val.data[rdn_value->length + 5],
4739                guid_str.buf,
4740                sizeof(guid_str.buf));
4741
4742         /* Now set the value into the RDN, without parsing it */
4743         ret = ldb_dn_set_component(
4744                 dn,
4745                 0,
4746                 rdn_name,
4747                 deleted_child_rdn_val);
4748
4749         return ret;
4750 }
4751
4752
4753 /*
4754   form a conflict DN
4755  */
4756 static struct ldb_dn *replmd_conflict_dn(TALLOC_CTX *mem_ctx,
4757                                          struct ldb_context *ldb,
4758                                          struct ldb_dn *dn,
4759                                          struct GUID *guid)
4760 {
4761         const struct ldb_val *rdn_val;
4762         const char *rdn_name;
4763         struct ldb_dn *new_dn;
4764         int ret;
4765
4766         rdn_val = ldb_dn_get_rdn_val(dn);
4767         rdn_name = ldb_dn_get_rdn_name(dn);
4768         if (!rdn_val || !rdn_name) {
4769                 return NULL;
4770         }
4771
4772         new_dn = ldb_dn_get_parent(mem_ctx, dn);
4773         if (!new_dn) {
4774                 return NULL;
4775         }
4776
4777         ret = replmd_make_prefix_child_dn(mem_ctx,
4778                                           ldb, new_dn,
4779                                           "CNF:",
4780                                           rdn_name,
4781                                           rdn_val,
4782                                           *guid);
4783         if (ret != LDB_SUCCESS) {
4784                 return NULL;
4785         }
4786         return new_dn;
4787 }
4788
4789 /*
4790   form a deleted DN
4791  */
4792 static int replmd_make_deleted_child_dn(TALLOC_CTX *tmp_ctx,
4793                                         struct ldb_context *ldb,
4794                                         struct ldb_dn *dn,
4795                                         const char *rdn_name,
4796                                         const struct ldb_val *rdn_value,
4797                                         struct GUID guid)
4798 {
4799         return replmd_make_prefix_child_dn(tmp_ctx,
4800                                            ldb, dn,
4801                                            "DEL:",
4802                                            rdn_name,
4803                                            rdn_value,
4804                                            guid);
4805 }
4806
4807
4808 /*
4809   perform a modify operation which sets the rDN and name attributes to
4810   their current values. This has the effect of changing these
4811   attributes to have been last updated by the current DC. This is
4812   needed to ensure that renames performed as part of conflict
4813   resolution are propagated to other DCs
4814  */
4815 static int replmd_name_modify(struct replmd_replicated_request *ar,
4816                               struct ldb_request *req, struct ldb_dn *dn)
4817 {
4818         struct ldb_message *msg;
4819         const char *rdn_name;
4820         const struct ldb_val *rdn_val;
4821         const struct dsdb_attribute *rdn_attr;
4822         int ret;
4823
4824         msg = ldb_msg_new(req);
4825         if (msg == NULL) {
4826                 goto failed;
4827         }
4828         msg->dn = dn;
4829
4830         rdn_name = ldb_dn_get_rdn_name(dn);
4831         if (rdn_name == NULL) {
4832                 goto failed;
4833         }
4834
4835         /* normalize the rdn attribute name */
4836         rdn_attr = dsdb_attribute_by_lDAPDisplayName(ar->schema, rdn_name);
4837         if (rdn_attr == NULL) {
4838                 goto failed;
4839         }
4840         rdn_name = rdn_attr->lDAPDisplayName;
4841
4842         rdn_val = ldb_dn_get_rdn_val(dn);
4843         if (rdn_val == NULL) {
4844                 goto failed;
4845         }
4846
4847         if (ldb_msg_add_empty(msg, rdn_name, LDB_FLAG_MOD_REPLACE, NULL) != 0) {
4848                 goto failed;
4849         }
4850         if (ldb_msg_add_value(msg, rdn_name, rdn_val, NULL) != 0) {
4851                 goto failed;
4852         }
4853         if (ldb_msg_add_empty(msg, "name", LDB_FLAG_MOD_REPLACE, NULL) != 0) {
4854                 goto failed;
4855         }
4856         if (ldb_msg_add_value(msg, "name", rdn_val, NULL) != 0) {
4857                 goto failed;
4858         }
4859
4860         /*
4861          * We have to mark this as a replicated update otherwise
4862          * schema_data may reject a rename in the schema partition
4863          */
4864
4865         ret = dsdb_module_modify(ar->module, msg,
4866                                  DSDB_FLAG_OWN_MODULE|DSDB_FLAG_REPLICATED_UPDATE,
4867                                  req);
4868         if (ret != LDB_SUCCESS) {
4869                 DEBUG(0,(__location__ ": Failed to modify rDN/name of DN being DRS renamed '%s' - %s",
4870                          ldb_dn_get_linearized(dn),
4871                          ldb_errstring(ldb_module_get_ctx(ar->module))));
4872                 return ret;
4873         }
4874
4875         talloc_free(msg);
4876
4877         return LDB_SUCCESS;
4878
4879 failed:
4880         talloc_free(msg);
4881         DEBUG(0,(__location__ ": Failed to setup modify rDN/name of DN being DRS renamed '%s'",
4882                  ldb_dn_get_linearized(dn)));
4883         return LDB_ERR_OPERATIONS_ERROR;
4884 }
4885
4886
4887 /*
4888   callback for conflict DN handling where we have renamed the incoming
4889   record. After renaming it, we need to ensure the change of name and
4890   rDN for the incoming record is seen as an originating update by this DC.
4891
4892   This also handles updating lastKnownParent for entries sent to lostAndFound
4893  */
4894 static int replmd_op_name_modify_callback(struct ldb_request *req, struct ldb_reply *ares)
4895 {
4896         struct replmd_replicated_request *ar =
4897                 talloc_get_type_abort(req->context, struct replmd_replicated_request);
4898         struct ldb_dn *conflict_dn = NULL;
4899         int ret;
4900
4901         if (ares->error != LDB_SUCCESS) {
4902                 /* call the normal callback for everything except success */
4903                 return replmd_op_callback(req, ares);
4904         }
4905
4906         switch (req->operation) {
4907         case LDB_ADD:
4908                 conflict_dn = req->op.add.message->dn;
4909                 break;
4910         case LDB_MODIFY:
4911                 conflict_dn = req->op.mod.message->dn;
4912                 break;
4913         default:
4914                 smb_panic("replmd_op_name_modify_callback called in unknown circumstances");
4915         }
4916
4917         /* perform a modify of the rDN and name of the record */
4918         ret = replmd_name_modify(ar, req, conflict_dn);
4919         if (ret != LDB_SUCCESS) {
4920                 ares->error = ret;
4921                 return replmd_op_callback(req, ares);
4922         }
4923
4924         if (ar->objs->objects[ar->index_current].last_known_parent) {
4925                 struct ldb_message *msg = ldb_msg_new(req);
4926                 if (msg == NULL) {
4927                         ldb_module_oom(ar->module);
4928                         return LDB_ERR_OPERATIONS_ERROR;
4929                 }
4930
4931                 msg->dn = req->op.add.message->dn;
4932
4933                 ret = ldb_msg_add_steal_string(msg, "lastKnownParent",
4934                                                ldb_dn_get_extended_linearized(msg, ar->objs->objects[ar->index_current].last_known_parent, 1));
4935                 if (ret != LDB_SUCCESS) {
4936                         DEBUG(0,(__location__ ": Failed to add lastKnownParent string to the msg\n"));
4937                         ldb_module_oom(ar->module);
4938                         return ret;
4939                 }
4940                 msg->elements[0].flags = LDB_FLAG_MOD_REPLACE;
4941
4942                 ret = dsdb_module_modify(ar->module, msg, DSDB_FLAG_OWN_MODULE, req);
4943                 if (ret != LDB_SUCCESS) {
4944                         DEBUG(0,(__location__ ": Failed to modify lastKnownParent of lostAndFound DN '%s' - %s",
4945                                  ldb_dn_get_linearized(msg->dn),
4946                                  ldb_errstring(ldb_module_get_ctx(ar->module))));
4947                         return ret;
4948                 }
4949                 TALLOC_FREE(msg);
4950         }
4951
4952         return replmd_op_callback(req, ares);
4953 }
4954
4955 /*
4956   callback for replmd_replicated_apply_add()
4957   This copes with the creation of conflict records in the case where
4958   the DN exists, but with a different objectGUID
4959  */
4960 static int replmd_op_possible_conflict_callback(struct ldb_request *req, struct ldb_reply *ares, int (*callback)(struct ldb_request *req, struct ldb_reply *ares))
4961 {
4962         struct ldb_dn *conflict_dn;
4963         struct replmd_replicated_request *ar =
4964                 talloc_get_type_abort(req->context, struct replmd_replicated_request);
4965         struct ldb_result *res;
4966         const char *attrs[] = { "replPropertyMetaData", "objectGUID", NULL };
4967         int ret;
4968         const struct ldb_val *omd_value;
4969         struct replPropertyMetaDataBlob omd, *rmd;
4970         enum ndr_err_code ndr_err;
4971         bool rename_incoming_record, rodc;
4972         struct replPropertyMetaData1 *rmd_name, *omd_name;
4973         struct ldb_message *msg;
4974         struct ldb_request *down_req = NULL;
4975
4976         /* call the normal callback for success */
4977         if (ares->error == LDB_SUCCESS) {
4978                 return callback(req, ares);
4979         }
4980
4981         /*
4982          * we have a conflict, and need to decide if we will keep the
4983          * new record or the old record
4984          */
4985
4986         msg = ar->objs->objects[ar->index_current].msg;
4987         conflict_dn = msg->dn;
4988
4989         /* For failures other than conflicts, fail the whole operation here */
4990         if (ares->error != LDB_ERR_ENTRY_ALREADY_EXISTS) {
4991                 ldb_asprintf_errstring(ldb_module_get_ctx(ar->module), "Failed to locally apply remote add of %s: %s",
4992                                        ldb_dn_get_linearized(conflict_dn),
4993                                        ldb_errstring(ldb_module_get_ctx(ar->module)));
4994
4995                 return ldb_module_done(ar->req, NULL, NULL,
4996                                        LDB_ERR_OPERATIONS_ERROR);
4997         }
4998
4999         ret = samdb_rodc(ldb_module_get_ctx(ar->module), &rodc);
5000         if (ret != LDB_SUCCESS) {
5001                 ldb_asprintf_errstring(ldb_module_get_ctx(ar->module), "Failed to determine if we are an RODC when attempting to form conflict DN: %s", ldb_errstring(ldb_module_get_ctx(ar->module)));
5002                 return ldb_module_done(ar->req, NULL, NULL,
5003                                        LDB_ERR_OPERATIONS_ERROR);
5004
5005         }
5006
5007         if (rodc) {
5008                 /*
5009                  * We are on an RODC, or were a GC for this
5010                  * partition, so we have to fail this until
5011                  * someone who owns the partition sorts it
5012                  * out
5013                  */
5014                 ldb_asprintf_errstring(ldb_module_get_ctx(ar->module),
5015                                        "Conflict adding object '%s' from incoming replication as we are read only for the partition.  \n"
5016                                        " - We must fail the operation until a master for this partition resolves the conflict",
5017                                        ldb_dn_get_linearized(conflict_dn));
5018                 ret = LDB_ERR_OPERATIONS_ERROR;
5019                 goto failed;
5020         }
5021
5022         /*
5023          * first we need the replPropertyMetaData attribute from the
5024          * local, conflicting record
5025          */
5026         ret = dsdb_module_search_dn(ar->module, req, &res, conflict_dn,
5027                                     attrs,
5028                                     DSDB_FLAG_NEXT_MODULE |
5029                                     DSDB_SEARCH_SHOW_DELETED |
5030                                     DSDB_SEARCH_SHOW_RECYCLED, req);
5031         if (ret != LDB_SUCCESS) {
5032                 DEBUG(0,(__location__ ": Unable to find object for conflicting record '%s'\n",
5033                          ldb_dn_get_linearized(conflict_dn)));
5034                 goto failed;
5035         }
5036
5037         omd_value = ldb_msg_find_ldb_val(res->msgs[0], "replPropertyMetaData");
5038         if (omd_value == NULL) {
5039                 DEBUG(0,(__location__ ": Unable to find replPropertyMetaData for conflicting record '%s'\n",
5040                          ldb_dn_get_linearized(conflict_dn)));
5041                 goto failed;
5042         }
5043
5044         ndr_err = ndr_pull_struct_blob(omd_value, res->msgs[0], &omd,
5045                                        (ndr_pull_flags_fn_t)ndr_pull_replPropertyMetaDataBlob);
5046         if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
5047                 DEBUG(0,(__location__ ": Failed to parse old replPropertyMetaData for %s\n",
5048                          ldb_dn_get_linearized(conflict_dn)));
5049                 goto failed;
5050         }
5051
5052         rmd = ar->objs->objects[ar->index_current].meta_data;
5053
5054         /*
5055          * we decide which is newer based on the RPMD on the name
5056          * attribute.  See [MS-DRSR] ResolveNameConflict.
5057          *
5058          * We expect omd_name to be present, as this is from a local
5059          * search, but while rmd_name should have been given to us by
5060          * the remote server, if it is missing we just prefer the
5061          * local name in
5062          * replmd_replPropertyMetaData1_new_should_be_taken()
5063          */
5064         rmd_name = replmd_replPropertyMetaData1_find_attid(rmd, DRSUAPI_ATTID_name);
5065         omd_name = replmd_replPropertyMetaData1_find_attid(&omd, DRSUAPI_ATTID_name);
5066         if (!omd_name) {
5067                 DEBUG(0,(__location__ ": Failed to find name attribute in local LDB replPropertyMetaData for %s\n",
5068                          ldb_dn_get_linearized(conflict_dn)));
5069                 goto failed;
5070         }
5071
5072         /*
5073          * Should we preserve the current record, and so rename the
5074          * incoming record to be a conflict?
5075          */
5076         rename_incoming_record
5077                 = !replmd_replPropertyMetaData1_new_should_be_taken(ar->objs->dsdb_repl_flags & DSDB_REPL_FLAG_PRIORITISE_INCOMING,
5078                                                                     omd_name, rmd_name);
5079
5080         if (rename_incoming_record) {
5081                 struct GUID guid;
5082                 struct ldb_dn *new_dn;
5083
5084                 guid = samdb_result_guid(msg, "objectGUID");
5085                 if (GUID_all_zero(&guid)) {
5086                         DEBUG(0,(__location__ ": Failed to find objectGUID for conflicting incoming record %s\n",
5087                                  ldb_dn_get_linearized(conflict_dn)));
5088                         goto failed;
5089                 }
5090                 new_dn = replmd_conflict_dn(req,
5091                                             ldb_module_get_ctx(ar->module),
5092                                             conflict_dn, &guid);
5093                 if (new_dn == NULL) {
5094                         DEBUG(0,(__location__ ": Failed to form conflict DN for %s\n",
5095                                  ldb_dn_get_linearized(conflict_dn)));
5096                         goto failed;
5097                 }
5098
5099                 DEBUG(2,(__location__ ": Resolving conflict record via incoming rename '%s' -> '%s'\n",
5100                          ldb_dn_get_linearized(conflict_dn), ldb_dn_get_linearized(new_dn)));
5101
5102                 /* re-submit the request, but with the new DN */
5103                 callback = replmd_op_name_modify_callback;
5104                 msg->dn = new_dn;
5105         } else {
5106                 /* we are renaming the existing record */
5107                 struct GUID guid;
5108                 struct ldb_dn *new_dn;
5109
5110                 guid = samdb_result_guid(res->msgs[0], "objectGUID");
5111                 if (GUID_all_zero(&guid)) {
5112                         DEBUG(0,(__location__ ": Failed to find objectGUID for existing conflict record %s\n",
5113                                  ldb_dn_get_linearized(conflict_dn)));
5114                         goto failed;
5115                 }
5116
5117                 new_dn = replmd_conflict_dn(req,
5118                                             ldb_module_get_ctx(ar->module),
5119                                             conflict_dn, &guid);
5120                 if (new_dn == NULL) {
5121                         DEBUG(0,(__location__ ": Failed to form conflict DN for %s\n",
5122                                  ldb_dn_get_linearized(conflict_dn)));
5123                         goto failed;
5124                 }
5125
5126                 DEBUG(2,(__location__ ": Resolving conflict record via existing-record rename '%s' -> '%s'\n",
5127                          ldb_dn_get_linearized(conflict_dn), ldb_dn_get_linearized(new_dn)));
5128
5129                 ret = dsdb_module_rename(ar->module, conflict_dn, new_dn,
5130                                          DSDB_FLAG_OWN_MODULE, req);
5131                 if (ret != LDB_SUCCESS) {
5132                         DEBUG(0,(__location__ ": Failed to rename conflict dn '%s' to '%s' - %s\n",
5133                                  ldb_dn_get_linearized(conflict_dn),
5134                                  ldb_dn_get_linearized(new_dn),
5135                                  ldb_errstring(ldb_module_get_ctx(ar->module))));
5136                         goto failed;
5137                 }
5138
5139                 /*
5140                  * now we need to ensure that the rename is seen as an
5141                  * originating update. We do that with a modify.
5142                  */
5143                 ret = replmd_name_modify(ar, req, new_dn);
5144                 if (ret != LDB_SUCCESS) {
5145                         goto failed;
5146                 }
5147
5148                 DEBUG(2,(__location__ ": With conflicting record renamed, re-apply replicated creation of '%s'\n",
5149                          ldb_dn_get_linearized(req->op.add.message->dn)));
5150         }
5151
5152         ret = ldb_build_add_req(&down_req,
5153                                 ldb_module_get_ctx(ar->module),
5154                                 req,
5155                                 msg,
5156                                 ar->controls,
5157                                 ar,
5158                                 callback,
5159                                 req);
5160         if (ret != LDB_SUCCESS) {
5161                 goto failed;
5162         }
5163         LDB_REQ_SET_LOCATION(down_req);
5164
5165         /* current partition control needed by "repmd_op_callback" */
5166         ret = ldb_request_add_control(down_req,
5167                                       DSDB_CONTROL_CURRENT_PARTITION_OID,
5168                                       false, NULL);
5169         if (ret != LDB_SUCCESS) {
5170                 return replmd_replicated_request_error(ar, ret);
5171         }
5172
5173         if (ar->objs->dsdb_repl_flags & DSDB_REPL_FLAG_PARTIAL_REPLICA) {
5174                 /* this tells the partition module to make it a
5175                    partial replica if creating an NC */
5176                 ret = ldb_request_add_control(down_req,
5177                                               DSDB_CONTROL_PARTIAL_REPLICA,
5178                                               false, NULL);
5179                 if (ret != LDB_SUCCESS) {
5180                         return replmd_replicated_request_error(ar, ret);
5181                 }
5182         }
5183
5184         /*
5185          * Finally we re-run the add, otherwise the new record won't
5186          * exist, as we are here because of that exact failure!
5187          */
5188         return ldb_next_request(ar->module, down_req);
5189 failed:
5190
5191         /* on failure make the caller get the error. This means
5192          * replication will stop with an error, but there is not much
5193          * else we can do.
5194          */
5195         if (ret == LDB_SUCCESS) {
5196                 ret = LDB_ERR_OPERATIONS_ERROR;
5197         }
5198         return ldb_module_done(ar->req, NULL, NULL,
5199                                ret);
5200 }
5201
5202 /*
5203   callback for replmd_replicated_apply_add()
5204   This copes with the creation of conflict records in the case where
5205   the DN exists, but with a different objectGUID
5206  */
5207 static int replmd_op_add_callback(struct ldb_request *req, struct ldb_reply *ares)
5208 {
5209         struct replmd_replicated_request *ar =
5210                 talloc_get_type_abort(req->context, struct replmd_replicated_request);
5211
5212         if (ar->objs->objects[ar->index_current].last_known_parent) {
5213                 /* This is like a conflict DN, where we put the object in LostAndFound
5214                    see MS-DRSR 4.1.10.6.10 FindBestParentObject */
5215                 return replmd_op_possible_conflict_callback(req, ares, replmd_op_name_modify_callback);
5216         }
5217
5218         return replmd_op_possible_conflict_callback(req, ares, replmd_op_callback);
5219 }
5220
5221 /*
5222   this is called when a new object comes in over DRS
5223  */
5224 static int replmd_replicated_apply_add(struct replmd_replicated_request *ar)
5225 {
5226         struct ldb_context *ldb;
5227         struct ldb_request *change_req;
5228         enum ndr_err_code ndr_err;
5229         struct ldb_message *msg;
5230         struct replPropertyMetaDataBlob *md;
5231         struct ldb_val md_value;
5232         unsigned int i;
5233         int ret;
5234         bool remote_isDeleted = false;
5235         bool is_schema_nc;
5236         NTTIME now;
5237         time_t t = time(NULL);
5238         const struct ldb_val *rdn_val;
5239         struct replmd_private *replmd_private =
5240                 talloc_get_type(ldb_module_get_private(ar->module),
5241                                 struct replmd_private);
5242         unix_to_nt_time(&now, t);
5243
5244         ldb = ldb_module_get_ctx(ar->module);
5245         msg = ar->objs->objects[ar->index_current].msg;
5246         md = ar->objs->objects[ar->index_current].meta_data;
5247         is_schema_nc = ldb_dn_compare_base(replmd_private->schema_dn, msg->dn) == 0;
5248
5249         ret = ldb_sequence_number(ldb, LDB_SEQ_NEXT, &ar->seq_num);
5250         if (ret != LDB_SUCCESS) {
5251                 return replmd_replicated_request_error(ar, ret);
5252         }
5253
5254         ret = dsdb_msg_add_guid(msg,
5255                                 &ar->objs->objects[ar->index_current].object_guid,
5256                                 "objectGUID");
5257         if (ret != LDB_SUCCESS) {
5258                 return replmd_replicated_request_error(ar, ret);
5259         }
5260
5261         ret = ldb_msg_add_string(msg, "whenChanged", ar->objs->objects[ar->index_current].when_changed);
5262         if (ret != LDB_SUCCESS) {
5263                 return replmd_replicated_request_error(ar, ret);
5264         }
5265
5266         ret = samdb_msg_add_uint64(ldb, msg, msg, "uSNCreated", ar->seq_num);
5267         if (ret != LDB_SUCCESS) {
5268                 return replmd_replicated_request_error(ar, ret);
5269         }
5270
5271         ret = samdb_msg_add_uint64(ldb, msg, msg, "uSNChanged", ar->seq_num);
5272         if (ret != LDB_SUCCESS) {
5273                 return replmd_replicated_request_error(ar, ret);
5274         }
5275
5276         /* remove any message elements that have zero values */
5277         for (i=0; i<msg->num_elements; i++) {
5278                 struct ldb_message_element *el = &msg->elements[i];
5279
5280                 if (el->num_values == 0) {
5281                         if (ldb_attr_cmp(msg->elements[i].name, "objectClass") == 0) {
5282                                 ldb_asprintf_errstring(ldb, __location__
5283                                                        ": empty objectClass sent on %s, aborting replication\n",
5284                                                        ldb_dn_get_linearized(msg->dn));
5285                                 return replmd_replicated_request_error(ar, LDB_ERR_OBJECT_CLASS_VIOLATION);
5286                         }
5287
5288                         DEBUG(4,(__location__ ": Removing attribute %s with num_values==0\n",
5289                                  el->name));
5290                         memmove(el, el+1, sizeof(*el)*(msg->num_elements - (i+1)));
5291                         msg->num_elements--;
5292                         i--;
5293                         continue;
5294                 }
5295         }
5296
5297         if (DEBUGLVL(8)) {
5298                 struct GUID_txt_buf guid_txt;
5299
5300                 char *s = ldb_ldif_message_redacted_string(ldb, ar,
5301                                                            LDB_CHANGETYPE_ADD,
5302                                                            msg);
5303                 DEBUG(8, ("DRS replication add message of %s:\n%s\n",
5304                           GUID_buf_string(&ar->objs->objects[ar->index_current].object_guid, &guid_txt),
5305                           s));
5306                 talloc_free(s);
5307         } else if (DEBUGLVL(4)) {
5308                 struct GUID_txt_buf guid_txt;
5309                 DEBUG(4, ("DRS replication add DN of %s is %s\n",
5310                           GUID_buf_string(&ar->objs->objects[ar->index_current].object_guid, &guid_txt),
5311                           ldb_dn_get_linearized(msg->dn)));
5312         }
5313         remote_isDeleted = ldb_msg_find_attr_as_bool(msg,
5314                                                      "isDeleted", false);
5315
5316         /*
5317          * the meta data array is already sorted by the caller, except
5318          * for the RDN, which needs to be added.
5319          */
5320
5321
5322         rdn_val = ldb_dn_get_rdn_val(msg->dn);
5323         ret = replmd_update_rpmd_rdn_attr(ldb, msg, rdn_val, NULL,
5324                                           md, ar, now, is_schema_nc,
5325                                           false);
5326         if (ret != LDB_SUCCESS) {
5327                 ldb_asprintf_errstring(ldb, "%s: error during DRS repl ADD: %s", __func__, ldb_errstring(ldb));
5328                 return replmd_replicated_request_error(ar, ret);
5329         }
5330
5331         ret = replmd_replPropertyMetaDataCtr1_sort_and_verify(ldb, &md->ctr.ctr1, msg->dn);
5332         if (ret != LDB_SUCCESS) {
5333                 ldb_asprintf_errstring(ldb, "%s: error during DRS repl ADD: %s", __func__, ldb_errstring(ldb));
5334                 return replmd_replicated_request_error(ar, ret);
5335         }
5336
5337         for (i=0; i < md->ctr.ctr1.count; i++) {
5338                 md->ctr.ctr1.array[i].local_usn = ar->seq_num;
5339         }
5340         ndr_err = ndr_push_struct_blob(&md_value, msg, md,
5341                                        (ndr_push_flags_fn_t)ndr_push_replPropertyMetaDataBlob);
5342         if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
5343                 NTSTATUS nt_status = ndr_map_error2ntstatus(ndr_err);
5344                 return replmd_replicated_request_werror(ar, ntstatus_to_werror(nt_status));
5345         }
5346         ret = ldb_msg_add_value(msg, "replPropertyMetaData", &md_value, NULL);
5347         if (ret != LDB_SUCCESS) {
5348                 return replmd_replicated_request_error(ar, ret);
5349         }
5350
5351         replmd_ldb_message_sort(msg, ar->schema);
5352
5353         if (!remote_isDeleted) {
5354                 ret = dsdb_module_schedule_sd_propagation(ar->module,
5355                                                           ar->objs->partition_dn,
5356                                                           msg->dn, true);
5357                 if (ret != LDB_SUCCESS) {
5358                         return replmd_replicated_request_error(ar, ret);
5359                 }
5360         }
5361
5362         ar->isDeleted = remote_isDeleted;
5363
5364         ret = ldb_build_add_req(&change_req,
5365                                 ldb,
5366                                 ar,
5367                                 msg,
5368                                 ar->controls,
5369                                 ar,
5370                                 replmd_op_add_callback,
5371                                 ar->req);
5372         LDB_REQ_SET_LOCATION(change_req);
5373         if (ret != LDB_SUCCESS) return replmd_replicated_request_error(ar, ret);
5374
5375         /* current partition control needed by "repmd_op_callback" */
5376         ret = ldb_request_add_control(change_req,
5377                                       DSDB_CONTROL_CURRENT_PARTITION_OID,
5378                                       false, NULL);
5379         if (ret != LDB_SUCCESS) return replmd_replicated_request_error(ar, ret);
5380
5381         if (ar->objs->dsdb_repl_flags & DSDB_REPL_FLAG_PARTIAL_REPLICA) {
5382                 /* this tells the partition module to make it a
5383                    partial replica if creating an NC */
5384                 ret = ldb_request_add_control(change_req,
5385                                               DSDB_CONTROL_PARTIAL_REPLICA,
5386                                               false, NULL);
5387                 if (ret != LDB_SUCCESS) return replmd_replicated_request_error(ar, ret);
5388         }
5389
5390         return ldb_next_request(ar->module, change_req);
5391 }
5392
5393 static int replmd_replicated_apply_search_for_parent_callback(struct ldb_request *req,
5394                                                               struct ldb_reply *ares)
5395 {
5396         struct replmd_replicated_request *ar = talloc_get_type(req->context,
5397                                                struct replmd_replicated_request);
5398         int ret;
5399
5400         if (!ares) {
5401                 return ldb_module_done(ar->req, NULL, NULL,
5402                                         LDB_ERR_OPERATIONS_ERROR);
5403         }
5404
5405         /*
5406          * The error NO_SUCH_OBJECT is not expected, unless the search
5407          * base is the partition DN, and that case doesn't happen here
5408          * because then we wouldn't get a parent_guid_value in any
5409          * case.
5410          */
5411         if (ares->error != LDB_SUCCESS) {
5412                 return ldb_module_done(ar->req, ares->controls,
5413                                         ares->response, ares->error);
5414         }
5415
5416         switch (ares->type) {
5417         case LDB_REPLY_ENTRY:
5418         {
5419                 struct ldb_message *parent_msg = ares->message;
5420                 struct ldb_message *msg = ar->objs->objects[ar->index_current].msg;
5421                 struct ldb_dn *parent_dn = NULL;
5422                 int comp_num;
5423
5424                 if (!ldb_msg_check_string_attribute(msg, "isDeleted", "TRUE")
5425                     && ldb_msg_check_string_attribute(parent_msg, "isDeleted", "TRUE")) {
5426                         /* Per MS-DRSR 4.1.10.6.10
5427                          * FindBestParentObject we need to move this
5428                          * new object under a deleted object to
5429                          * lost-and-found */
5430                         struct ldb_dn *nc_root;
5431
5432                         ret = dsdb_find_nc_root(ldb_module_get_ctx(ar->module), msg, msg->dn, &nc_root);
5433                         if (ret == LDB_ERR_NO_SUCH_OBJECT) {
5434                                 ldb_asprintf_errstring(ldb_module_get_ctx(ar->module),
5435                                                        "No suitable NC root found for %s.  "
5436                                                        "We need to move this object because parent object %s "
5437                                                        "is deleted, but this object is not.",
5438                                                        ldb_dn_get_linearized(msg->dn),
5439                                                        ldb_dn_get_linearized(parent_msg->dn));
5440                                 return ldb_module_done(ar->req, NULL, NULL, LDB_ERR_OPERATIONS_ERROR);
5441                         } else if (ret != LDB_SUCCESS) {
5442                                 ldb_asprintf_errstring(ldb_module_get_ctx(ar->module),
5443                                                        "Unable to find NC root for %s: %s. "
5444                                                        "We need to move this object because parent object %s "
5445                                                        "is deleted, but this object is not.",
5446                                                        ldb_dn_get_linearized(msg->dn),
5447                                                        ldb_errstring(ldb_module_get_ctx(ar->module)),
5448                                                        ldb_dn_get_linearized(parent_msg->dn));
5449                                 return ldb_module_done(ar->req, NULL, NULL, LDB_ERR_OPERATIONS_ERROR);
5450                         }
5451
5452                         ret = dsdb_wellknown_dn(ldb_module_get_ctx(ar->module), msg,
5453                                                 nc_root,
5454                                                 DS_GUID_LOSTANDFOUND_CONTAINER,
5455                                                 &parent_dn);
5456                         if (ret != LDB_SUCCESS) {
5457                                 ldb_asprintf_errstring(ldb_module_get_ctx(ar->module),
5458                                                        "Unable to find LostAndFound Container for %s "
5459                                                        "in partition %s: %s. "
5460                                                        "We need to move this object because parent object %s "
5461                                                        "is deleted, but this object is not.",
5462                                                        ldb_dn_get_linearized(msg->dn), ldb_dn_get_linearized(nc_root),
5463                                                        ldb_errstring(ldb_module_get_ctx(ar->module)),
5464                                                        ldb_dn_get_linearized(parent_msg->dn));
5465                                 return ldb_module_done(ar->req, NULL, NULL, LDB_ERR_OPERATIONS_ERROR);
5466                         }
5467                         ar->objs->objects[ar->index_current].last_known_parent
5468                                 = talloc_steal(ar->objs->objects[ar->index_current].msg, parent_msg->dn);
5469
5470                 } else {
5471                         parent_dn
5472                                 = talloc_steal(ar->objs->objects[ar->index_current].msg, parent_msg->dn);
5473
5474                 }
5475                 ar->objs->objects[ar->index_current].local_parent_dn = parent_dn;
5476
5477                 comp_num = ldb_dn_get_comp_num(msg->dn);
5478                 if (comp_num > 1) {
5479                         if (!ldb_dn_remove_base_components(msg->dn, comp_num - 1)) {
5480                                 talloc_free(ares);
5481                                 return ldb_module_done(ar->req, NULL, NULL, ldb_module_operr(ar->module));
5482                         }
5483                 }
5484                 if (!ldb_dn_add_base(msg->dn, parent_dn)) {
5485                         talloc_free(ares);
5486                         return ldb_module_done(ar->req, NULL, NULL, ldb_module_operr(ar->module));
5487                 }
5488                 break;
5489         }
5490         case LDB_REPLY_REFERRAL:
5491                 /* we ignore referrals */
5492                 break;
5493
5494         case LDB_REPLY_DONE:
5495
5496                 if (ar->objs->objects[ar->index_current].local_parent_dn == NULL) {
5497                         struct GUID_txt_buf str_buf;
5498                         if (ar->search_msg != NULL) {
5499                                 ldb_asprintf_errstring(ldb_module_get_ctx(ar->module),
5500                                                        "No parent with GUID %s found for object locally known as %s",
5501                                                        GUID_buf_string(ar->objs->objects[ar->index_current].parent_guid, &str_buf),
5502                                                        ldb_dn_get_linearized(ar->search_msg->dn));
5503                         } else {
5504                                 ldb_asprintf_errstring(ldb_module_get_ctx(ar->module),
5505                                                        "No parent with GUID %s found for object remotely known as %s",
5506                                                        GUID_buf_string(ar->objs->objects[ar->index_current].parent_guid, &str_buf),
5507                                                        ldb_dn_get_linearized(ar->objs->objects[ar->index_current].msg->dn));
5508                         }
5509
5510                         /*
5511                          * This error code is really important, as it
5512                          * is the flag back to the callers to retry
5513                          * this with DRSUAPI_DRS_GET_ANC, and so get
5514                          * the parent objects before the child
5515                          * objects
5516                          */
5517                         return ldb_module_done(ar->req, NULL, NULL,
5518                                                replmd_replicated_request_werror(ar, WERR_DS_DRA_MISSING_PARENT));
5519                 }
5520
5521                 if (ar->search_msg != NULL) {
5522                         ret = replmd_replicated_apply_merge(ar);
5523                 } else {
5524                         ret = replmd_replicated_apply_add(ar);
5525                 }
5526                 if (ret != LDB_SUCCESS) {
5527                         return ldb_module_done(ar->req, NULL, NULL, ret);
5528                 }
5529         }
5530
5531         talloc_free(ares);
5532         return LDB_SUCCESS;
5533 }
5534
5535 /*
5536  * Look for the parent object, so we put the new object in the right
5537  * place This is akin to NameObject in MS-DRSR - this routine and the
5538  * callbacks find the right parent name, and correct name for this
5539  * object
5540  */
5541
5542 static int replmd_replicated_apply_search_for_parent(struct replmd_replicated_request *ar)
5543 {
5544         struct ldb_context *ldb;
5545         int ret;
5546         char *tmp_str;
5547         char *filter;
5548         struct ldb_request *search_req;
5549         static const char *attrs[] = {"isDeleted", NULL};
5550         struct GUID_txt_buf guid_str_buf;
5551
5552         ldb = ldb_module_get_ctx(ar->module);
5553
5554         if (ar->objs->objects[ar->index_current].parent_guid == NULL) {
5555                 if (ar->search_msg != NULL) {
5556                         return replmd_replicated_apply_merge(ar);
5557                 } else {
5558                         return replmd_replicated_apply_add(ar);
5559                 }
5560         }
5561
5562         tmp_str = GUID_buf_string(ar->objs->objects[ar->index_current].parent_guid,
5563                                   &guid_str_buf);
5564
5565         filter = talloc_asprintf(ar, "(objectGUID=%s)", tmp_str);
5566         if (!filter) return replmd_replicated_request_werror(ar, WERR_NOT_ENOUGH_MEMORY);
5567
5568         ret = ldb_build_search_req(&search_req,
5569                                    ldb,
5570                                    ar,
5571                                    ar->objs->partition_dn,
5572                                    LDB_SCOPE_SUBTREE,
5573                                    filter,
5574                                    attrs,
5575                                    NULL,
5576                                    ar,
5577                                    replmd_replicated_apply_search_for_parent_callback,
5578                                    ar->req);
5579         LDB_REQ_SET_LOCATION(search_req);
5580
5581         ret = dsdb_request_add_controls(search_req,
5582                                         DSDB_SEARCH_SHOW_RECYCLED|
5583                                         DSDB_SEARCH_SHOW_DELETED|
5584                                         DSDB_SEARCH_SHOW_EXTENDED_DN);
5585         if (ret != LDB_SUCCESS) {
5586                 return ret;
5587         }
5588
5589         return ldb_next_request(ar->module, search_req);
5590 }
5591
5592 /*
5593   handle renames that come in over DRS replication
5594  */
5595 static int replmd_replicated_handle_rename(struct replmd_replicated_request *ar,
5596                                            struct ldb_message *msg,
5597                                            struct ldb_request *parent,
5598                                            bool *renamed)
5599 {
5600         int ret;
5601         TALLOC_CTX *tmp_ctx = talloc_new(msg);
5602         struct ldb_result *res;
5603         struct ldb_dn *conflict_dn;
5604         const char *attrs[] = { "replPropertyMetaData", "objectGUID", NULL };
5605         const struct ldb_val *omd_value;
5606         struct replPropertyMetaDataBlob omd, *rmd;
5607         enum ndr_err_code ndr_err;
5608         bool rename_incoming_record, rodc;
5609         struct replPropertyMetaData1 *rmd_name, *omd_name;
5610         struct ldb_dn *new_dn;
5611         struct GUID guid;
5612
5613         DEBUG(4,("replmd_replicated_request rename %s => %s\n",
5614                  ldb_dn_get_linearized(ar->search_msg->dn),
5615                  ldb_dn_get_linearized(msg->dn)));
5616
5617
5618         ret = dsdb_module_rename(ar->module, ar->search_msg->dn, msg->dn,
5619                                  DSDB_FLAG_NEXT_MODULE, ar->req);
5620         if (ret == LDB_SUCCESS) {
5621                 talloc_free(tmp_ctx);
5622                 *renamed = true;
5623                 return ret;
5624         }
5625
5626         if (ret != LDB_ERR_ENTRY_ALREADY_EXISTS) {
5627                 talloc_free(tmp_ctx);
5628                 ldb_asprintf_errstring(ldb_module_get_ctx(ar->module), "Failed to locally apply remote rename from %s to %s: %s",
5629                                        ldb_dn_get_linearized(ar->search_msg->dn),
5630                                        ldb_dn_get_linearized(msg->dn),
5631                                        ldb_errstring(ldb_module_get_ctx(ar->module)));
5632                 return ret;
5633         }
5634
5635         ret = samdb_rodc(ldb_module_get_ctx(ar->module), &rodc);
5636         if (ret != LDB_SUCCESS) {
5637                 ldb_asprintf_errstring(ldb_module_get_ctx(ar->module),
5638                                        "Failed to determine if we are an RODC when attempting to form conflict DN: %s",
5639                                        ldb_errstring(ldb_module_get_ctx(ar->module)));
5640                 return LDB_ERR_OPERATIONS_ERROR;
5641         }
5642         /*
5643          * we have a conflict, and need to decide if we will keep the
5644          * new record or the old record
5645          */
5646
5647         conflict_dn = msg->dn;
5648
5649         if (rodc) {
5650                 /*
5651                  * We are on an RODC, or were a GC for this
5652                  * partition, so we have to fail this until
5653                  * someone who owns the partition sorts it
5654                  * out
5655                  */
5656                 ldb_asprintf_errstring(ldb_module_get_ctx(ar->module),
5657                                        "Conflict adding object '%s' from incoming replication but we are read only for the partition.  \n"
5658                                        " - We must fail the operation until a master for this partition resolves the conflict",
5659                                        ldb_dn_get_linearized(conflict_dn));
5660                 ret = LDB_ERR_OPERATIONS_ERROR;
5661                 goto failed;
5662         }
5663
5664         /*
5665          * first we need the replPropertyMetaData attribute from the
5666          * old record
5667          */
5668         ret = dsdb_module_search_dn(ar->module, tmp_ctx, &res, conflict_dn,
5669                                     attrs,
5670                                     DSDB_FLAG_NEXT_MODULE |
5671                                     DSDB_SEARCH_SHOW_DELETED |
5672                                     DSDB_SEARCH_SHOW_RECYCLED, ar->req);
5673         if (ret != LDB_SUCCESS) {
5674                 DEBUG(0,(__location__ ": Unable to find object for conflicting record '%s'\n",
5675                          ldb_dn_get_linearized(conflict_dn)));
5676                 goto failed;
5677         }
5678
5679         omd_value = ldb_msg_find_ldb_val(res->msgs[0], "replPropertyMetaData");
5680         if (omd_value == NULL) {
5681                 DEBUG(0,(__location__ ": Unable to find replPropertyMetaData for conflicting record '%s'\n",
5682                          ldb_dn_get_linearized(conflict_dn)));
5683                 goto failed;
5684         }
5685
5686         ndr_err = ndr_pull_struct_blob(omd_value, res->msgs[0], &omd,
5687                                        (ndr_pull_flags_fn_t)ndr_pull_replPropertyMetaDataBlob);
5688         if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
5689                 DEBUG(0,(__location__ ": Failed to parse old replPropertyMetaData for %s\n",
5690                          ldb_dn_get_linearized(conflict_dn)));
5691                 goto failed;
5692         }
5693
5694         rmd = ar->objs->objects[ar->index_current].meta_data;
5695
5696         /*
5697          * we decide which is newer based on the RPMD on the name
5698          * attribute.  See [MS-DRSR] ResolveNameConflict.
5699          *
5700          * We expect omd_name to be present, as this is from a local
5701          * search, but while rmd_name should have been given to us by
5702          * the remote server, if it is missing we just prefer the
5703          * local name in
5704          * replmd_replPropertyMetaData1_new_should_be_taken()
5705          */
5706         rmd_name = replmd_replPropertyMetaData1_find_attid(rmd, DRSUAPI_ATTID_name);
5707         omd_name = replmd_replPropertyMetaData1_find_attid(&omd, DRSUAPI_ATTID_name);
5708         if (!omd_name) {
5709                 DEBUG(0,(__location__ ": Failed to find name attribute in local LDB replPropertyMetaData for %s\n",
5710                          ldb_dn_get_linearized(conflict_dn)));
5711                 goto failed;
5712         }
5713
5714         /*
5715          * Should we preserve the current record, and so rename the
5716          * incoming record to be a conflict?
5717          */
5718         rename_incoming_record =
5719                 !replmd_replPropertyMetaData1_new_should_be_taken(
5720                         ar->objs->dsdb_repl_flags & DSDB_REPL_FLAG_PRIORITISE_INCOMING,
5721                         omd_name, rmd_name);
5722
5723         if (rename_incoming_record) {
5724
5725                 new_dn = replmd_conflict_dn(msg,
5726                                             ldb_module_get_ctx(ar->module),
5727                                             msg->dn,
5728                                             &ar->objs->objects[ar->index_current].object_guid);
5729                 if (new_dn == NULL) {
5730                         ldb_asprintf_errstring(ldb_module_get_ctx(ar->module),
5731                                                                   "Failed to form conflict DN for %s\n",
5732                                                                   ldb_dn_get_linearized(msg->dn));
5733
5734                         return replmd_replicated_request_werror(ar, WERR_NOT_ENOUGH_MEMORY);
5735                 }
5736
5737                 ret = dsdb_module_rename(ar->module, ar->search_msg->dn, new_dn,
5738                                          DSDB_FLAG_NEXT_MODULE, ar->req);
5739                 if (ret != LDB_SUCCESS) {
5740                         ldb_asprintf_errstring(ldb_module_get_ctx(ar->module),
5741                                                "Failed to rename incoming conflicting dn '%s' (was '%s') to '%s' - %s\n",
5742                                                ldb_dn_get_linearized(conflict_dn),
5743                                                ldb_dn_get_linearized(ar->search_msg->dn),
5744                                                ldb_dn_get_linearized(new_dn),
5745                                                ldb_errstring(ldb_module_get_ctx(ar->module)));
5746                         return replmd_replicated_request_werror(ar, WERR_DS_DRA_DB_ERROR);
5747                 }
5748
5749                 msg->dn = new_dn;
5750                 *renamed = true;
5751                 return LDB_SUCCESS;
5752         }
5753
5754         /* we are renaming the existing record */
5755
5756         guid = samdb_result_guid(res->msgs[0], "objectGUID");
5757         if (GUID_all_zero(&guid)) {
5758                 DEBUG(0,(__location__ ": Failed to find objectGUID for existing conflict record %s\n",
5759                          ldb_dn_get_linearized(conflict_dn)));
5760                 goto failed;
5761         }
5762
5763         new_dn = replmd_conflict_dn(tmp_ctx,
5764                                     ldb_module_get_ctx(ar->module),
5765                                     conflict_dn, &guid);
5766         if (new_dn == NULL) {
5767                 DEBUG(0,(__location__ ": Failed to form conflict DN for %s\n",
5768                          ldb_dn_get_linearized(conflict_dn)));
5769                 goto failed;
5770         }
5771
5772         DEBUG(2,(__location__ ": Resolving conflict record via existing-record rename '%s' -> '%s'\n",
5773                  ldb_dn_get_linearized(conflict_dn), ldb_dn_get_linearized(new_dn)));
5774
5775         ret = dsdb_module_rename(ar->module, conflict_dn, new_dn,
5776                                  DSDB_FLAG_OWN_MODULE, ar->req);
5777         if (ret != LDB_SUCCESS) {
5778                 DEBUG(0,(__location__ ": Failed to rename conflict dn '%s' to '%s' - %s\n",
5779                          ldb_dn_get_linearized(conflict_dn),
5780                          ldb_dn_get_linearized(new_dn),
5781                          ldb_errstring(ldb_module_get_ctx(ar->module))));
5782                 goto failed;
5783         }
5784
5785         /*
5786          * now we need to ensure that the rename is seen as an
5787          * originating update. We do that with a modify.
5788          */
5789         ret = replmd_name_modify(ar, ar->req, new_dn);
5790         if (ret != LDB_SUCCESS) {
5791                 goto failed;
5792         }
5793
5794         DEBUG(2,(__location__ ": With conflicting record renamed, re-apply replicated rename '%s' -> '%s'\n",
5795                  ldb_dn_get_linearized(ar->search_msg->dn),
5796                  ldb_dn_get_linearized(msg->dn)));
5797
5798
5799         ret = dsdb_module_rename(ar->module, ar->search_msg->dn, msg->dn,
5800                                  DSDB_FLAG_NEXT_MODULE, ar->req);
5801         if (ret != LDB_SUCCESS) {
5802                 DEBUG(0,(__location__ ": After conflict resolution, failed to rename dn '%s' to '%s' - %s\n",
5803                          ldb_dn_get_linearized(ar->search_msg->dn),
5804                          ldb_dn_get_linearized(msg->dn),
5805                          ldb_errstring(ldb_module_get_ctx(ar->module))));
5806                         goto failed;
5807         }
5808
5809         talloc_free(tmp_ctx);
5810         return ret;
5811 failed:
5812         /*
5813          * On failure make the caller get the error
5814          * This means replication will stop with an error,
5815          * but there is not much else we can do.  In the
5816          * LDB_ERR_ENTRY_ALREADY_EXISTS case this is exactly what is
5817          * needed.
5818          */
5819         if (ret == LDB_SUCCESS) {
5820                 ret = LDB_ERR_OPERATIONS_ERROR;
5821         }
5822
5823         talloc_free(tmp_ctx);
5824         return ret;
5825 }
5826
5827
5828 static int replmd_replicated_apply_merge(struct replmd_replicated_request *ar)
5829 {
5830         struct ldb_context *ldb;
5831         struct ldb_request *change_req;
5832         enum ndr_err_code ndr_err;
5833         struct ldb_message *msg;
5834         struct replPropertyMetaDataBlob *rmd;
5835         struct replPropertyMetaDataBlob omd;
5836         const struct ldb_val *omd_value;
5837         struct replPropertyMetaDataBlob nmd;
5838         struct ldb_val nmd_value;
5839         struct GUID remote_parent_guid;
5840         unsigned int i;
5841         uint32_t j,ni=0;
5842         unsigned int removed_attrs = 0;
5843         int ret;
5844         int (*callback)(struct ldb_request *req, struct ldb_reply *ares) = replmd_op_callback;
5845         bool isDeleted = false;
5846         bool local_isDeleted = false;
5847         bool remote_isDeleted = false;
5848         bool take_remote_isDeleted = false;
5849         bool sd_updated = false;
5850         bool renamed = false;
5851         bool is_schema_nc = false;
5852         NTSTATUS nt_status;
5853         const struct ldb_val *old_rdn, *new_rdn;
5854         struct replmd_private *replmd_private =
5855                 talloc_get_type(ldb_module_get_private(ar->module),
5856                                 struct replmd_private);
5857         NTTIME now;
5858         time_t t = time(NULL);
5859         unix_to_nt_time(&now, t);
5860
5861         ldb = ldb_module_get_ctx(ar->module);
5862         msg = ar->objs->objects[ar->index_current].msg;
5863
5864         is_schema_nc = ldb_dn_compare_base(replmd_private->schema_dn, msg->dn) == 0;
5865
5866         rmd = ar->objs->objects[ar->index_current].meta_data;
5867         ZERO_STRUCT(omd);
5868         omd.version = 1;
5869
5870         /* find existing meta data */
5871         omd_value = ldb_msg_find_ldb_val(ar->search_msg, "replPropertyMetaData");
5872         if (omd_value) {
5873                 ndr_err = ndr_pull_struct_blob(omd_value, ar, &omd,
5874                                                (ndr_pull_flags_fn_t)ndr_pull_replPropertyMetaDataBlob);
5875                 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
5876                         nt_status = ndr_map_error2ntstatus(ndr_err);
5877                         return replmd_replicated_request_werror(ar, ntstatus_to_werror(nt_status));
5878                 }
5879
5880                 if (omd.version != 1) {
5881                         return replmd_replicated_request_werror(ar, WERR_DS_DRA_INTERNAL_ERROR);
5882                 }
5883         }
5884
5885         if (DEBUGLVL(8)) {
5886                 struct GUID_txt_buf guid_txt;
5887
5888                 char *s = ldb_ldif_message_redacted_string(ldb, ar,
5889                                                            LDB_CHANGETYPE_MODIFY, msg);
5890                 DEBUG(8, ("Initial DRS replication modify message of %s is:\n%s\n"
5891                           "%s\n"
5892                           "%s\n",
5893                           GUID_buf_string(&ar->objs->objects[ar->index_current].object_guid, &guid_txt),
5894                           s,
5895                           ndr_print_struct_string(s,
5896                                                   (ndr_print_fn_t)ndr_print_replPropertyMetaDataBlob,
5897                                                   "existing replPropertyMetaData",
5898                                                   &omd),
5899                           ndr_print_struct_string(s,
5900                                                   (ndr_print_fn_t)ndr_print_replPropertyMetaDataBlob,
5901                                                   "incoming replPropertyMetaData",
5902                                                   rmd)));
5903                 talloc_free(s);
5904         } else if (DEBUGLVL(4)) {
5905                 struct GUID_txt_buf guid_txt;
5906
5907                 DEBUG(4, ("Initial DRS replication modify DN of %s is: %s\n",
5908                           GUID_buf_string(&ar->objs->objects[ar->index_current].object_guid,
5909                                           &guid_txt),
5910                           ldb_dn_get_linearized(msg->dn)));
5911         }
5912                 
5913         local_isDeleted = ldb_msg_find_attr_as_bool(ar->search_msg,
5914                                                     "isDeleted", false);
5915         remote_isDeleted = ldb_msg_find_attr_as_bool(msg,
5916                                                      "isDeleted", false);
5917
5918         /*
5919          * Fill in the remote_parent_guid with the GUID or an all-zero
5920          * GUID.
5921          */
5922         if (ar->objs->objects[ar->index_current].parent_guid != NULL) {
5923                 remote_parent_guid = *ar->objs->objects[ar->index_current].parent_guid;
5924         } else {
5925                 remote_parent_guid = GUID_zero();
5926         }
5927
5928         /*
5929          * To ensure we follow a complex rename chain around, we have
5930          * to confirm that the DN is the same (mostly to confirm the
5931          * RDN) and the parentGUID is the same.
5932          *
5933          * This ensures we keep things under the correct parent, which
5934          * replmd_replicated_handle_rename() will do.
5935          */
5936
5937         if (strcmp(ldb_dn_get_linearized(msg->dn), ldb_dn_get_linearized(ar->search_msg->dn)) == 0
5938             && GUID_equal(&remote_parent_guid, &ar->local_parent_guid)) {
5939                 ret = LDB_SUCCESS;
5940         } else {
5941                 /*
5942                  * handle renames, even just by case that come in over
5943                  * DRS.  Changes in the parent DN don't hit us here,
5944                  * because the search for a parent will clean up those
5945                  * components.
5946                  *
5947                  * We also have already filtered out the case where
5948                  * the peer has an older name to what we have (see
5949                  * replmd_replicated_apply_search_callback())
5950                  */
5951                 ret = replmd_replicated_handle_rename(ar, msg, ar->req, &renamed);
5952         }
5953
5954         if (ret != LDB_SUCCESS) {
5955                 ldb_debug(ldb, LDB_DEBUG_FATAL,
5956                           "replmd_replicated_request rename %s => %s failed - %s\n",
5957                           ldb_dn_get_linearized(ar->search_msg->dn),
5958                           ldb_dn_get_linearized(msg->dn),
5959                           ldb_errstring(ldb));
5960                 return replmd_replicated_request_werror(ar, WERR_DS_DRA_DB_ERROR);
5961         }
5962
5963         if (renamed == true) {
5964                 /*
5965                  * Set the callback to one that will fix up the name
5966                  * metadata on the new conflict DN
5967                  */
5968                 callback = replmd_op_name_modify_callback;
5969         }
5970
5971         ZERO_STRUCT(nmd);
5972         nmd.version = 1;
5973         nmd.ctr.ctr1.count = omd.ctr.ctr1.count + rmd->ctr.ctr1.count;
5974         nmd.ctr.ctr1.array = talloc_array(ar,
5975                                           struct replPropertyMetaData1,
5976                                           nmd.ctr.ctr1.count);
5977         if (!nmd.ctr.ctr1.array) return replmd_replicated_request_werror(ar, WERR_NOT_ENOUGH_MEMORY);
5978
5979         /* first copy the old meta data */
5980         for (i=0; i < omd.ctr.ctr1.count; i++) {
5981                 nmd.ctr.ctr1.array[ni]  = omd.ctr.ctr1.array[i];
5982                 ni++;
5983         }
5984
5985         ar->seq_num = 0;
5986         /* now merge in the new meta data */
5987         for (i=0; i < rmd->ctr.ctr1.count; i++) {
5988                 bool found = false;
5989
5990                 for (j=0; j < ni; j++) {
5991                         bool cmp;
5992
5993                         if (rmd->ctr.ctr1.array[i].attid != nmd.ctr.ctr1.array[j].attid) {
5994                                 continue;
5995                         }
5996
5997                         cmp = replmd_replPropertyMetaData1_new_should_be_taken(
5998                                 ar->objs->dsdb_repl_flags,
5999                                 &nmd.ctr.ctr1.array[j],
6000                                 &rmd->ctr.ctr1.array[i]);
6001                         if (cmp) {
6002                                 /* replace the entry */
6003                                 nmd.ctr.ctr1.array[j] = rmd->ctr.ctr1.array[i];
6004                                 if (ar->seq_num == 0) {
6005                                         ret = ldb_sequence_number(ldb, LDB_SEQ_NEXT, &ar->seq_num);
6006                                         if (ret != LDB_SUCCESS) {
6007                                                 return replmd_replicated_request_error(ar, ret);
6008                                         }
6009                                 }
6010                                 nmd.ctr.ctr1.array[j].local_usn = ar->seq_num;
6011                                 switch (nmd.ctr.ctr1.array[j].attid) {
6012                                 case DRSUAPI_ATTID_ntSecurityDescriptor:
6013                                         sd_updated = true;
6014                                         break;
6015                                 case DRSUAPI_ATTID_isDeleted:
6016                                         take_remote_isDeleted = true;
6017                                         break;
6018                                 default:
6019                                         break;
6020                                 }
6021                                 found = true;
6022                                 break;
6023                         }
6024
6025                         if (rmd->ctr.ctr1.array[i].attid != DRSUAPI_ATTID_instanceType) {
6026                                 DEBUG(3,("Discarding older DRS attribute update to %s on %s from %s\n",
6027                                          msg->elements[i-removed_attrs].name,
6028                                          ldb_dn_get_linearized(msg->dn),
6029                                          GUID_string(ar, &rmd->ctr.ctr1.array[i].originating_invocation_id)));
6030                         }
6031
6032                         /* we don't want to apply this change so remove the attribute */
6033                         ldb_msg_remove_element(msg, &msg->elements[i-removed_attrs]);
6034                         removed_attrs++;
6035
6036                         found = true;
6037                         break;
6038                 }
6039
6040                 if (found) continue;
6041
6042                 nmd.ctr.ctr1.array[ni] = rmd->ctr.ctr1.array[i];
6043                 if (ar->seq_num == 0) {
6044                         ret = ldb_sequence_number(ldb, LDB_SEQ_NEXT, &ar->seq_num);
6045                         if (ret != LDB_SUCCESS) {
6046                                 return replmd_replicated_request_error(ar, ret);
6047                         }
6048                 }
6049                 nmd.ctr.ctr1.array[ni].local_usn = ar->seq_num;
6050                 switch (nmd.ctr.ctr1.array[ni].attid) {
6051                 case DRSUAPI_ATTID_ntSecurityDescriptor:
6052                         sd_updated = true;
6053                         break;
6054                 case DRSUAPI_ATTID_isDeleted:
6055                         take_remote_isDeleted = true;
6056                         break;
6057                 default:
6058                         break;
6059                 }
6060                 ni++;
6061         }
6062
6063         /*
6064          * finally correct the size of the meta_data array
6065          */
6066         nmd.ctr.ctr1.count = ni;
6067
6068         new_rdn = ldb_dn_get_rdn_val(msg->dn);
6069         old_rdn = ldb_dn_get_rdn_val(ar->search_msg->dn);
6070
6071         if (renamed) {
6072                 ret = replmd_update_rpmd_rdn_attr(ldb, msg, new_rdn, old_rdn,
6073                                                   &nmd, ar, now, is_schema_nc,
6074                                                   false);
6075                 if (ret != LDB_SUCCESS) {
6076                         ldb_asprintf_errstring(ldb, "%s: error during DRS repl merge: %s", __func__, ldb_errstring(ldb));
6077                         return replmd_replicated_request_error(ar, ret);
6078                 }
6079         }
6080         /*
6081          * sort the new meta data array
6082          */
6083         ret = replmd_replPropertyMetaDataCtr1_sort_and_verify(ldb, &nmd.ctr.ctr1, msg->dn);
6084         if (ret != LDB_SUCCESS) {
6085                 ldb_asprintf_errstring(ldb, "%s: error during DRS repl merge: %s", __func__, ldb_errstring(ldb));
6086                 return ret;
6087         }
6088
6089         /*
6090          * Work out if this object is deleted, so we can prune any extra attributes.  See MS-DRSR 4.1.10.6.9
6091          * UpdateObject.
6092          *
6093          * This also controls SD propagation below
6094          */
6095         if (take_remote_isDeleted) {
6096                 isDeleted = remote_isDeleted;
6097         } else {
6098                 isDeleted = local_isDeleted;
6099         }
6100
6101         ar->isDeleted = isDeleted;
6102
6103         /*
6104          * check if some replicated attributes left, otherwise skip the ldb_modify() call
6105          */
6106         if (msg->num_elements == 0) {
6107                 ldb_debug(ldb, LDB_DEBUG_TRACE, "replmd_replicated_apply_merge[%u]: skip replace\n",
6108                           ar->index_current);
6109
6110                 return replmd_replicated_apply_isDeleted(ar);
6111         }
6112
6113         ldb_debug(ldb, LDB_DEBUG_TRACE, "replmd_replicated_apply_merge[%u]: replace %u attributes\n",
6114                   ar->index_current, msg->num_elements);
6115
6116         if (renamed) {
6117                 sd_updated = true;
6118         }
6119
6120         if (sd_updated && !isDeleted) {
6121                 ret = dsdb_module_schedule_sd_propagation(ar->module,
6122                                                           ar->objs->partition_dn,
6123                                                           msg->dn, true);
6124                 if (ret != LDB_SUCCESS) {
6125                         return ldb_operr(ldb);
6126                 }
6127         }
6128
6129         /* create the meta data value */
6130         ndr_err = ndr_push_struct_blob(&nmd_value, msg, &nmd,
6131                                        (ndr_push_flags_fn_t)ndr_push_replPropertyMetaDataBlob);
6132         if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
6133                 nt_status = ndr_map_error2ntstatus(ndr_err);
6134                 return replmd_replicated_request_werror(ar, ntstatus_to_werror(nt_status));
6135         }
6136
6137         /*
6138          * when we know that we'll modify the record, add the whenChanged, uSNChanged
6139          * and replPopertyMetaData attributes
6140          */
6141         ret = ldb_msg_add_string(msg, "whenChanged", ar->objs->objects[ar->index_current].when_changed);
6142         if (ret != LDB_SUCCESS) {
6143                 return replmd_replicated_request_error(ar, ret);
6144         }
6145         ret = samdb_msg_add_uint64(ldb, msg, msg, "uSNChanged", ar->seq_num);
6146         if (ret != LDB_SUCCESS) {
6147                 return replmd_replicated_request_error(ar, ret);
6148         }
6149         ret = ldb_msg_add_value(msg, "replPropertyMetaData", &nmd_value, NULL);
6150         if (ret != LDB_SUCCESS) {
6151                 return replmd_replicated_request_error(ar, ret);
6152         }
6153
6154         replmd_ldb_message_sort(msg, ar->schema);
6155
6156         /* we want to replace the old values */
6157         for (i=0; i < msg->num_elements; i++) {
6158                 msg->elements[i].flags = LDB_FLAG_MOD_REPLACE;
6159                 if (ldb_attr_cmp(msg->elements[i].name, "objectClass") == 0) {
6160                         if (msg->elements[i].num_values == 0) {
6161                                 ldb_asprintf_errstring(ldb, __location__
6162                                                        ": objectClass removed on %s, aborting replication\n",
6163                                                        ldb_dn_get_linearized(msg->dn));
6164                                 return replmd_replicated_request_error(ar, LDB_ERR_OBJECT_CLASS_VIOLATION);
6165                         }
6166                 }
6167         }
6168
6169         if (DEBUGLVL(8)) {
6170                 struct GUID_txt_buf guid_txt;
6171
6172                 char *s = ldb_ldif_message_redacted_string(ldb, ar,
6173                                                            LDB_CHANGETYPE_MODIFY,
6174                                                            msg);
6175                 DEBUG(8, ("Final DRS replication modify message of %s:\n%s\n",
6176                           GUID_buf_string(&ar->objs->objects[ar->index_current].object_guid,
6177                                           &guid_txt),
6178                           s));
6179                 talloc_free(s);
6180         } else if (DEBUGLVL(4)) {
6181                 struct GUID_txt_buf guid_txt;
6182
6183                 DEBUG(4, ("Final DRS replication modify DN of %s is %s\n",
6184                           GUID_buf_string(&ar->objs->objects[ar->index_current].object_guid,
6185                                           &guid_txt),
6186                           ldb_dn_get_linearized(msg->dn)));
6187         }
6188
6189         ret = ldb_build_mod_req(&change_req,
6190                                 ldb,
6191                                 ar,
6192                                 msg,
6193                                 ar->controls,
6194                                 ar,
6195                                 callback,
6196                                 ar->req);
6197         LDB_REQ_SET_LOCATION(change_req);
6198         if (ret != LDB_SUCCESS) return replmd_replicated_request_error(ar, ret);
6199
6200         /* current partition control needed by "repmd_op_callback" */
6201         ret = ldb_request_add_control(change_req,
6202                                       DSDB_CONTROL_CURRENT_PARTITION_OID,
6203                                       false, NULL);
6204         if (ret != LDB_SUCCESS) return replmd_replicated_request_error(ar, ret);
6205
6206         return ldb_next_request(ar->module, change_req);
6207 }
6208
6209 static int replmd_replicated_apply_search_callback(struct ldb_request *req,
6210                                                    struct ldb_reply *ares)
6211 {
6212         struct replmd_replicated_request *ar = talloc_get_type(req->context,
6213                                                struct replmd_replicated_request);
6214         int ret;
6215
6216         if (!ares) {
6217                 return ldb_module_done(ar->req, NULL, NULL,
6218                                         LDB_ERR_OPERATIONS_ERROR);
6219         }
6220         if (ares->error != LDB_SUCCESS &&
6221             ares->error != LDB_ERR_NO_SUCH_OBJECT) {
6222                 return ldb_module_done(ar->req, ares->controls,
6223                                         ares->response, ares->error);
6224         }
6225
6226         switch (ares->type) {
6227         case LDB_REPLY_ENTRY:
6228                 ar->search_msg = talloc_steal(ar, ares->message);
6229                 break;
6230
6231         case LDB_REPLY_REFERRAL:
6232                 /* we ignore referrals */
6233                 break;
6234
6235         case LDB_REPLY_DONE:
6236         {
6237                 struct replPropertyMetaData1 *md_remote;
6238                 struct replPropertyMetaData1 *md_local;
6239
6240                 struct replPropertyMetaDataBlob omd;
6241                 const struct ldb_val *omd_value;
6242                 struct replPropertyMetaDataBlob *rmd;
6243                 struct ldb_message *msg;
6244                 int instanceType;
6245                 ar->objs->objects[ar->index_current].local_parent_dn = NULL;
6246                 ar->objs->objects[ar->index_current].last_known_parent = NULL;
6247
6248                 /*
6249                  * This is the ADD case, find the appropriate parent,
6250                  * as this object doesn't exist locally:
6251                  */
6252                 if (ar->search_msg == NULL) {
6253                         ret = replmd_replicated_apply_search_for_parent(ar);
6254                         if (ret != LDB_SUCCESS) {
6255                                 return ldb_module_done(ar->req, NULL, NULL, ret);
6256                         }
6257                         talloc_free(ares);
6258                         return LDB_SUCCESS;
6259                 }
6260
6261                 /*
6262                  * Otherwise, in the MERGE case, work out if we are
6263                  * attempting a rename, and if so find the parent the
6264                  * newly renamed object wants to belong under (which
6265                  * may not be the parent in it's attached string DN
6266                  */
6267                 rmd = ar->objs->objects[ar->index_current].meta_data;
6268                 ZERO_STRUCT(omd);
6269                 omd.version = 1;
6270
6271                 /* find existing meta data */
6272                 omd_value = ldb_msg_find_ldb_val(ar->search_msg, "replPropertyMetaData");
6273                 if (omd_value) {
6274                         enum ndr_err_code ndr_err;
6275                         ndr_err = ndr_pull_struct_blob(omd_value, ar, &omd,
6276                                                        (ndr_pull_flags_fn_t)ndr_pull_replPropertyMetaDataBlob);
6277                         if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
6278                                 NTSTATUS nt_status = ndr_map_error2ntstatus(ndr_err);
6279                                 return replmd_replicated_request_werror(ar, ntstatus_to_werror(nt_status));
6280                         }
6281
6282                         if (omd.version != 1) {
6283                                 return replmd_replicated_request_werror(ar, WERR_DS_DRA_INTERNAL_ERROR);
6284                         }
6285                 }
6286
6287                 ar->local_parent_guid = samdb_result_guid(ar->search_msg, "parentGUID");
6288
6289                 instanceType = ldb_msg_find_attr_as_int(ar->search_msg, "instanceType", 0);
6290                 if (((instanceType & INSTANCE_TYPE_IS_NC_HEAD) == 0)
6291                     && GUID_all_zero(&ar->local_parent_guid)) {
6292                         DEBUG(0, ("Refusing to replicate new version of %s "
6293                                   "as local object has an all-zero parentGUID attribute, "
6294                                   "despite not being an NC root\n",
6295                                   ldb_dn_get_linearized(ar->search_msg->dn)));
6296                         return replmd_replicated_request_werror(ar, WERR_DS_DRA_INTERNAL_ERROR);
6297                 }
6298
6299                 /*
6300                  * now we need to check for double renames. We could have a
6301                  * local rename pending which our replication partner hasn't
6302                  * received yet. We choose which one wins by looking at the
6303                  * attribute stamps on the two objects, the newer one wins.
6304                  *
6305                  * This also simply applies the correct algorithms for
6306                  * determining if a change was made to name at all, or
6307                  * if the object has just been renamed under the same
6308                  * parent.
6309                  */
6310                 md_remote = replmd_replPropertyMetaData1_find_attid(rmd, DRSUAPI_ATTID_name);
6311                 md_local = replmd_replPropertyMetaData1_find_attid(&omd, DRSUAPI_ATTID_name);
6312                 if (!md_local) {
6313                         DEBUG(0,(__location__ ": Failed to find name attribute in local LDB replPropertyMetaData for %s\n",
6314                                  ldb_dn_get_linearized(ar->search_msg->dn)));
6315                         return replmd_replicated_request_werror(ar, WERR_DS_DRA_DB_ERROR);
6316                 }
6317
6318                 /*
6319                  * if there is no name attribute given then we have to assume the
6320                  *  object we've received has the older name
6321                  */
6322                 if (replmd_replPropertyMetaData1_new_should_be_taken(
6323                             ar->objs->dsdb_repl_flags & DSDB_REPL_FLAG_PRIORITISE_INCOMING,
6324                             md_local, md_remote)) {
6325                         struct GUID_txt_buf p_guid_local;
6326                         struct GUID_txt_buf p_guid_remote;
6327                         msg = ar->objs->objects[ar->index_current].msg;
6328
6329                         /* Merge on the existing object, with rename */
6330
6331                         DEBUG(4,(__location__ ": Looking for new parent for object %s currently under %s "
6332                                  "as incoming object changing to %s under %s\n",
6333                                  ldb_dn_get_linearized(ar->search_msg->dn),
6334                                  GUID_buf_string(&ar->local_parent_guid, &p_guid_local),
6335                                  ldb_dn_get_linearized(msg->dn),
6336                                  GUID_buf_string(ar->objs->objects[ar->index_current].parent_guid,
6337                                                  &p_guid_remote)));
6338                         ret = replmd_replicated_apply_search_for_parent(ar);
6339                 } else {
6340                         struct GUID_txt_buf p_guid_local;
6341                         struct GUID_txt_buf p_guid_remote;
6342                         msg = ar->objs->objects[ar->index_current].msg;
6343
6344                         /*
6345                          * Merge on the existing object, force no
6346                          * rename (code below just to explain why in
6347                          * the DEBUG() logs)
6348                          */
6349
6350                         if (strcmp(ldb_dn_get_linearized(ar->search_msg->dn),
6351                                    ldb_dn_get_linearized(msg->dn)) == 0) {
6352                                 if (ar->objs->objects[ar->index_current].parent_guid != NULL &&
6353                                     GUID_equal(&ar->local_parent_guid,
6354                                                ar->objs->objects[ar->index_current].parent_guid)
6355                                     == false) {
6356                                         DEBUG(4,(__location__ ": Keeping object %s at under %s "
6357                                                  "despite incoming object changing parent to %s\n",
6358                                                  ldb_dn_get_linearized(ar->search_msg->dn),
6359                                                  GUID_buf_string(&ar->local_parent_guid, &p_guid_local),
6360                                                  GUID_buf_string(ar->objs->objects[ar->index_current].parent_guid,
6361                                                                  &p_guid_remote)));
6362                                 }
6363                         } else {
6364                                 DEBUG(4,(__location__ ": Keeping object %s at under %s "
6365                                          " and rejecting older rename to %s under %s\n",
6366                                          ldb_dn_get_linearized(ar->search_msg->dn),
6367                                          GUID_buf_string(&ar->local_parent_guid, &p_guid_local),
6368                                          ldb_dn_get_linearized(msg->dn),
6369                                          GUID_buf_string(ar->objs->objects[ar->index_current].parent_guid,
6370                                                          &p_guid_remote)));
6371                         }
6372                         /*
6373                          * This assignment ensures that the strcmp()
6374                          * and GUID_equal() calls in
6375                          * replmd_replicated_apply_merge() avoids the
6376                          * rename call
6377                          */
6378                         ar->objs->objects[ar->index_current].parent_guid =
6379                                 &ar->local_parent_guid;
6380
6381                         msg->dn = ar->search_msg->dn;
6382                         ret = replmd_replicated_apply_merge(ar);
6383                 }
6384                 if (ret != LDB_SUCCESS) {
6385                         return ldb_module_done(ar->req, NULL, NULL, ret);
6386                 }
6387         }
6388         }
6389
6390         talloc_free(ares);
6391         return LDB_SUCCESS;
6392 }
6393
6394 /**
6395  * Stores the linked attributes received in the replication chunk - these get
6396  * applied at the end of the transaction. We also check that each linked
6397  * attribute is valid, i.e. source and target objects are known.
6398  */
6399 static int replmd_store_linked_attributes(struct replmd_replicated_request *ar)
6400 {
6401         int ret = LDB_SUCCESS;
6402         uint32_t i;
6403         struct ldb_module *module = ar->module;
6404         struct replmd_private *replmd_private =
6405                 talloc_get_type(ldb_module_get_private(module), struct replmd_private);
6406         struct ldb_context *ldb;
6407
6408         ldb = ldb_module_get_ctx(module);
6409
6410         DEBUG(4,("linked_attributes_count=%u\n", ar->objs->linked_attributes_count));
6411
6412         /* save away the linked attributes for the end of the transaction */
6413         for (i = 0; i < ar->objs->linked_attributes_count; i++) {
6414                 struct la_entry *la_entry;
6415
6416                 if (replmd_private->la_ctx == NULL) {
6417                         replmd_private->la_ctx = talloc_new(replmd_private);
6418                 }
6419                 la_entry = talloc(replmd_private->la_ctx, struct la_entry);
6420                 if (la_entry == NULL) {
6421                         ldb_oom(ldb);
6422                         return LDB_ERR_OPERATIONS_ERROR;
6423                 }
6424                 la_entry->la = talloc(la_entry, struct drsuapi_DsReplicaLinkedAttribute);
6425                 if (la_entry->la == NULL) {
6426                         talloc_free(la_entry);
6427                         ldb_oom(ldb);
6428                         return LDB_ERR_OPERATIONS_ERROR;
6429                 }
6430                 *la_entry->la = ar->objs->linked_attributes[i];
6431                 la_entry->dsdb_repl_flags = ar->objs->dsdb_repl_flags;
6432
6433                 /* we need to steal the non-scalars so they stay
6434                    around until the end of the transaction */
6435                 talloc_steal(la_entry->la, la_entry->la->identifier);
6436                 talloc_steal(la_entry->la, la_entry->la->value.blob);
6437
6438                 ret = replmd_verify_linked_attribute(ar, la_entry);
6439
6440                 if (ret != LDB_SUCCESS) {
6441                         break;
6442                 }
6443
6444                 DLIST_ADD(replmd_private->la_list, la_entry);
6445         }
6446
6447         return ret;
6448 }
6449
6450 static int replmd_replicated_uptodate_vector(struct replmd_replicated_request *ar);
6451
6452 static int replmd_replicated_apply_next(struct replmd_replicated_request *ar)
6453 {
6454         struct ldb_context *ldb;
6455         int ret;
6456         char *tmp_str;
6457         char *filter;
6458         struct ldb_request *search_req;
6459         static const char *attrs[] = { "repsFrom", "replUpToDateVector",
6460                                        "parentGUID", "instanceType",
6461                                        "replPropertyMetaData", "nTSecurityDescriptor",
6462                                        "isDeleted", NULL };
6463         struct GUID_txt_buf guid_str_buf;
6464
6465         if (ar->index_current >= ar->objs->num_objects) {
6466
6467                 /*
6468                  * Now that we've applied all the objects, check the new linked
6469                  * attributes and store them (we apply them in .prepare_commit)
6470                  */
6471                 ret = replmd_store_linked_attributes(ar);
6472
6473                 if (ret != LDB_SUCCESS) {
6474                         return ret;
6475                 }
6476
6477                 /* done applying objects, move on to the next stage */
6478                 return replmd_replicated_uptodate_vector(ar);
6479         }
6480
6481         ldb = ldb_module_get_ctx(ar->module);
6482         ar->search_msg = NULL;
6483         ar->isDeleted = false;
6484
6485         tmp_str = GUID_buf_string(&ar->objs->objects[ar->index_current].object_guid,
6486                                   &guid_str_buf);
6487
6488         filter = talloc_asprintf(ar, "(objectGUID=%s)", tmp_str);
6489         if (!filter) return replmd_replicated_request_werror(ar, WERR_NOT_ENOUGH_MEMORY);
6490
6491         ret = ldb_build_search_req(&search_req,
6492                                    ldb,
6493                                    ar,
6494                                    ar->objs->partition_dn,
6495                                    LDB_SCOPE_SUBTREE,
6496                                    filter,
6497                                    attrs,
6498                                    NULL,
6499                                    ar,
6500                                    replmd_replicated_apply_search_callback,
6501                                    ar->req);
6502         LDB_REQ_SET_LOCATION(search_req);
6503
6504         ret = dsdb_request_add_controls(search_req, DSDB_SEARCH_SHOW_RECYCLED);
6505
6506         if (ret != LDB_SUCCESS) {
6507                 return ret;
6508         }
6509
6510         return ldb_next_request(ar->module, search_req);
6511 }
6512
6513 /*
6514  * This is essentially a wrapper for replmd_replicated_apply_next()
6515  *
6516  * This is needed to ensure that both codepaths call this handler.
6517  */
6518 static int replmd_replicated_apply_isDeleted(struct replmd_replicated_request *ar)
6519 {
6520         struct ldb_dn *deleted_objects_dn;
6521         struct ldb_message *msg = ar->objs->objects[ar->index_current].msg;
6522         int ret = dsdb_get_deleted_objects_dn(ldb_module_get_ctx(ar->module), msg, msg->dn,
6523                                               &deleted_objects_dn);
6524         if (ar->isDeleted && (ret != LDB_SUCCESS || ldb_dn_compare(msg->dn, deleted_objects_dn) != 0)) {
6525                 /*
6526                  * Do a delete here again, so that if there is
6527                  * anything local that conflicts with this
6528                  * object being deleted, it is removed.  This
6529                  * includes links.  See MS-DRSR 4.1.10.6.9
6530                  * UpdateObject.
6531                  *
6532                  * If the object is already deleted, and there
6533                  * is no more work required, it doesn't do
6534                  * anything.
6535                  */
6536
6537                 /* This has been updated to point to the DN we eventually did the modify on */
6538
6539                 struct ldb_request *del_req;
6540                 struct ldb_result *res;
6541
6542                 TALLOC_CTX *tmp_ctx = talloc_new(ar);
6543                 if (!tmp_ctx) {
6544                         ret = ldb_oom(ldb_module_get_ctx(ar->module));
6545                         return ret;
6546                 }
6547
6548                 res = talloc_zero(tmp_ctx, struct ldb_result);
6549                 if (!res) {
6550                         ret = ldb_oom(ldb_module_get_ctx(ar->module));
6551                         talloc_free(tmp_ctx);
6552                         return ret;
6553                 }
6554
6555                 /* Build a delete request, which hopefully will artually turn into nothing */
6556                 ret = ldb_build_del_req(&del_req, ldb_module_get_ctx(ar->module), tmp_ctx,
6557                                         msg->dn,
6558                                         NULL,
6559                                         res,
6560                                         ldb_modify_default_callback,
6561                                         ar->req);
6562                 LDB_REQ_SET_LOCATION(del_req);
6563                 if (ret != LDB_SUCCESS) {
6564                         talloc_free(tmp_ctx);
6565                         return ret;
6566                 }
6567
6568                 /*
6569                  * This is the guts of the call, call back
6570                  * into our delete code, but setting the
6571                  * re_delete flag so we delete anything that
6572                  * shouldn't be there on a deleted or recycled
6573                  * object
6574                  */
6575                 ret = replmd_delete_internals(ar->module, del_req, true);
6576                 if (ret == LDB_SUCCESS) {
6577                         ret = ldb_wait(del_req->handle, LDB_WAIT_ALL);
6578                 }
6579
6580                 talloc_free(tmp_ctx);
6581                 if (ret != LDB_SUCCESS) {
6582                         return ret;
6583                 }
6584         }
6585
6586         ar->index_current++;
6587         return replmd_replicated_apply_next(ar);
6588 }
6589
6590 static int replmd_replicated_uptodate_modify_callback(struct ldb_request *req,
6591                                                       struct ldb_reply *ares)
6592 {
6593         struct ldb_context *ldb;
6594         struct replmd_replicated_request *ar = talloc_get_type(req->context,
6595                                                struct replmd_replicated_request);
6596         ldb = ldb_module_get_ctx(ar->module);
6597
6598         if (!ares) {
6599                 return ldb_module_done(ar->req, NULL, NULL,
6600                                         LDB_ERR_OPERATIONS_ERROR);
6601         }
6602         if (ares->error != LDB_SUCCESS) {
6603                 return ldb_module_done(ar->req, ares->controls,
6604                                         ares->response, ares->error);
6605         }
6606
6607         if (ares->type != LDB_REPLY_DONE) {
6608                 ldb_asprintf_errstring(ldb, "Invalid LDB reply type %d", ares->type);
6609                 return ldb_module_done(ar->req, NULL, NULL,
6610                                         LDB_ERR_OPERATIONS_ERROR);
6611         }
6612
6613         talloc_free(ares);
6614
6615         return ldb_module_done(ar->req, NULL, NULL, LDB_SUCCESS);
6616 }
6617
6618 static int replmd_replicated_uptodate_modify(struct replmd_replicated_request *ar)
6619 {
6620         struct ldb_context *ldb;
6621         struct ldb_request *change_req;
6622         enum ndr_err_code ndr_err;
6623         struct ldb_message *msg;
6624         struct replUpToDateVectorBlob ouv;
6625         const struct ldb_val *ouv_value;
6626         const struct drsuapi_DsReplicaCursor2CtrEx *ruv;
6627         struct replUpToDateVectorBlob nuv;
6628         struct ldb_val nuv_value;
6629         struct ldb_message_element *nuv_el = NULL;
6630         struct ldb_message_element *orf_el = NULL;
6631         struct repsFromToBlob nrf;
6632         struct ldb_val *nrf_value = NULL;
6633         struct ldb_message_element *nrf_el = NULL;
6634         unsigned int i;
6635         uint32_t j,ni=0;
6636         bool found = false;
6637         time_t t = time(NULL);
6638         NTTIME now;
6639         int ret;
6640         uint32_t instanceType;
6641
6642         ldb = ldb_module_get_ctx(ar->module);
6643         ruv = ar->objs->uptodateness_vector;
6644         ZERO_STRUCT(ouv);
6645         ouv.version = 2;
6646         ZERO_STRUCT(nuv);
6647         nuv.version = 2;
6648
6649         unix_to_nt_time(&now, t);
6650
6651         if (ar->search_msg == NULL) {
6652                 /* this happens for a REPL_OBJ call where we are
6653                    creating the target object by replicating it. The
6654                    subdomain join code does this for the partition DN
6655                 */
6656                 DEBUG(4,(__location__ ": Skipping UDV and repsFrom update as no target DN\n"));
6657                 return ldb_module_done(ar->req, NULL, NULL, LDB_SUCCESS);
6658         }
6659
6660         instanceType = ldb_msg_find_attr_as_uint(ar->search_msg, "instanceType", 0);
6661         if (! (instanceType & INSTANCE_TYPE_IS_NC_HEAD)) {
6662                 DEBUG(4,(__location__ ": Skipping UDV and repsFrom update as not NC root: %s\n",
6663                          ldb_dn_get_linearized(ar->search_msg->dn)));
6664                 return ldb_module_done(ar->req, NULL, NULL, LDB_SUCCESS);
6665         }
6666
6667         /*
6668          * first create the new replUpToDateVector
6669          */
6670         ouv_value = ldb_msg_find_ldb_val(ar->search_msg, "replUpToDateVector");
6671         if (ouv_value) {
6672                 ndr_err = ndr_pull_struct_blob(ouv_value, ar, &ouv,
6673                                                (ndr_pull_flags_fn_t)ndr_pull_replUpToDateVectorBlob);
6674                 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
6675                         NTSTATUS nt_status = ndr_map_error2ntstatus(ndr_err);
6676                         return replmd_replicated_request_werror(ar, ntstatus_to_werror(nt_status));
6677                 }
6678
6679                 if (ouv.version != 2) {
6680                         return replmd_replicated_request_werror(ar, WERR_DS_DRA_INTERNAL_ERROR);
6681                 }
6682         }
6683
6684         /*
6685          * the new uptodateness vector will at least
6686          * contain 1 entry, one for the source_dsa
6687          *
6688          * plus optional values from our old vector and the one from the source_dsa
6689          */
6690         nuv.ctr.ctr2.count = ouv.ctr.ctr2.count;
6691         if (ruv) nuv.ctr.ctr2.count += ruv->count;
6692         nuv.ctr.ctr2.cursors = talloc_array(ar,
6693                                             struct drsuapi_DsReplicaCursor2,
6694                                             nuv.ctr.ctr2.count);
6695         if (!nuv.ctr.ctr2.cursors) return replmd_replicated_request_werror(ar, WERR_NOT_ENOUGH_MEMORY);
6696
6697         /* first copy the old vector */
6698         for (i=0; i < ouv.ctr.ctr2.count; i++) {
6699                 nuv.ctr.ctr2.cursors[ni] = ouv.ctr.ctr2.cursors[i];
6700                 ni++;
6701         }
6702
6703         /* merge in the source_dsa vector is available */
6704         for (i=0; (ruv && i < ruv->count); i++) {
6705                 found = false;
6706
6707                 if (GUID_equal(&ruv->cursors[i].source_dsa_invocation_id,
6708                                &ar->our_invocation_id)) {
6709                         continue;
6710                 }
6711
6712                 for (j=0; j < ni; j++) {
6713                         if (!GUID_equal(&ruv->cursors[i].source_dsa_invocation_id,
6714                                         &nuv.ctr.ctr2.cursors[j].source_dsa_invocation_id)) {
6715                                 continue;
6716                         }
6717
6718                         found = true;
6719
6720                         if (ruv->cursors[i].highest_usn > nuv.ctr.ctr2.cursors[j].highest_usn) {
6721                                 nuv.ctr.ctr2.cursors[j] = ruv->cursors[i];
6722                         }
6723                         break;
6724                 }
6725
6726                 if (found) continue;
6727
6728                 /* if it's not there yet, add it */
6729                 nuv.ctr.ctr2.cursors[ni] = ruv->cursors[i];
6730                 ni++;
6731         }
6732
6733         /*
6734          * finally correct the size of the cursors array
6735          */
6736         nuv.ctr.ctr2.count = ni;
6737
6738         /*
6739          * sort the cursors
6740          */
6741         TYPESAFE_QSORT(nuv.ctr.ctr2.cursors, nuv.ctr.ctr2.count, drsuapi_DsReplicaCursor2_compare);
6742
6743         /*
6744          * create the change ldb_message
6745          */
6746         msg = ldb_msg_new(ar);
6747         if (!msg) return replmd_replicated_request_werror(ar, WERR_NOT_ENOUGH_MEMORY);
6748         msg->dn = ar->search_msg->dn;
6749
6750         ndr_err = ndr_push_struct_blob(&nuv_value, msg, &nuv,
6751                                        (ndr_push_flags_fn_t)ndr_push_replUpToDateVectorBlob);
6752         if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
6753                 NTSTATUS nt_status = ndr_map_error2ntstatus(ndr_err);
6754                 return replmd_replicated_request_werror(ar, ntstatus_to_werror(nt_status));
6755         }
6756         ret = ldb_msg_add_value(msg, "replUpToDateVector", &nuv_value, &nuv_el);
6757         if (ret != LDB_SUCCESS) {
6758                 return replmd_replicated_request_error(ar, ret);
6759         }
6760         nuv_el->flags = LDB_FLAG_MOD_REPLACE;
6761
6762         /*
6763          * now create the new repsFrom value from the given repsFromTo1 structure
6764          */
6765         ZERO_STRUCT(nrf);
6766         nrf.version                                     = 1;
6767         nrf.ctr.ctr1                                    = *ar->objs->source_dsa;
6768         nrf.ctr.ctr1.last_attempt                       = now;
6769         nrf.ctr.ctr1.last_success                       = now;
6770         nrf.ctr.ctr1.result_last_attempt                = WERR_OK;
6771
6772         /*
6773          * first see if we already have a repsFrom value for the current source dsa
6774          * if so we'll later replace this value
6775          */
6776         orf_el = ldb_msg_find_element(ar->search_msg, "repsFrom");
6777         if (orf_el) {
6778                 for (i=0; i < orf_el->num_values; i++) {
6779                         struct repsFromToBlob *trf;
6780
6781                         trf = talloc(ar, struct repsFromToBlob);
6782                         if (!trf) return replmd_replicated_request_werror(ar, WERR_NOT_ENOUGH_MEMORY);
6783
6784                         ndr_err = ndr_pull_struct_blob(&orf_el->values[i], trf, trf,
6785                                                        (ndr_pull_flags_fn_t)ndr_pull_repsFromToBlob);
6786                         if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
6787                                 NTSTATUS nt_status = ndr_map_error2ntstatus(ndr_err);
6788                                 return replmd_replicated_request_werror(ar, ntstatus_to_werror(nt_status));
6789                         }
6790
6791                         if (trf->version != 1) {
6792                                 return replmd_replicated_request_werror(ar, WERR_DS_DRA_INTERNAL_ERROR);
6793                         }
6794
6795                         /*
6796                          * we compare the source dsa objectGUID not the invocation_id
6797                          * because we want only one repsFrom value per source dsa
6798                          * and when the invocation_id of the source dsa has changed we don't need
6799                          * the old repsFrom with the old invocation_id
6800                          */
6801                         if (!GUID_equal(&trf->ctr.ctr1.source_dsa_obj_guid,
6802                                         &ar->objs->source_dsa->source_dsa_obj_guid)) {
6803                                 talloc_free(trf);
6804                                 continue;
6805                         }
6806
6807                         talloc_free(trf);
6808                         nrf_value = &orf_el->values[i];
6809                         break;
6810                 }
6811
6812                 /*
6813                  * copy over all old values to the new ldb_message
6814                  */
6815                 ret = ldb_msg_add_empty(msg, "repsFrom", 0, &nrf_el);
6816                 if (ret != LDB_SUCCESS) return replmd_replicated_request_error(ar, ret);
6817                 *nrf_el = *orf_el;
6818         }
6819
6820         /*
6821          * if we haven't found an old repsFrom value for the current source dsa
6822          * we'll add a new value
6823          */
6824         if (!nrf_value) {
6825                 struct ldb_val zero_value;
6826                 ZERO_STRUCT(zero_value);
6827                 ret = ldb_msg_add_value(msg, "repsFrom", &zero_value, &nrf_el);
6828                 if (ret != LDB_SUCCESS) return replmd_replicated_request_error(ar, ret);
6829
6830                 nrf_value = &nrf_el->values[nrf_el->num_values - 1];
6831         }
6832
6833         /* we now fill the value which is already attached to ldb_message */
6834         ndr_err = ndr_push_struct_blob(nrf_value, msg,
6835                                        &nrf,
6836                                        (ndr_push_flags_fn_t)ndr_push_repsFromToBlob);
6837         if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
6838                 NTSTATUS nt_status = ndr_map_error2ntstatus(ndr_err);
6839                 return replmd_replicated_request_werror(ar, ntstatus_to_werror(nt_status));
6840         }
6841
6842         /*
6843          * the ldb_message_element for the attribute, has all the old values and the new one
6844          * so we'll replace the whole attribute with all values
6845          */
6846         nrf_el->flags = LDB_FLAG_MOD_REPLACE;
6847
6848         if (CHECK_DEBUGLVL(4)) {
6849                 char *s = ldb_ldif_message_redacted_string(ldb, ar,
6850                                                            LDB_CHANGETYPE_MODIFY,
6851                                                            msg);
6852                 DEBUG(4, ("DRS replication uptodate modify message:\n%s\n", s));
6853                 talloc_free(s);
6854         }
6855
6856         /* prepare the ldb_modify() request */
6857         ret = ldb_build_mod_req(&change_req,
6858                                 ldb,
6859                                 ar,
6860                                 msg,
6861                                 ar->controls,
6862                                 ar,
6863                                 replmd_replicated_uptodate_modify_callback,
6864                                 ar->req);
6865         LDB_REQ_SET_LOCATION(change_req);
6866         if (ret != LDB_SUCCESS) return replmd_replicated_request_error(ar, ret);
6867
6868         return ldb_next_request(ar->module, change_req);
6869 }
6870
6871 static int replmd_replicated_uptodate_search_callback(struct ldb_request *req,
6872                                                       struct ldb_reply *ares)
6873 {
6874         struct replmd_replicated_request *ar = talloc_get_type(req->context,
6875                                                struct replmd_replicated_request);
6876         int ret;
6877
6878         if (!ares) {
6879                 return ldb_module_done(ar->req, NULL, NULL,
6880                                         LDB_ERR_OPERATIONS_ERROR);
6881         }
6882         if (ares->error != LDB_SUCCESS &&
6883             ares->error != LDB_ERR_NO_SUCH_OBJECT) {
6884                 return ldb_module_done(ar->req, ares->controls,
6885                                         ares->response, ares->error);
6886         }
6887
6888         switch (ares->type) {
6889         case LDB_REPLY_ENTRY:
6890                 ar->search_msg = talloc_steal(ar, ares->message);
6891                 break;
6892
6893         case LDB_REPLY_REFERRAL:
6894                 /* we ignore referrals */
6895                 break;
6896
6897         case LDB_REPLY_DONE:
6898                 ret = replmd_replicated_uptodate_modify(ar);
6899                 if (ret != LDB_SUCCESS) {
6900                         return ldb_module_done(ar->req, NULL, NULL, ret);
6901                 }
6902         }
6903
6904         talloc_free(ares);
6905         return LDB_SUCCESS;
6906 }
6907
6908
6909 static int replmd_replicated_uptodate_vector(struct replmd_replicated_request *ar)
6910 {
6911         struct ldb_context *ldb = ldb_module_get_ctx(ar->module);
6912         struct replmd_private *replmd_private =
6913                 talloc_get_type_abort(ldb_module_get_private(ar->module),
6914                 struct replmd_private);
6915         int ret;
6916         static const char *attrs[] = {
6917                 "replUpToDateVector",
6918                 "repsFrom",
6919                 "instanceType",
6920                 NULL
6921         };
6922         struct ldb_request *search_req;
6923
6924         ar->search_msg = NULL;
6925
6926         /*
6927          * Let the caller know that we did an originating updates
6928          */
6929         ar->objs->originating_updates = replmd_private->originating_updates;
6930
6931         ret = ldb_build_search_req(&search_req,
6932                                    ldb,
6933                                    ar,
6934                                    ar->objs->partition_dn,
6935                                    LDB_SCOPE_BASE,
6936                                    "(objectClass=*)",
6937                                    attrs,
6938                                    NULL,
6939                                    ar,
6940                                    replmd_replicated_uptodate_search_callback,
6941                                    ar->req);
6942         LDB_REQ_SET_LOCATION(search_req);
6943         if (ret != LDB_SUCCESS) return replmd_replicated_request_error(ar, ret);
6944
6945         return ldb_next_request(ar->module, search_req);
6946 }
6947
6948
6949
6950 static int replmd_extended_replicated_objects(struct ldb_module *module, struct ldb_request *req)
6951 {
6952         struct ldb_context *ldb;
6953         struct dsdb_extended_replicated_objects *objs;
6954         struct replmd_replicated_request *ar;
6955         struct ldb_control **ctrls;
6956         int ret;
6957
6958         ldb = ldb_module_get_ctx(module);
6959
6960         ldb_debug(ldb, LDB_DEBUG_TRACE, "replmd_extended_replicated_objects\n");
6961
6962         objs = talloc_get_type(req->op.extended.data, struct dsdb_extended_replicated_objects);
6963         if (!objs) {
6964                 ldb_debug(ldb, LDB_DEBUG_FATAL, "replmd_extended_replicated_objects: invalid extended data\n");
6965                 return LDB_ERR_PROTOCOL_ERROR;
6966         }
6967
6968         if (objs->version != DSDB_EXTENDED_REPLICATED_OBJECTS_VERSION) {
6969                 ldb_debug(ldb, LDB_DEBUG_FATAL, "replmd_extended_replicated_objects: extended data invalid version [%u != %u]\n",
6970                           objs->version, DSDB_EXTENDED_REPLICATED_OBJECTS_VERSION);
6971                 return LDB_ERR_PROTOCOL_ERROR;
6972         }
6973
6974         ar = replmd_ctx_init(module, req);
6975         if (!ar)
6976                 return LDB_ERR_OPERATIONS_ERROR;
6977
6978         /* Set the flags to have the replmd_op_callback run over the full set of objects */
6979         ar->apply_mode = true;
6980         ar->objs = objs;
6981         ar->schema = dsdb_get_schema(ldb, ar);
6982         if (!ar->schema) {
6983                 ldb_debug_set(ldb, LDB_DEBUG_FATAL, "replmd_ctx_init: no loaded schema found\n");
6984                 talloc_free(ar);
6985                 DEBUG(0,(__location__ ": %s\n", ldb_errstring(ldb)));
6986                 return LDB_ERR_CONSTRAINT_VIOLATION;
6987         }
6988
6989         ctrls = req->controls;
6990
6991         if (req->controls) {
6992                 req->controls = talloc_memdup(ar, req->controls,
6993                                               talloc_get_size(req->controls));
6994                 if (!req->controls) return replmd_replicated_request_werror(ar, WERR_NOT_ENOUGH_MEMORY);
6995         }
6996
6997         ret = ldb_request_add_control(req, DSDB_CONTROL_REPLICATED_UPDATE_OID, false, NULL);
6998         if (ret != LDB_SUCCESS) {
6999                 return ret;
7000         }
7001
7002         /* If this change contained linked attributes in the body
7003          * (rather than in the links section) we need to update
7004          * backlinks in linked_attributes */
7005         ret = ldb_request_add_control(req, DSDB_CONTROL_APPLY_LINKS, false, NULL);
7006         if (ret != LDB_SUCCESS) {
7007                 return ret;
7008         }
7009
7010         ar->controls = req->controls;
7011         req->controls = ctrls;
7012
7013         return replmd_replicated_apply_next(ar);
7014 }
7015
7016 /**
7017  * Checks how to handle an missing target - either we need to fail the
7018  * replication and retry with GET_TGT, ignore the link and continue, or try to
7019  * add a partial link to an unknown target.
7020  */
7021 static int replmd_allow_missing_target(struct ldb_module *module,
7022                                        TALLOC_CTX *mem_ctx,
7023                                        struct ldb_dn *target_dn,
7024                                        struct ldb_dn *source_dn,
7025                                        bool is_obj_commit,
7026                                        struct GUID *guid,
7027                                        uint32_t dsdb_repl_flags,
7028                                        bool *ignore_link,
7029                                        const char * missing_str)
7030 {
7031         struct ldb_context *ldb = ldb_module_get_ctx(module);
7032         bool is_in_same_nc;
7033
7034         /*
7035          * we may not be able to resolve link targets properly when
7036          * dealing with subsets of objects, e.g. the source is a
7037          * critical object and the target isn't
7038          *
7039          * TODO:
7040          * When we implement Trusted Domains we need to consider
7041          * whether they get treated as an incomplete replica here or not
7042          */
7043         if (dsdb_repl_flags & DSDB_REPL_FLAG_OBJECT_SUBSET) {
7044
7045                 /*
7046                  * Ignore the link. We don't increase the highwater-mark in
7047                  * the object subset cases, so subsequent replications should
7048                  * resolve any missing links
7049                  */
7050                 DEBUG(2, ("%s target %s linked from %s\n", missing_str,
7051                           ldb_dn_get_linearized(target_dn),
7052                           ldb_dn_get_linearized(source_dn)));
7053                 *ignore_link = true;
7054                 return LDB_SUCCESS;
7055         }
7056
7057         if (dsdb_repl_flags & DSDB_REPL_FLAG_TARGETS_UPTODATE) {
7058
7059                 /*
7060                  * target should already be up-to-date so there's no point in
7061                  * retrying. This could be due to bad timing, or if a target
7062                  * on a one-way link was deleted. We ignore the link rather
7063                  * than failing the replication cycle completely
7064                  */
7065                 *ignore_link = true;
7066                 DBG_WARNING("%s is %s but up to date. Ignoring link from %s\n",
7067                             ldb_dn_get_linearized(target_dn), missing_str,
7068                             ldb_dn_get_linearized(source_dn));
7069                 return LDB_SUCCESS;
7070         }
7071         
7072         is_in_same_nc = dsdb_objects_have_same_nc(ldb,
7073                                                   mem_ctx,
7074                                                   source_dn,
7075                                                   target_dn);
7076         if (is_in_same_nc) {
7077                 /* fail the replication and retry with GET_TGT */
7078                 ldb_asprintf_errstring(ldb, "%s target %s GUID %s linked from %s\n",
7079                                        missing_str,
7080                                        ldb_dn_get_linearized(target_dn),
7081                                        GUID_string(mem_ctx, guid),
7082                                        ldb_dn_get_linearized(source_dn));
7083                 return LDB_ERR_NO_SUCH_OBJECT;
7084         }
7085
7086         /*
7087          * The target of the cross-partition link is missing. Continue
7088          * and try to at least add the forward-link. This isn't great,
7089          * but a partial link can be fixed by dbcheck, so it's better
7090          * than dropping the link completely.
7091          */
7092         *ignore_link = false;
7093
7094         if (is_obj_commit) {
7095
7096                 /*
7097                  * Only log this when we're actually committing the objects.
7098                  * This avoids spurious logs, i.e. if we're just verifying the
7099                  * received link during a join.
7100                  */
7101                 DBG_WARNING("%s cross-partition target %s linked from %s\n",
7102                             missing_str, ldb_dn_get_linearized(target_dn),
7103                             ldb_dn_get_linearized(source_dn));
7104         }
7105         
7106         return LDB_SUCCESS;
7107 }
7108
7109 /**
7110  * Checks that the target object for a linked attribute exists.
7111  * @param guid returns the target object's GUID (is returned)if it exists)
7112  * @param ignore_link set to true if the linked attribute should be ignored
7113  * (i.e. the target doesn't exist, but that it's OK to skip the link)
7114  */
7115 static int replmd_check_target_exists(struct ldb_module *module,
7116                                       struct dsdb_dn *dsdb_dn,
7117                                       struct la_entry *la_entry,
7118                                       struct ldb_dn *source_dn,
7119                                       bool is_obj_commit,
7120                                       struct GUID *guid,
7121                                       bool *ignore_link)
7122 {
7123         struct drsuapi_DsReplicaLinkedAttribute *la = la_entry->la;
7124         struct ldb_context *ldb = ldb_module_get_ctx(module);
7125         struct ldb_result *target_res;
7126         TALLOC_CTX *tmp_ctx = talloc_new(la_entry);
7127         const char *attrs[] = { "isDeleted", "isRecycled", NULL };
7128         NTSTATUS ntstatus;
7129         int ret;
7130         enum deletion_state target_deletion_state = OBJECT_REMOVED;
7131         bool active = (la->flags & DRSUAPI_DS_LINKED_ATTRIBUTE_FLAG_ACTIVE) ? true : false;
7132
7133         *ignore_link = false;
7134         ntstatus = dsdb_get_extended_dn_guid(dsdb_dn->dn, guid, "GUID");
7135
7136         if (!NT_STATUS_IS_OK(ntstatus) && !active) {
7137
7138                 /*
7139                  * This strange behaviour (allowing a NULL/missing
7140                  * GUID) originally comes from:
7141                  *
7142                  * commit e3054ce0fe0f8f62d2f5b2a77893e7a1479128bd
7143                  * Author: Andrew Tridgell <tridge@samba.org>
7144                  * Date:   Mon Dec 21 21:21:55 2009 +1100
7145                  *
7146                  *  s4-drs: cope better with NULL GUIDS from DRS
7147                  *
7148                  *  It is valid to get a NULL GUID over DRS for a deleted forward link. We
7149                  *  need to match by DN if possible when seeing if we should update an
7150                  *  existing link.
7151                  *
7152                  *  Pair-Programmed-With: Andrew Bartlett <abartlet@samba.org>
7153                  */
7154                 ret = dsdb_module_search_dn(module, tmp_ctx, &target_res,
7155                                             dsdb_dn->dn, attrs,
7156                                             DSDB_FLAG_NEXT_MODULE |
7157                                             DSDB_SEARCH_SHOW_RECYCLED |
7158                                             DSDB_SEARCH_SEARCH_ALL_PARTITIONS |
7159                                             DSDB_SEARCH_SHOW_DN_IN_STORAGE_FORMAT,
7160                                             NULL);
7161         } else if (!NT_STATUS_IS_OK(ntstatus)) {
7162                 ldb_asprintf_errstring(ldb, "Failed to find GUID in linked attribute 0x%x blob for %s from %s",
7163                                        la->attid,
7164                                        ldb_dn_get_linearized(dsdb_dn->dn),
7165                                        ldb_dn_get_linearized(source_dn));
7166                 talloc_free(tmp_ctx);
7167                 return LDB_ERR_OPERATIONS_ERROR;
7168         } else {
7169                 ret = dsdb_module_search(module, tmp_ctx, &target_res,
7170                                          NULL, LDB_SCOPE_SUBTREE,
7171                                          attrs,
7172                                          DSDB_FLAG_NEXT_MODULE |
7173                                          DSDB_SEARCH_SHOW_RECYCLED |
7174                                          DSDB_SEARCH_SEARCH_ALL_PARTITIONS |
7175                                          DSDB_SEARCH_SHOW_DN_IN_STORAGE_FORMAT,
7176                                          NULL,
7177                                          "objectGUID=%s",
7178                                          GUID_string(tmp_ctx, guid));
7179         }
7180
7181         if (ret != LDB_SUCCESS) {
7182                 ldb_asprintf_errstring(ldb, "Failed to re-resolve GUID %s: %s\n",
7183                                        GUID_string(tmp_ctx, guid),
7184                                        ldb_errstring(ldb));
7185                 talloc_free(tmp_ctx);
7186                 return ret;
7187         }
7188
7189         if (target_res->count == 0) {
7190
7191                 /*
7192                  * target object is unknown. Check whether to ignore the link,
7193                  * fail the replication, or add a partial link
7194                  */
7195                 ret = replmd_allow_missing_target(module, tmp_ctx, dsdb_dn->dn,
7196                                                   source_dn, is_obj_commit, guid,
7197                                                   la_entry->dsdb_repl_flags,
7198                                                   ignore_link, "Unknown");
7199
7200         } else if (target_res->count != 1) {
7201                 ldb_asprintf_errstring(ldb, "More than one object found matching objectGUID %s\n",
7202                                        GUID_string(tmp_ctx, guid));
7203                 ret = LDB_ERR_OPERATIONS_ERROR;
7204         } else {
7205                 struct ldb_message *target_msg = target_res->msgs[0];
7206
7207                 dsdb_dn->dn = talloc_steal(dsdb_dn, target_msg->dn);
7208
7209                 /* Get the object's state (i.e. Not Deleted, Tombstone, etc) */
7210                 replmd_deletion_state(module, target_msg,
7211                                       &target_deletion_state, NULL);
7212
7213                 /*
7214                  * Check for deleted objects as per MS-DRSR 4.1.10.6.14
7215                  * ProcessLinkValue(). Link updates should not be sent for
7216                  * recycled and tombstone objects (deleting the links should
7217                  * happen when we delete the object). This probably means our
7218                  * copy of the target object isn't up to date.
7219                  */
7220                 if (target_deletion_state >= OBJECT_RECYCLED) {
7221
7222                         /*
7223                          * target object is deleted. Check whether to ignore the
7224                          * link, fail the replication, or add a partial link
7225                          */
7226                         ret = replmd_allow_missing_target(module, tmp_ctx,
7227                                                           dsdb_dn->dn, source_dn,
7228                                                           is_obj_commit, guid,
7229                                                           la_entry->dsdb_repl_flags,
7230                                                           ignore_link, "Deleted");
7231                 }
7232         }
7233
7234         talloc_free(tmp_ctx);
7235         return ret;
7236 }
7237
7238 /**
7239  * Extracts the key details about the source/target object for a
7240  * linked-attribute entry.
7241  * This returns the following details:
7242  * @param ret_attr the schema details for the linked attribute
7243  * @param source_msg the search result for the source object
7244  * @param target_dsdb_dn the unpacked DN info for the target object
7245  */
7246 static int replmd_extract_la_entry_details(struct ldb_module *module,
7247                                            struct la_entry *la_entry,
7248                                            TALLOC_CTX *mem_ctx,
7249                                            const struct dsdb_attribute **ret_attr,
7250                                            struct ldb_message **source_msg,
7251                                            struct dsdb_dn **target_dsdb_dn)
7252 {
7253         struct drsuapi_DsReplicaLinkedAttribute *la = la_entry->la;
7254         struct ldb_context *ldb = ldb_module_get_ctx(module);
7255         const struct dsdb_schema *schema = dsdb_get_schema(ldb, mem_ctx);
7256         int ret;
7257         const struct dsdb_attribute *attr;
7258         WERROR status;
7259         struct ldb_result *res;
7260         const char *attrs[4];
7261
7262 /*
7263 linked_attributes[0]:
7264      &objs->linked_attributes[i]: struct drsuapi_DsReplicaLinkedAttribute
7265         identifier               : *
7266             identifier: struct drsuapi_DsReplicaObjectIdentifier
7267                 __ndr_size               : 0x0000003a (58)
7268                 __ndr_size_sid           : 0x00000000 (0)
7269                 guid                     : 8e95b6a9-13dd-4158-89db-3220a5be5cc7
7270                 sid                      : S-0-0
7271                 __ndr_size_dn            : 0x00000000 (0)
7272                 dn                       : ''
7273         attid                    : DRSUAPI_ATTID_member (0x1F)
7274         value: struct drsuapi_DsAttributeValue
7275             __ndr_size               : 0x0000007e (126)
7276             blob                     : *
7277                 blob                     : DATA_BLOB length=126
7278         flags                    : 0x00000001 (1)
7279                1: DRSUAPI_DS_LINKED_ATTRIBUTE_FLAG_ACTIVE
7280         originating_add_time     : Wed Sep  2 22:20:01 2009 EST
7281         meta_data: struct drsuapi_DsReplicaMetaData
7282             version                  : 0x00000015 (21)
7283             originating_change_time  : Wed Sep  2 23:39:07 2009 EST
7284             originating_invocation_id: 794640f3-18cf-40ee-a211-a93992b67a64
7285             originating_usn          : 0x000000000001e19c (123292)
7286
7287 (for cases where the link is to a normal DN)
7288      &target: struct drsuapi_DsReplicaObjectIdentifier3
7289         __ndr_size               : 0x0000007e (126)
7290         __ndr_size_sid           : 0x0000001c (28)
7291         guid                     : 7639e594-db75-4086-b0d4-67890ae46031
7292         sid                      : S-1-5-21-2848215498-2472035911-1947525656-19924
7293         __ndr_size_dn            : 0x00000022 (34)
7294         dn                       : 'CN=UOne,OU=TestOU,DC=vsofs8,DC=com'
7295  */
7296
7297         /* find the attribute being modified */
7298         attr = dsdb_attribute_by_attributeID_id(schema, la->attid);
7299         if (attr == NULL) {
7300                 struct GUID_txt_buf guid_str;
7301                 ldb_asprintf_errstring(ldb, "Unable to find attributeID 0x%x for link on <GUID=%s>",
7302                                        la->attid,
7303                                        GUID_buf_string(&la->identifier->guid,
7304                                                        &guid_str));
7305                 return LDB_ERR_OPERATIONS_ERROR;
7306         }
7307
7308         /*
7309          * All attributes listed here must be dealt with in some way
7310          * by replmd_process_linked_attribute() otherwise in the case
7311          * of isDeleted: FALSE the modify will fail with:
7312          *
7313          * Failed to apply linked attribute change 'attribute 'isDeleted':
7314          * invalid modify flags on
7315          * 'CN=g1_1527570609273,CN=Users,DC=samba,DC=example,DC=com':
7316          * 0x0'
7317          *
7318          * This is becaue isDeleted is a Boolean, so FALSE is a
7319          * legitimate value (set by Samba's deletetest.py)
7320          */
7321         attrs[0] = attr->lDAPDisplayName;
7322         attrs[1] = "isDeleted";
7323         attrs[2] = "isRecycled";
7324         attrs[3] = NULL;
7325
7326         /*
7327          * get the existing message from the db for the object with
7328          * this GUID, returning attribute being modified. We will then
7329          * use this msg as the basis for a modify call
7330          */
7331         ret = dsdb_module_search(module, mem_ctx, &res, NULL, LDB_SCOPE_SUBTREE, attrs,
7332                                  DSDB_FLAG_NEXT_MODULE |
7333                                  DSDB_SEARCH_SEARCH_ALL_PARTITIONS |
7334                                  DSDB_SEARCH_SHOW_RECYCLED |
7335                                  DSDB_SEARCH_SHOW_DN_IN_STORAGE_FORMAT |
7336                                  DSDB_SEARCH_REVEAL_INTERNALS,
7337                                  NULL,
7338                                  "objectGUID=%s", GUID_string(mem_ctx, &la->identifier->guid));
7339         if (ret != LDB_SUCCESS) {
7340                 return ret;
7341         }
7342         if (res->count != 1) {
7343                 ldb_asprintf_errstring(ldb, "DRS linked attribute for GUID %s - DN not found",
7344                                        GUID_string(mem_ctx, &la->identifier->guid));
7345                 return LDB_ERR_NO_SUCH_OBJECT;
7346         }
7347
7348         *source_msg = res->msgs[0];
7349
7350         /* the value blob for the attribute holds the target object DN */
7351         status = dsdb_dn_la_from_blob(ldb, attr, schema, mem_ctx, la->value.blob, target_dsdb_dn);
7352         if (!W_ERROR_IS_OK(status)) {
7353                 ldb_asprintf_errstring(ldb, "Failed to parsed linked attribute blob for %s on %s - %s\n",
7354                                        attr->lDAPDisplayName,
7355                                        ldb_dn_get_linearized(res->msgs[0]->dn),
7356                                        win_errstr(status));
7357                 return LDB_ERR_OPERATIONS_ERROR;
7358         }
7359
7360         *ret_attr = attr;
7361
7362         return LDB_SUCCESS;
7363 }
7364
7365 /**
7366  * Verifies the source and target objects are known for a linked attribute
7367  */
7368 static int replmd_verify_linked_attribute(struct replmd_replicated_request *ar,
7369                                           struct la_entry *la)
7370 {
7371         int ret = LDB_SUCCESS;
7372         TALLOC_CTX *tmp_ctx = talloc_new(la);
7373         struct ldb_module *module = ar->module;
7374         struct ldb_message *src_msg;
7375         const struct dsdb_attribute *attr;
7376         struct dsdb_dn *tgt_dsdb_dn;
7377         struct GUID guid = GUID_zero();
7378         bool dummy;
7379
7380         ret = replmd_extract_la_entry_details(module, la, tmp_ctx, &attr,
7381                                               &src_msg, &tgt_dsdb_dn);
7382
7383         /*
7384          * When we fail to find the source object, the error code we pass
7385          * back here is really important. It flags back to the callers to
7386          * retry this request with DRSUAPI_DRS_GET_ANC. This case should
7387          * never happen if we're replicating from a Samba DC, but it is
7388          * needed to talk to a Windows DC
7389          */
7390         if (ret == LDB_ERR_NO_SUCH_OBJECT) {
7391                 ret = replmd_replicated_request_werror(ar, WERR_DS_DRA_MISSING_PARENT);
7392         }
7393
7394         if (ret != LDB_SUCCESS) {
7395                 talloc_free(tmp_ctx);
7396                 return ret;
7397         }
7398
7399         /*
7400          * We can skip the target object checks if we're only syncing critical
7401          * objects, or we know the target is up-to-date. If either case, we
7402          * still continue even if the target doesn't exist
7403          */
7404         if ((la->dsdb_repl_flags & (DSDB_REPL_FLAG_OBJECT_SUBSET |
7405                                     DSDB_REPL_FLAG_TARGETS_UPTODATE)) == 0) {
7406
7407                 ret = replmd_check_target_exists(module, tgt_dsdb_dn, la,
7408                                                  src_msg->dn, false, &guid,
7409                                                  &dummy);
7410         }
7411
7412         /*
7413          * When we fail to find the target object, the error code we pass
7414          * back here is really important. It flags back to the callers to
7415          * retry this request with DRSUAPI_DRS_GET_TGT
7416          */
7417         if (ret == LDB_ERR_NO_SUCH_OBJECT) {
7418                 ret = replmd_replicated_request_werror(ar, WERR_DS_DRA_RECYCLED_TARGET);
7419         }
7420
7421         talloc_free(tmp_ctx);
7422         return ret;
7423 }
7424
7425 /**
7426  * Finds the current active Parsed-DN value for a single-valued linked
7427  * attribute, if one exists.
7428  * @param ret_pdn assigned the active Parsed-DN, or NULL if none was found
7429  * @returns LDB_SUCCESS (regardless of whether a match was found), unless
7430  * an error occurred
7431  */
7432 static int replmd_get_active_singleval_link(struct ldb_module *module,
7433                                             TALLOC_CTX *mem_ctx,
7434                                             struct parsed_dn pdn_list[],
7435                                             unsigned int count,
7436                                             const struct dsdb_attribute *attr,
7437                                             struct parsed_dn **ret_pdn)
7438 {
7439         unsigned int i;
7440
7441         *ret_pdn = NULL;
7442
7443         if (!(attr->ldb_schema_attribute->flags & LDB_ATTR_FLAG_SINGLE_VALUE)) {
7444
7445                 /* nothing to do for multi-valued linked attributes */
7446                 return LDB_SUCCESS;
7447         }
7448
7449         for (i = 0; i < count; i++) {
7450                 int ret = LDB_SUCCESS;
7451                 struct parsed_dn *pdn = &pdn_list[i];
7452
7453                 /* skip any inactive links */
7454                 if (dsdb_dn_is_deleted_val(pdn->v)) {
7455                         continue;
7456                 }
7457
7458                 /* we've found an active value for this attribute */
7459                 *ret_pdn = pdn;
7460
7461                 if (pdn->dsdb_dn == NULL) {
7462                         struct ldb_context *ldb = ldb_module_get_ctx(module);
7463
7464                         ret = really_parse_trusted_dn(mem_ctx, ldb, pdn,
7465                                                       attr->syntax->ldap_oid);
7466                 }
7467
7468                 return ret;
7469         }
7470
7471         /* no active link found */
7472         return LDB_SUCCESS;
7473 }
7474
7475 /**
7476  * @returns true if the replication linked attribute info is newer than we
7477  * already have in our DB
7478  * @param pdn the existing linked attribute info in our DB
7479  * @param la the new linked attribute info received during replication
7480  */
7481 static bool replmd_link_update_is_newer(struct parsed_dn *pdn,
7482                                         struct drsuapi_DsReplicaLinkedAttribute *la)
7483 {
7484         /* see if this update is newer than what we have already */
7485         struct GUID invocation_id = GUID_zero();
7486         uint32_t version = 0;
7487         NTTIME change_time = 0;
7488
7489         if (pdn == NULL) {
7490
7491                 /* no existing info so update is newer */
7492                 return true;
7493         }
7494
7495         dsdb_get_extended_dn_guid(pdn->dsdb_dn->dn, &invocation_id, "RMD_INVOCID");
7496         dsdb_get_extended_dn_uint32(pdn->dsdb_dn->dn, &version, "RMD_VERSION");
7497         dsdb_get_extended_dn_nttime(pdn->dsdb_dn->dn, &change_time, "RMD_CHANGETIME");
7498
7499         return replmd_update_is_newer(&invocation_id,
7500                                       &la->meta_data.originating_invocation_id,
7501                                       version,
7502                                       la->meta_data.version,
7503                                       change_time,
7504                                       la->meta_data.originating_change_time);
7505 }
7506
7507 /**
7508  * Marks an existing linked attribute value as deleted in the DB
7509  * @param pdn the parsed-DN of the target-value to delete
7510  */
7511 static int replmd_delete_link_value(struct ldb_module *module,
7512                                     struct replmd_private *replmd_private,
7513                                     TALLOC_CTX *mem_ctx,
7514                                     struct ldb_dn *src_obj_dn,
7515                                     const struct dsdb_schema *schema,
7516                                     const struct dsdb_attribute *attr,
7517                                     uint64_t seq_num,
7518                                     bool is_active,
7519                                     struct GUID *target_guid,
7520                                     struct dsdb_dn *target_dsdb_dn,
7521                                     struct ldb_val *output_val)
7522 {
7523         struct ldb_context *ldb = ldb_module_get_ctx(module);
7524         time_t t;
7525         NTTIME now;
7526         const struct GUID *invocation_id = NULL;
7527         int ret;
7528
7529         t = time(NULL);
7530         unix_to_nt_time(&now, t);
7531
7532         invocation_id = samdb_ntds_invocation_id(ldb);
7533         if (invocation_id == NULL) {
7534                 return LDB_ERR_OPERATIONS_ERROR;
7535         }
7536
7537         /* if the existing link is active, remove its backlink */
7538         if (is_active) {
7539
7540                 ret = replmd_add_backlink(module, replmd_private, schema,
7541                                           src_obj_dn, target_guid, false,
7542                                           attr, NULL);
7543                 if (ret != LDB_SUCCESS) {
7544                         return ret;
7545                 }
7546         }
7547
7548         /* mark the existing value as deleted */
7549         ret = replmd_update_la_val(mem_ctx, output_val, target_dsdb_dn,
7550                                    target_dsdb_dn, invocation_id, seq_num,
7551                                    seq_num, now, true);
7552         return ret;
7553 }
7554
7555 /**
7556  * Checks for a conflict in single-valued link attributes, and tries to
7557  * resolve the problem if possible.
7558  *
7559  * Single-valued links should only ever have one active value. If we already
7560  * have an active link value, and during replication we receive an active link
7561  * value for a different target DN, then we need to resolve this inconsistency
7562  * and determine which value should be active. If the received info is better/
7563  * newer than the existing link attribute, then we need to set our existing
7564  * link as deleted. If the received info is worse/older, then we should continue
7565  * to add it, but set it as an inactive link.
7566  *
7567  * Note that this is a corner-case that is unlikely to happen (but if it does
7568  * happen, we don't want it to break replication completely).
7569  *
7570  * @param pdn_being_modified the parsed DN corresponding to the received link
7571  * target (note this is NULL if the link does not already exist in our DB)
7572  * @param pdn_list all the source object's Parsed-DNs for this attribute, i.e.
7573  * any existing active or inactive values for the attribute in our DB.
7574  * @param dsdb_dn the target DN for the received link attribute
7575  * @param add_as_inactive gets set to true if the received link is worse than
7576  * the existing link - it should still be added, but as an inactive link.
7577  */
7578 static int replmd_check_singleval_la_conflict(struct ldb_module *module,
7579                                               struct replmd_private *replmd_private,
7580                                               TALLOC_CTX *mem_ctx,
7581                                               struct ldb_dn *src_obj_dn,
7582                                               struct drsuapi_DsReplicaLinkedAttribute *la,
7583                                               struct dsdb_dn *dsdb_dn,
7584                                               struct parsed_dn *pdn_being_modified,
7585                                               struct parsed_dn *pdn_list,
7586                                               struct ldb_message_element *old_el,
7587                                               const struct dsdb_schema *schema,
7588                                               const struct dsdb_attribute *attr,
7589                                               uint64_t seq_num,
7590                                               bool *add_as_inactive)
7591 {
7592         struct parsed_dn *active_pdn = NULL;
7593         bool update_is_newer = false;
7594         int ret;
7595
7596         /*
7597          * check if there's a conflict for single-valued links, i.e. an active
7598          * linked attribute already exists, but it has a different target value
7599          */
7600         ret = replmd_get_active_singleval_link(module, mem_ctx, pdn_list,
7601                                                old_el->num_values, attr,
7602                                                &active_pdn);
7603
7604         if (ret != LDB_SUCCESS) {
7605                 return ret;
7606         }
7607
7608         /*
7609          * If no active value exists (or the received info is for the currently
7610          * active value), then no conflict exists
7611          */
7612         if (active_pdn == NULL || active_pdn == pdn_being_modified) {
7613                 return LDB_SUCCESS;
7614         }
7615
7616         DBG_WARNING("Link conflict for %s attribute on %s\n",
7617                     attr->lDAPDisplayName, ldb_dn_get_linearized(src_obj_dn));
7618
7619         /* Work out how to resolve the conflict based on which info is better */
7620         update_is_newer = replmd_link_update_is_newer(active_pdn, la);
7621
7622         if (update_is_newer) {
7623                 DBG_WARNING("Using received value %s, over existing target %s\n",
7624                             ldb_dn_get_linearized(dsdb_dn->dn),
7625                             ldb_dn_get_linearized(active_pdn->dsdb_dn->dn));
7626
7627                 /*
7628                  * Delete our existing active link. The received info will then
7629                  * be added (through normal link processing) as the active value
7630                  */
7631                 ret = replmd_delete_link_value(module, replmd_private, old_el,
7632                                                src_obj_dn, schema, attr,
7633                                                seq_num, true, &active_pdn->guid,
7634                                                active_pdn->dsdb_dn,
7635                                                active_pdn->v);
7636
7637                 if (ret != LDB_SUCCESS) {
7638                         return ret;
7639                 }
7640         } else {
7641                 DBG_WARNING("Using existing target %s, over received value %s\n",
7642                             ldb_dn_get_linearized(active_pdn->dsdb_dn->dn),
7643                             ldb_dn_get_linearized(dsdb_dn->dn));
7644
7645                 /*
7646                  * we want to keep our existing active link and add the
7647                  * received link as inactive
7648                  */
7649                 *add_as_inactive = true;
7650         }
7651
7652         return LDB_SUCCESS;
7653 }
7654
7655 /*
7656   process one linked attribute structure
7657  */
7658 static int replmd_process_linked_attribute(struct ldb_module *module,
7659                                            struct replmd_private *replmd_private,
7660                                            struct la_entry *la_entry,
7661                                            struct ldb_request *parent)
7662 {
7663         struct drsuapi_DsReplicaLinkedAttribute *la = la_entry->la;
7664         struct ldb_context *ldb = ldb_module_get_ctx(module);
7665         struct ldb_message *msg;
7666         TALLOC_CTX *tmp_ctx = talloc_new(la_entry);
7667         const struct dsdb_schema *schema = dsdb_get_schema(ldb, tmp_ctx);
7668         int ret;
7669         const struct dsdb_attribute *attr;
7670         struct dsdb_dn *dsdb_dn;
7671         uint64_t seq_num = 0;
7672         struct ldb_message_element *old_el;
7673         time_t t = time(NULL);
7674         struct parsed_dn *pdn_list, *pdn, *next;
7675         struct GUID guid = GUID_zero();
7676         bool active = (la->flags & DRSUAPI_DS_LINKED_ATTRIBUTE_FLAG_ACTIVE)?true:false;
7677         bool ignore_link;
7678         enum deletion_state deletion_state = OBJECT_NOT_DELETED;
7679         struct dsdb_dn *old_dsdb_dn = NULL;
7680         struct ldb_val *val_to_update = NULL;
7681         bool add_as_inactive = false;
7682
7683         /*
7684          * get the attribute being modified, the search result for the source object,
7685          * and the target object's DN details
7686          */
7687         ret = replmd_extract_la_entry_details(module, la_entry, tmp_ctx, &attr,
7688                                               &msg, &dsdb_dn);
7689
7690         if (ret != LDB_SUCCESS) {
7691                 talloc_free(tmp_ctx);
7692                 return ret;
7693         }
7694
7695         /*
7696          * Check for deleted objects per MS-DRSR 4.1.10.6.14
7697          * ProcessLinkValue, because link updates are not applied to
7698          * recycled and tombstone objects.  We don't have to delete
7699          * any existing link, that should have happened when the
7700          * object deletion was replicated or initiated.
7701          *
7702          * This needs isDeleted and isRecycled to be included as
7703          * attributes in the search and so in msg if set.
7704          */
7705         replmd_deletion_state(module, msg, &deletion_state, NULL);
7706
7707         if (deletion_state >= OBJECT_RECYCLED) {
7708                 talloc_free(tmp_ctx);
7709                 return LDB_SUCCESS;
7710         }
7711
7712         /*
7713          * Now that we know the deletion_state, remove the extra
7714          * attributes added for that purpose.  We need to do this
7715          * otherwise in the case of isDeleted: FALSE the modify will
7716          * fail with:
7717          *
7718          * Failed to apply linked attribute change 'attribute 'isDeleted':
7719          * invalid modify flags on
7720          * 'CN=g1_1527570609273,CN=Users,DC=samba,DC=example,DC=com':
7721          * 0x0'
7722          *
7723          * This is becaue isDeleted is a Boolean, so FALSE is a
7724          * legitimate value (set by Samba's deletetest.py)
7725          */
7726
7727         ldb_msg_remove_attr(msg, "isDeleted");
7728         ldb_msg_remove_attr(msg, "isRecycled");
7729
7730         old_el = ldb_msg_find_element(msg, attr->lDAPDisplayName);
7731         if (old_el == NULL) {
7732                 ret = ldb_msg_add_empty(msg, attr->lDAPDisplayName, LDB_FLAG_MOD_REPLACE, &old_el);
7733                 if (ret != LDB_SUCCESS) {
7734                         ldb_module_oom(module);
7735                         talloc_free(tmp_ctx);
7736                         return LDB_ERR_OPERATIONS_ERROR;
7737                 }
7738         } else {
7739                 old_el->flags = LDB_FLAG_MOD_REPLACE;
7740         }
7741
7742         /* parse the existing links */
7743         ret = get_parsed_dns_trusted(module, replmd_private, tmp_ctx, old_el, &pdn_list,
7744                                      attr->syntax->ldap_oid, parent);
7745
7746         if (ret != LDB_SUCCESS) {
7747                 talloc_free(tmp_ctx);
7748                 return ret;
7749         }
7750
7751         ret = replmd_check_target_exists(module, dsdb_dn, la_entry, msg->dn,
7752                                          true, &guid, &ignore_link);
7753
7754         if (ret != LDB_SUCCESS) {
7755                 talloc_free(tmp_ctx);
7756                 return ret;
7757         }
7758
7759         /*
7760          * there are some cases where the target object doesn't exist, but it's
7761          * OK to ignore the linked attribute
7762          */
7763         if (ignore_link) {
7764                 talloc_free(tmp_ctx);
7765                 return ret;
7766         }
7767
7768         /* see if this link already exists */
7769         ret = parsed_dn_find(ldb, pdn_list, old_el->num_values,
7770                              &guid,
7771                              dsdb_dn->dn,
7772                              dsdb_dn->extra_part, 0,
7773                              &pdn, &next,
7774                              attr->syntax->ldap_oid,
7775                              true);
7776         if (ret != LDB_SUCCESS) {
7777                 talloc_free(tmp_ctx);
7778                 return ret;
7779         }
7780
7781         if (!replmd_link_update_is_newer(pdn, la)) {
7782                 DEBUG(3,("Discarding older DRS linked attribute update to %s on %s from %s\n",
7783                          old_el->name, ldb_dn_get_linearized(msg->dn),
7784                          GUID_string(tmp_ctx, &la->meta_data.originating_invocation_id)));
7785                 talloc_free(tmp_ctx);
7786                 return LDB_SUCCESS;
7787         }
7788
7789         /* get a seq_num for this change */
7790         ret = ldb_sequence_number(ldb, LDB_SEQ_NEXT, &seq_num);
7791         if (ret != LDB_SUCCESS) {
7792                 talloc_free(tmp_ctx);
7793                 return ret;
7794         }
7795
7796         /*
7797          * check for single-valued link conflicts, i.e. an active linked
7798          * attribute already exists, but it has a different target value
7799          */
7800         if (active) {
7801                 ret = replmd_check_singleval_la_conflict(module, replmd_private,
7802                                                          tmp_ctx, msg->dn, la,
7803                                                          dsdb_dn, pdn, pdn_list,
7804                                                          old_el, schema, attr,
7805                                                          seq_num,
7806                                                          &add_as_inactive);
7807                 if (ret != LDB_SUCCESS) {
7808                         talloc_free(tmp_ctx);
7809                         return ret;
7810                 }
7811         }
7812
7813         if (pdn != NULL) {
7814                 uint32_t rmd_flags = dsdb_dn_rmd_flags(pdn->dsdb_dn->dn);
7815
7816                 if (!(rmd_flags & DSDB_RMD_FLAG_DELETED)) {
7817                         /* remove the existing backlink */
7818                         ret = replmd_add_backlink(module, replmd_private,
7819                                                   schema, 
7820                                                   msg->dn,
7821                                                   &pdn->guid, false, attr,
7822                                                   parent);
7823                         if (ret != LDB_SUCCESS) {
7824                                 talloc_free(tmp_ctx);
7825                                 return ret;
7826                         }
7827                 }
7828
7829                 val_to_update = pdn->v;
7830                 old_dsdb_dn = pdn->dsdb_dn;
7831
7832         } else {
7833                 unsigned offset;
7834
7835                 /*
7836                  * We know where the new one needs to be, from the *next
7837                  * pointer into pdn_list.
7838                  */
7839                 if (next == NULL) {
7840                         offset = old_el->num_values;
7841                 } else {
7842                         if (next->dsdb_dn == NULL) {
7843                                 ret = really_parse_trusted_dn(tmp_ctx, ldb, next,
7844                                                               attr->syntax->ldap_oid);
7845                                 if (ret != LDB_SUCCESS) {
7846                                         return ret;
7847                                 }
7848                         }
7849                         offset = next - pdn_list;
7850                         if (offset > old_el->num_values) {
7851                                 talloc_free(tmp_ctx);
7852                                 return LDB_ERR_OPERATIONS_ERROR;
7853                         }
7854                 }
7855
7856                 old_el->values = talloc_realloc(msg->elements, old_el->values,
7857                                                 struct ldb_val, old_el->num_values+1);
7858                 if (!old_el->values) {
7859                         ldb_module_oom(module);
7860                         return LDB_ERR_OPERATIONS_ERROR;
7861                 }
7862
7863                 if (offset != old_el->num_values) {
7864                         memmove(&old_el->values[offset + 1], &old_el->values[offset],
7865                                 (old_el->num_values - offset) * sizeof(old_el->values[0]));
7866                 }
7867
7868                 old_el->num_values++;
7869
7870                 val_to_update = &old_el->values[offset];
7871                 old_dsdb_dn = NULL;
7872         }
7873
7874         /* set the link attribute's value to the info that was received */
7875         ret = replmd_set_la_val(tmp_ctx, val_to_update, dsdb_dn, old_dsdb_dn,
7876                                 &la->meta_data.originating_invocation_id,
7877                                 la->meta_data.originating_usn, seq_num,
7878                                 la->meta_data.originating_change_time,
7879                                 la->meta_data.version,
7880                                 !active);
7881         if (ret != LDB_SUCCESS) {
7882                 talloc_free(tmp_ctx);
7883                 return ret;
7884         }
7885
7886         if (add_as_inactive) {
7887
7888                 /* Set the new link as inactive/deleted to avoid conflicts */
7889                 ret = replmd_delete_link_value(module, replmd_private, old_el,
7890                                                msg->dn, schema, attr, seq_num,
7891                                                false, &guid, dsdb_dn,
7892                                                val_to_update);
7893
7894                 if (ret != LDB_SUCCESS) {
7895                         talloc_free(tmp_ctx);
7896                         return ret;
7897                 }
7898
7899         } else if (active) {
7900
7901                 /* if the new link is active, then add the new backlink */
7902                 ret = replmd_add_backlink(module, replmd_private,
7903                                           schema,
7904                                           msg->dn,
7905                                           &guid, true, attr,
7906                                           parent);
7907                 if (ret != LDB_SUCCESS) {
7908                         talloc_free(tmp_ctx);
7909                         return ret;
7910                 }
7911         }
7912
7913         /* we only change whenChanged and uSNChanged if the seq_num
7914            has changed */
7915         ret = add_time_element(msg, "whenChanged", t);
7916         if (ret != LDB_SUCCESS) {
7917                 talloc_free(tmp_ctx);
7918                 ldb_operr(ldb);
7919                 return ret;
7920         }
7921
7922         ret = add_uint64_element(ldb, msg, "uSNChanged", seq_num);
7923         if (ret != LDB_SUCCESS) {
7924                 talloc_free(tmp_ctx);
7925                 ldb_operr(ldb);
7926                 return ret;
7927         }
7928
7929         old_el = ldb_msg_find_element(msg, attr->lDAPDisplayName);
7930         if (old_el == NULL) {
7931                 talloc_free(tmp_ctx);
7932                 return ldb_operr(ldb);
7933         }
7934
7935         ret = dsdb_check_single_valued_link(attr, old_el);
7936         if (ret != LDB_SUCCESS) {
7937                 talloc_free(tmp_ctx);
7938                 return ret;
7939         }
7940
7941         old_el->flags |= LDB_FLAG_INTERNAL_DISABLE_SINGLE_VALUE_CHECK;
7942
7943         ret = linked_attr_modify(module, msg, parent);
7944         if (ret != LDB_SUCCESS) {
7945                 ldb_debug(ldb, LDB_DEBUG_WARNING, "Failed to apply linked attribute change '%s'\n%s\n",
7946                           ldb_errstring(ldb),
7947                           ldb_ldif_message_redacted_string(ldb,
7948                                                            tmp_ctx,
7949                                                            LDB_CHANGETYPE_MODIFY,
7950                                                            msg));
7951                 talloc_free(tmp_ctx);
7952                 return ret;
7953         }
7954
7955         talloc_free(tmp_ctx);
7956
7957         return ret;
7958 }
7959
7960 static int replmd_extended(struct ldb_module *module, struct ldb_request *req)
7961 {
7962         if (strcmp(req->op.extended.oid, DSDB_EXTENDED_REPLICATED_OBJECTS_OID) == 0) {
7963                 return replmd_extended_replicated_objects(module, req);
7964         }
7965
7966         return ldb_next_request(module, req);
7967 }
7968
7969
7970 /*
7971   we hook into the transaction operations to allow us to
7972   perform the linked attribute updates at the end of the whole
7973   transaction. This allows a forward linked attribute to be created
7974   before the object is created. During a vampire, w2k8 sends us linked
7975   attributes before the objects they are part of.
7976  */
7977 static int replmd_start_transaction(struct ldb_module *module)
7978 {
7979         /* create our private structure for this transaction */
7980         struct replmd_private *replmd_private = talloc_get_type(ldb_module_get_private(module),
7981                                                                 struct replmd_private);
7982         replmd_txn_cleanup(replmd_private);
7983
7984         /* free any leftover mod_usn records from cancelled
7985            transactions */
7986         while (replmd_private->ncs) {
7987                 struct nc_entry *e = replmd_private->ncs;
7988                 DLIST_REMOVE(replmd_private->ncs, e);
7989                 talloc_free(e);
7990         }
7991
7992         replmd_private->originating_updates = false;
7993
7994         return ldb_next_start_trans(module);
7995 }
7996
7997 /*
7998   on prepare commit we loop over our queued la_context structures and
7999   apply each of them
8000  */
8001 static int replmd_prepare_commit(struct ldb_module *module)
8002 {
8003         struct replmd_private *replmd_private =
8004                 talloc_get_type(ldb_module_get_private(module), struct replmd_private);
8005         struct la_entry *la, *prev;
8006         int ret;
8007
8008         /*
8009          * Walk the list of linked attributes from DRS replication.
8010          *
8011          * We walk backwards, to do the first entry first, as we
8012          * added the entries with DLIST_ADD() which puts them at the
8013          * start of the list
8014          */
8015         for (la = DLIST_TAIL(replmd_private->la_list); la; la=prev) {
8016                 prev = DLIST_PREV(la);
8017                 DLIST_REMOVE(replmd_private->la_list, la);
8018                 ret = replmd_process_linked_attribute(module, replmd_private,
8019                                                       la, NULL);
8020                 if (ret != LDB_SUCCESS) {
8021                         replmd_txn_cleanup(replmd_private);
8022                         return ret;
8023                 }
8024         }
8025
8026         replmd_txn_cleanup(replmd_private);
8027
8028         /* possibly change @REPLCHANGED */
8029         ret = replmd_notify_store(module, NULL);
8030         if (ret != LDB_SUCCESS) {
8031                 return ret;
8032         }
8033
8034         return ldb_next_prepare_commit(module);
8035 }
8036
8037 static int replmd_del_transaction(struct ldb_module *module)
8038 {
8039         struct replmd_private *replmd_private =
8040                 talloc_get_type(ldb_module_get_private(module), struct replmd_private);
8041         replmd_txn_cleanup(replmd_private);
8042
8043         return ldb_next_del_trans(module);
8044 }
8045
8046
8047 static const struct ldb_module_ops ldb_repl_meta_data_module_ops = {
8048         .name          = "repl_meta_data",
8049         .init_context      = replmd_init,
8050         .add               = replmd_add,
8051         .modify            = replmd_modify,
8052         .rename            = replmd_rename,
8053         .del               = replmd_delete,
8054         .extended          = replmd_extended,
8055         .start_transaction = replmd_start_transaction,
8056         .prepare_commit    = replmd_prepare_commit,
8057         .del_transaction   = replmd_del_transaction,
8058 };
8059
8060 int ldb_repl_meta_data_module_init(const char *version)
8061 {
8062         LDB_MODULE_CHECK_VERSION(version);
8063         return ldb_register_module(&ldb_repl_meta_data_module_ops);
8064 }