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
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.
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.
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/>.
27 * Component: ldb repl_meta_data module
29 * Description: - add a unique objectGUID onto every new record,
30 * - handle whenCreated, whenChanged timestamps
31 * - handle uSNCreated, uSNChanged numbers
32 * - handle replPropertyMetaData attribute
35 * Author: Stefan Metzmacher
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"
55 #define DBGC_CLASS DBGC_DRS_REPL
57 /* the RMD_VERSION for linked attributes starts from 1 */
58 #define RMD_VERSION_INITIAL 1
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
64 static const NTTIME DELETED_OBJECT_CONTAINER_CHANGE_TIME
= 2650466015990000000ULL;
66 struct replmd_private
{
68 struct la_entry
*la_list
;
70 struct nc_entry
*prev
, *next
;
73 uint64_t mod_usn_urgent
;
75 struct ldb_dn
*schema_dn
;
76 bool originating_updates
;
81 struct la_entry
*next
, *prev
;
82 struct drsuapi_DsReplicaLinkedAttribute
*la
;
83 uint32_t dsdb_repl_flags
;
86 struct replmd_replicated_request
{
87 struct ldb_module
*module
;
88 struct ldb_request
*req
;
90 const struct dsdb_schema
*schema
;
91 struct GUID our_invocation_id
;
93 /* the controls we pass down */
94 struct ldb_control
**controls
;
97 * Backlinks for the replmd_add() case (we want to create
98 * backlinks after creating the user, but before the end of
101 struct la_backlink
*la_backlinks
;
103 /* details for the mode where we apply a bunch of inbound replication meessages */
105 uint32_t index_current
;
106 struct dsdb_extended_replicated_objects
*objs
;
108 struct ldb_message
*search_msg
;
109 struct GUID local_parent_guid
;
119 static int replmd_replicated_apply_merge(struct replmd_replicated_request
*ar
);
120 static int replmd_delete_internals(struct ldb_module
*module
, struct ldb_request
*req
, bool re_delete
);
121 static int replmd_check_upgrade_links(struct ldb_context
*ldb
,
122 struct parsed_dn
*dns
, uint32_t count
,
123 struct ldb_message_element
*el
,
124 const char *ldap_oid
);
125 static int replmd_verify_linked_attribute(struct replmd_replicated_request
*ar
,
126 struct la_entry
*la
);
127 static int replmd_set_la_val(TALLOC_CTX
*mem_ctx
, struct ldb_val
*v
, struct dsdb_dn
*dsdb_dn
,
128 struct dsdb_dn
*old_dsdb_dn
, const struct GUID
*invocation_id
,
129 uint64_t usn
, uint64_t local_usn
, NTTIME nttime
,
130 uint32_t version
, bool deleted
);
132 static int replmd_make_deleted_child_dn(TALLOC_CTX
*tmp_ctx
,
133 struct ldb_context
*ldb
,
135 const char *rdn_name
,
136 const struct ldb_val
*rdn_value
,
139 enum urgent_situation
{
140 REPL_URGENT_ON_CREATE
= 1,
141 REPL_URGENT_ON_UPDATE
= 2,
142 REPL_URGENT_ON_DELETE
= 4
145 enum deletion_state
{
146 OBJECT_NOT_DELETED
=1,
153 static void replmd_deletion_state(struct ldb_module
*module
,
154 const struct ldb_message
*msg
,
155 enum deletion_state
*current_state
,
156 enum deletion_state
*next_state
)
159 bool enabled
= false;
162 *current_state
= OBJECT_REMOVED
;
163 if (next_state
!= NULL
) {
164 *next_state
= OBJECT_REMOVED
;
169 ret
= dsdb_recyclebin_enabled(module
, &enabled
);
170 if (ret
!= LDB_SUCCESS
) {
174 if (ldb_msg_check_string_attribute(msg
, "isDeleted", "TRUE")) {
176 *current_state
= OBJECT_TOMBSTONE
;
177 if (next_state
!= NULL
) {
178 *next_state
= OBJECT_REMOVED
;
183 if (ldb_msg_check_string_attribute(msg
, "isRecycled", "TRUE")) {
184 *current_state
= OBJECT_RECYCLED
;
185 if (next_state
!= NULL
) {
186 *next_state
= OBJECT_REMOVED
;
191 *current_state
= OBJECT_DELETED
;
192 if (next_state
!= NULL
) {
193 *next_state
= OBJECT_RECYCLED
;
198 *current_state
= OBJECT_NOT_DELETED
;
199 if (next_state
== NULL
) {
204 *next_state
= OBJECT_DELETED
;
206 *next_state
= OBJECT_TOMBSTONE
;
210 static const struct {
211 const char *update_name
;
212 enum urgent_situation repl_situation
;
213 } urgent_objects
[] = {
214 {"nTDSDSA", (REPL_URGENT_ON_CREATE
| REPL_URGENT_ON_DELETE
)},
215 {"crossRef", (REPL_URGENT_ON_CREATE
| REPL_URGENT_ON_DELETE
)},
216 {"attributeSchema", (REPL_URGENT_ON_CREATE
| REPL_URGENT_ON_UPDATE
)},
217 {"classSchema", (REPL_URGENT_ON_CREATE
| REPL_URGENT_ON_UPDATE
)},
218 {"secret", (REPL_URGENT_ON_CREATE
| REPL_URGENT_ON_UPDATE
)},
219 {"rIDManager", (REPL_URGENT_ON_CREATE
| REPL_URGENT_ON_UPDATE
)},
223 /* Attributes looked for when updating or deleting, to check for a urgent replication needed */
224 static const char *urgent_attrs
[] = {
227 "userAccountControl",
232 static bool replmd_check_urgent_objectclass(const struct ldb_message_element
*objectclass_el
,
233 enum urgent_situation situation
)
236 for (i
=0; urgent_objects
[i
].update_name
; i
++) {
238 if ((situation
& urgent_objects
[i
].repl_situation
) == 0) {
242 for (j
=0; j
<objectclass_el
->num_values
; j
++) {
243 const struct ldb_val
*v
= &objectclass_el
->values
[j
];
244 if (ldb_attr_cmp((const char *)v
->data
, urgent_objects
[i
].update_name
) == 0) {
252 static bool replmd_check_urgent_attribute(const struct ldb_message_element
*el
)
254 if (ldb_attr_in_list(urgent_attrs
, el
->name
)) {
260 static int replmd_replicated_apply_isDeleted(struct replmd_replicated_request
*ar
);
263 initialise the module
264 allocate the private structure and build the list
265 of partition DNs for use by replmd_notify()
267 static int replmd_init(struct ldb_module
*module
)
269 struct replmd_private
*replmd_private
;
270 struct ldb_context
*ldb
= ldb_module_get_ctx(module
);
271 static const char *samba_dsdb_attrs
[] = { SAMBA_COMPATIBLE_FEATURES_ATTR
, NULL
};
272 struct ldb_dn
*samba_dsdb_dn
;
273 struct ldb_result
*res
;
275 TALLOC_CTX
*frame
= talloc_stackframe();
276 replmd_private
= talloc_zero(module
, struct replmd_private
);
277 if (replmd_private
== NULL
) {
280 return LDB_ERR_OPERATIONS_ERROR
;
282 ldb_module_set_private(module
, replmd_private
);
284 replmd_private
->schema_dn
= ldb_get_schema_basedn(ldb
);
286 samba_dsdb_dn
= ldb_dn_new(frame
, ldb
, "@SAMBA_DSDB");
287 if (!samba_dsdb_dn
) {
292 ret
= dsdb_module_search_dn(module
, frame
, &res
, samba_dsdb_dn
,
293 samba_dsdb_attrs
, DSDB_FLAG_NEXT_MODULE
, NULL
);
294 if (ret
== LDB_SUCCESS
) {
295 replmd_private
->sorted_links
296 = ldb_msg_check_string_attribute(res
->msgs
[0],
297 SAMBA_COMPATIBLE_FEATURES_ATTR
,
298 SAMBA_SORTED_LINKS_FEATURE
);
302 return ldb_next_init(module
);
306 cleanup our per-transaction contexts
308 static void replmd_txn_cleanup(struct replmd_private
*replmd_private
)
310 talloc_free(replmd_private
->la_ctx
);
311 replmd_private
->la_list
= NULL
;
312 replmd_private
->la_ctx
= NULL
;
318 struct la_backlink
*next
, *prev
;
319 const char *attr_name
;
320 struct ldb_dn
*forward_dn
;
321 struct GUID target_guid
;
326 a ldb_modify request operating on modules below the
329 static int linked_attr_modify(struct ldb_module
*module
,
330 const struct ldb_message
*message
,
331 struct ldb_request
*parent
)
333 struct ldb_request
*mod_req
;
335 struct ldb_context
*ldb
= ldb_module_get_ctx(module
);
336 TALLOC_CTX
*tmp_ctx
= talloc_new(module
);
337 struct ldb_result
*res
;
339 res
= talloc_zero(tmp_ctx
, struct ldb_result
);
341 talloc_free(tmp_ctx
);
342 return ldb_oom(ldb_module_get_ctx(module
));
345 ret
= ldb_build_mod_req(&mod_req
, ldb
, tmp_ctx
,
349 ldb_modify_default_callback
,
351 LDB_REQ_SET_LOCATION(mod_req
);
352 if (ret
!= LDB_SUCCESS
) {
353 talloc_free(tmp_ctx
);
357 ret
= ldb_request_add_control(mod_req
, DSDB_CONTROL_REPLICATED_UPDATE_OID
,
359 if (ret
!= LDB_SUCCESS
) {
363 /* Run the new request */
364 ret
= ldb_next_request(module
, mod_req
);
366 if (ret
== LDB_SUCCESS
) {
367 ret
= ldb_wait(mod_req
->handle
, LDB_WAIT_ALL
);
370 talloc_free(tmp_ctx
);
375 process a backlinks we accumulated during a transaction, adding and
376 deleting the backlinks from the target objects
378 static int replmd_process_backlink(struct ldb_module
*module
, struct la_backlink
*bl
, struct ldb_request
*parent
)
380 struct ldb_dn
*target_dn
, *source_dn
;
382 struct ldb_context
*ldb
= ldb_module_get_ctx(module
);
383 struct ldb_message
*msg
;
384 TALLOC_CTX
*frame
= talloc_stackframe();
390 - construct ldb_message
391 - either an add or a delete
393 ret
= dsdb_module_dn_by_guid(module
, frame
, &bl
->target_guid
, &target_dn
, parent
);
394 if (ret
!= LDB_SUCCESS
) {
395 struct GUID_txt_buf guid_str
;
396 DBG_WARNING("Failed to find target DN for linked attribute with GUID %s\n",
397 GUID_buf_string(&bl
->target_guid
, &guid_str
));
398 DBG_WARNING("Please run 'samba-tool dbcheck' to resolve any missing backlinks.\n");
403 msg
= ldb_msg_new(frame
);
405 ldb_module_oom(module
);
407 return LDB_ERR_OPERATIONS_ERROR
;
410 source_dn
= ldb_dn_copy(frame
, bl
->forward_dn
);
412 ldb_module_oom(module
);
414 return LDB_ERR_OPERATIONS_ERROR
;
416 /* Filter down to the attributes we want in the backlink */
417 const char *accept
[] = { "GUID", "SID", NULL
};
418 ldb_dn_extended_filter(source_dn
, accept
);
421 /* construct a ldb_message for adding/deleting the backlink */
423 dn_string
= ldb_dn_get_extended_linearized(frame
, bl
->forward_dn
, 1);
425 ldb_module_oom(module
);
427 return LDB_ERR_OPERATIONS_ERROR
;
429 ret
= ldb_msg_add_steal_string(msg
, bl
->attr_name
, dn_string
);
430 if (ret
!= LDB_SUCCESS
) {
434 msg
->elements
[0].flags
= bl
->active
?LDB_FLAG_MOD_ADD
:LDB_FLAG_MOD_DELETE
;
436 /* a backlink should never be single valued. Unfortunately the
437 exchange schema has a attribute
438 msExchBridgeheadedLocalConnectorsDNBL which is single
439 valued and a backlink. We need to cope with that by
440 ignoring the single value flag */
441 msg
->elements
[0].flags
|= LDB_FLAG_INTERNAL_DISABLE_SINGLE_VALUE_CHECK
;
443 ret
= dsdb_module_modify(module
, msg
, DSDB_FLAG_NEXT_MODULE
, parent
);
444 if (ret
== LDB_ERR_NO_SUCH_ATTRIBUTE
&& !bl
->active
) {
445 /* we allow LDB_ERR_NO_SUCH_ATTRIBUTE as success to
446 cope with possible corruption where the backlink has
447 already been removed */
448 DEBUG(3,("WARNING: backlink from %s already removed from %s - %s\n",
449 ldb_dn_get_linearized(target_dn
),
450 ldb_dn_get_linearized(source_dn
),
451 ldb_errstring(ldb
)));
453 } else if (ret
!= LDB_SUCCESS
) {
454 ldb_asprintf_errstring(ldb
, "Failed to %s backlink from %s to %s - %s",
455 bl
->active
?"add":"remove",
456 ldb_dn_get_linearized(source_dn
),
457 ldb_dn_get_linearized(target_dn
),
467 add a backlink to the list of backlinks to add/delete in the prepare
470 forward_dn is stolen onto the defereed context
472 static int replmd_defer_add_backlink(struct ldb_module
*module
,
473 struct replmd_private
*replmd_private
,
474 const struct dsdb_schema
*schema
,
475 struct replmd_replicated_request
*ac
,
476 struct ldb_dn
*forward_dn
,
477 struct GUID
*target_guid
, bool active
,
478 const struct dsdb_attribute
*schema_attr
,
479 struct ldb_request
*parent
)
481 const struct dsdb_attribute
*target_attr
;
482 struct la_backlink
*bl
;
484 bl
= talloc(ac
, struct la_backlink
);
486 ldb_module_oom(module
);
487 return LDB_ERR_OPERATIONS_ERROR
;
490 target_attr
= dsdb_attribute_by_linkID(schema
, schema_attr
->linkID
^ 1);
493 * windows 2003 has a broken schema where the
494 * definition of msDS-IsDomainFor is missing (which is
495 * supposed to be the backlink of the
496 * msDS-HasDomainNCs attribute
501 bl
->attr_name
= target_attr
->lDAPDisplayName
;
502 bl
->forward_dn
= talloc_steal(bl
, forward_dn
);
503 bl
->target_guid
= *target_guid
;
506 DLIST_ADD(ac
->la_backlinks
, bl
);
512 add a backlink to the list of backlinks to add/delete in the prepare
515 static int replmd_add_backlink(struct ldb_module
*module
,
516 struct replmd_private
*replmd_private
,
517 const struct dsdb_schema
*schema
,
518 struct ldb_dn
*forward_dn
,
519 struct GUID
*target_guid
, bool active
,
520 const struct dsdb_attribute
*schema_attr
,
521 struct ldb_request
*parent
)
523 const struct dsdb_attribute
*target_attr
;
524 struct la_backlink bl
;
527 target_attr
= dsdb_attribute_by_linkID(schema
, schema_attr
->linkID
^ 1);
530 * windows 2003 has a broken schema where the
531 * definition of msDS-IsDomainFor is missing (which is
532 * supposed to be the backlink of the
533 * msDS-HasDomainNCs attribute
538 bl
.attr_name
= target_attr
->lDAPDisplayName
;
539 bl
.forward_dn
= forward_dn
;
540 bl
.target_guid
= *target_guid
;
543 ret
= replmd_process_backlink(module
, &bl
, parent
);
549 * Callback for most write operations in this module:
551 * notify the repl task that a object has changed. The notifies are
552 * gathered up in the replmd_private structure then written to the
553 * @REPLCHANGED object in each partition during the prepare_commit
555 static int replmd_op_callback(struct ldb_request
*req
, struct ldb_reply
*ares
)
558 struct replmd_replicated_request
*ac
=
559 talloc_get_type_abort(req
->context
, struct replmd_replicated_request
);
560 struct replmd_private
*replmd_private
=
561 talloc_get_type_abort(ldb_module_get_private(ac
->module
), struct replmd_private
);
562 struct nc_entry
*modified_partition
;
563 struct ldb_control
*partition_ctrl
;
564 const struct dsdb_control_current_partition
*partition
;
566 struct ldb_control
**controls
;
568 partition_ctrl
= ldb_reply_get_control(ares
, DSDB_CONTROL_CURRENT_PARTITION_OID
);
570 controls
= ares
->controls
;
571 if (ldb_request_get_control(ac
->req
,
572 DSDB_CONTROL_CURRENT_PARTITION_OID
) == NULL
) {
574 * Remove the current partition control from what we pass up
575 * the chain if it hasn't been requested manually.
577 controls
= ldb_controls_except_specified(ares
->controls
, ares
,
581 if (ares
->error
!= LDB_SUCCESS
) {
582 struct GUID_txt_buf guid_txt
;
583 struct ldb_message
*msg
= NULL
;
586 if (ac
->apply_mode
== false) {
587 DBG_NOTICE("Originating update failure. Error is: %s\n",
588 ldb_strerror(ares
->error
));
589 return ldb_module_done(ac
->req
, controls
,
590 ares
->response
, ares
->error
);
593 msg
= ac
->objs
->objects
[ac
->index_current
].msg
;
595 * Set at DBG_NOTICE as once these start to happe, they
596 * will happen a lot until resolved, due to repeated
597 * replication. The caller will probably print the
598 * ldb error string anyway.
600 DBG_NOTICE("DRS replication apply failure for %s. Error is: %s\n",
601 ldb_dn_get_linearized(msg
->dn
),
602 ldb_strerror(ares
->error
));
604 s
= ldb_ldif_message_redacted_string(ldb_module_get_ctx(ac
->module
),
609 DBG_INFO("Failing DRS %s replication message was %s:\n%s\n",
610 ac
->search_msg
== NULL
? "ADD" : "MODIFY",
611 GUID_buf_string(&ac
->objs
->objects
[ac
->index_current
].object_guid
,
615 return ldb_module_done(ac
->req
, controls
,
616 ares
->response
, ares
->error
);
619 if (ares
->type
!= LDB_REPLY_DONE
) {
620 ldb_set_errstring(ldb_module_get_ctx(ac
->module
), "Invalid reply type for notify\n!");
621 return ldb_module_done(ac
->req
, NULL
,
622 NULL
, LDB_ERR_OPERATIONS_ERROR
);
625 if (ac
->apply_mode
== false) {
626 struct la_backlink
*bl
;
628 * process our backlink list after an replmd_add(),
629 * creating and deleting backlinks as necessary (this
630 * code is sync). The other cases are handled inline
633 for (bl
=ac
->la_backlinks
; bl
; bl
=bl
->next
) {
634 ret
= replmd_process_backlink(ac
->module
, bl
, ac
->req
);
635 if (ret
!= LDB_SUCCESS
) {
636 return ldb_module_done(ac
->req
, NULL
,
642 if (!partition_ctrl
) {
643 ldb_set_errstring(ldb_module_get_ctx(ac
->module
),"No partition control on reply");
644 return ldb_module_done(ac
->req
, NULL
,
645 NULL
, LDB_ERR_OPERATIONS_ERROR
);
648 partition
= talloc_get_type_abort(partition_ctrl
->data
,
649 struct dsdb_control_current_partition
);
651 if (ac
->seq_num
> 0) {
652 for (modified_partition
= replmd_private
->ncs
; modified_partition
;
653 modified_partition
= modified_partition
->next
) {
654 if (ldb_dn_compare(modified_partition
->dn
, partition
->dn
) == 0) {
659 if (modified_partition
== NULL
) {
660 modified_partition
= talloc_zero(replmd_private
, struct nc_entry
);
661 if (!modified_partition
) {
662 ldb_oom(ldb_module_get_ctx(ac
->module
));
663 return ldb_module_done(ac
->req
, NULL
,
664 NULL
, LDB_ERR_OPERATIONS_ERROR
);
666 modified_partition
->dn
= ldb_dn_copy(modified_partition
, partition
->dn
);
667 if (!modified_partition
->dn
) {
668 ldb_oom(ldb_module_get_ctx(ac
->module
));
669 return ldb_module_done(ac
->req
, NULL
,
670 NULL
, LDB_ERR_OPERATIONS_ERROR
);
672 DLIST_ADD(replmd_private
->ncs
, modified_partition
);
675 if (ac
->seq_num
> modified_partition
->mod_usn
) {
676 modified_partition
->mod_usn
= ac
->seq_num
;
678 modified_partition
->mod_usn_urgent
= ac
->seq_num
;
681 if (!ac
->apply_mode
) {
682 replmd_private
->originating_updates
= true;
686 if (ac
->apply_mode
) {
687 ret
= replmd_replicated_apply_isDeleted(ac
);
688 if (ret
!= LDB_SUCCESS
) {
689 return ldb_module_done(ac
->req
, NULL
, NULL
, ret
);
693 /* free the partition control container here, for the
694 * common path. Other cases will have it cleaned up
695 * eventually with the ares */
696 talloc_free(partition_ctrl
);
697 return ldb_module_done(ac
->req
, controls
,
698 ares
->response
, LDB_SUCCESS
);
704 * update a @REPLCHANGED record in each partition if there have been
705 * any writes of replicated data in the partition
707 static int replmd_notify_store(struct ldb_module
*module
, struct ldb_request
*parent
)
709 struct replmd_private
*replmd_private
=
710 talloc_get_type(ldb_module_get_private(module
), struct replmd_private
);
712 while (replmd_private
->ncs
) {
714 struct nc_entry
*modified_partition
= replmd_private
->ncs
;
716 ret
= dsdb_module_save_partition_usn(module
, modified_partition
->dn
,
717 modified_partition
->mod_usn
,
718 modified_partition
->mod_usn_urgent
, parent
);
719 if (ret
!= LDB_SUCCESS
) {
720 DEBUG(0,(__location__
": Failed to save partition uSN for %s\n",
721 ldb_dn_get_linearized(modified_partition
->dn
)));
725 if (ldb_dn_compare(modified_partition
->dn
,
726 replmd_private
->schema_dn
) == 0) {
727 struct ldb_result
*ext_res
;
728 ret
= dsdb_module_extended(module
,
729 replmd_private
->schema_dn
,
731 DSDB_EXTENDED_SCHEMA_UPDATE_NOW_OID
,
733 DSDB_FLAG_NEXT_MODULE
,
735 if (ret
!= LDB_SUCCESS
) {
738 talloc_free(ext_res
);
741 DLIST_REMOVE(replmd_private
->ncs
, modified_partition
);
742 talloc_free(modified_partition
);
750 created a replmd_replicated_request context
752 static struct replmd_replicated_request
*replmd_ctx_init(struct ldb_module
*module
,
753 struct ldb_request
*req
)
755 struct ldb_context
*ldb
;
756 struct replmd_replicated_request
*ac
;
757 const struct GUID
*our_invocation_id
;
759 ldb
= ldb_module_get_ctx(module
);
761 ac
= talloc_zero(req
, struct replmd_replicated_request
);
770 ac
->schema
= dsdb_get_schema(ldb
, ac
);
772 ldb_debug_set(ldb
, LDB_DEBUG_FATAL
,
773 "replmd_modify: no dsdb_schema loaded");
774 DEBUG(0,(__location__
": %s\n", ldb_errstring(ldb
)));
779 /* get our invocationId */
780 our_invocation_id
= samdb_ntds_invocation_id(ldb
);
781 if (!our_invocation_id
) {
782 ldb_debug_set(ldb
, LDB_DEBUG_FATAL
,
783 "replmd_add: unable to find invocationId\n");
787 ac
->our_invocation_id
= *our_invocation_id
;
793 add a time element to a record
795 static int add_time_element(struct ldb_message
*msg
, const char *attr
, time_t t
)
797 struct ldb_message_element
*el
;
801 if (ldb_msg_find_element(msg
, attr
) != NULL
) {
805 s
= ldb_timestring(msg
, t
);
807 return LDB_ERR_OPERATIONS_ERROR
;
810 ret
= ldb_msg_add_string(msg
, attr
, s
);
811 if (ret
!= LDB_SUCCESS
) {
815 el
= ldb_msg_find_element(msg
, attr
);
816 /* always set as replace. This works because on add ops, the flag
818 el
->flags
= LDB_FLAG_MOD_REPLACE
;
824 add a uint64_t element to a record
826 static int add_uint64_element(struct ldb_context
*ldb
, struct ldb_message
*msg
,
827 const char *attr
, uint64_t v
)
829 struct ldb_message_element
*el
;
832 if (ldb_msg_find_element(msg
, attr
) != NULL
) {
836 ret
= samdb_msg_add_uint64(ldb
, msg
, msg
, attr
, v
);
837 if (ret
!= LDB_SUCCESS
) {
841 el
= ldb_msg_find_element(msg
, attr
);
842 /* always set as replace. This works because on add ops, the flag
844 el
->flags
= LDB_FLAG_MOD_REPLACE
;
849 static int replmd_replPropertyMetaData1_attid_sort(const struct replPropertyMetaData1
*m1
,
850 const struct replPropertyMetaData1
*m2
,
851 const uint32_t *rdn_attid
)
854 * This assignment seems inoccous, but it is critical for the
855 * system, as we need to do the comparisons as a unsigned
856 * quantity, not signed (enums are signed integers)
858 uint32_t attid_1
= m1
->attid
;
859 uint32_t attid_2
= m2
->attid
;
861 if (attid_1
== attid_2
) {
866 * See above regarding this being an unsigned comparison.
867 * Otherwise when the high bit is set on non-standard
868 * attributes, they would end up first, before objectClass
871 return attid_1
> attid_2
? 1 : -1;
874 static int replmd_replPropertyMetaDataCtr1_verify(struct ldb_context
*ldb
,
875 struct replPropertyMetaDataCtr1
*ctr1
,
878 if (ctr1
->count
== 0) {
879 ldb_debug_set(ldb
, LDB_DEBUG_FATAL
,
880 "No elements found in replPropertyMetaData for %s!\n",
881 ldb_dn_get_linearized(dn
));
882 return LDB_ERR_CONSTRAINT_VIOLATION
;
885 /* the objectClass attribute is value 0x00000000, so must be first */
886 if (ctr1
->array
[0].attid
!= DRSUAPI_ATTID_objectClass
) {
887 ldb_debug_set(ldb
, LDB_DEBUG_FATAL
,
888 "No objectClass found in replPropertyMetaData for %s!\n",
889 ldb_dn_get_linearized(dn
));
890 return LDB_ERR_OBJECT_CLASS_VIOLATION
;
896 static int replmd_replPropertyMetaDataCtr1_sort_and_verify(struct ldb_context
*ldb
,
897 struct replPropertyMetaDataCtr1
*ctr1
,
900 /* Note this is O(n^2) for the almost-sorted case, which this is */
901 LDB_TYPESAFE_QSORT(ctr1
->array
, ctr1
->count
, NULL
,
902 replmd_replPropertyMetaData1_attid_sort
);
903 return replmd_replPropertyMetaDataCtr1_verify(ldb
, ctr1
, dn
);
906 static int replmd_ldb_message_element_attid_sort(const struct ldb_message_element
*e1
,
907 const struct ldb_message_element
*e2
,
908 const struct dsdb_schema
*schema
)
910 const struct dsdb_attribute
*a1
;
911 const struct dsdb_attribute
*a2
;
914 * TODO: make this faster by caching the dsdb_attribute pointer
915 * on the ldb_messag_element
918 a1
= dsdb_attribute_by_lDAPDisplayName(schema
, e1
->name
);
919 a2
= dsdb_attribute_by_lDAPDisplayName(schema
, e2
->name
);
922 * TODO: remove this check, we should rely on e1 and e2 having valid attribute names
926 return strcasecmp(e1
->name
, e2
->name
);
928 if (a1
->attributeID_id
== a2
->attributeID_id
) {
931 return a1
->attributeID_id
> a2
->attributeID_id
? 1 : -1;
934 static void replmd_ldb_message_sort(struct ldb_message
*msg
,
935 const struct dsdb_schema
*schema
)
937 LDB_TYPESAFE_QSORT(msg
->elements
, msg
->num_elements
, schema
, replmd_ldb_message_element_attid_sort
);
940 static int replmd_build_la_val(TALLOC_CTX
*mem_ctx
, struct ldb_val
*v
, struct dsdb_dn
*dsdb_dn
,
941 const struct GUID
*invocation_id
,
942 uint64_t local_usn
, NTTIME nttime
);
944 static int parsed_dn_compare(struct parsed_dn
*pdn1
, struct parsed_dn
*pdn2
);
946 static int get_parsed_dns(struct ldb_module
*module
, TALLOC_CTX
*mem_ctx
,
947 struct ldb_message_element
*el
, struct parsed_dn
**pdn
,
948 const char *ldap_oid
, struct ldb_request
*parent
);
950 static int check_parsed_dn_duplicates(struct ldb_module
*module
,
951 struct ldb_message_element
*el
,
952 struct parsed_dn
*pdn
);
955 fix up linked attributes in replmd_add.
956 This involves setting up the right meta-data in extended DN
957 components, and creating backlinks to the object
959 static int replmd_add_fix_la(struct ldb_module
*module
, TALLOC_CTX
*mem_ctx
,
960 struct replmd_private
*replmd_private
,
961 struct ldb_message_element
*el
,
962 struct replmd_replicated_request
*ac
,
964 struct ldb_dn
*forward_dn
,
965 const struct dsdb_attribute
*sa
,
966 struct ldb_request
*parent
)
969 TALLOC_CTX
*tmp_ctx
= talloc_new(mem_ctx
);
970 struct ldb_context
*ldb
= ldb_module_get_ctx(module
);
971 struct parsed_dn
*pdn
;
972 /* We will take a reference to the schema in replmd_add_backlink */
973 const struct dsdb_schema
*schema
= dsdb_get_schema(ldb
, NULL
);
974 struct ldb_val
*new_values
= NULL
;
977 if (dsdb_check_single_valued_link(sa
, el
) == LDB_SUCCESS
) {
978 el
->flags
|= LDB_FLAG_INTERNAL_DISABLE_SINGLE_VALUE_CHECK
;
980 ldb_asprintf_errstring(ldb
,
981 "Attribute %s is single valued but "
982 "more than one value has been supplied",
984 talloc_free(tmp_ctx
);
985 return LDB_ERR_CONSTRAINT_VIOLATION
;
988 ret
= get_parsed_dns(module
, tmp_ctx
, el
, &pdn
,
989 sa
->syntax
->ldap_oid
, parent
);
990 if (ret
!= LDB_SUCCESS
) {
991 talloc_free(tmp_ctx
);
995 ret
= check_parsed_dn_duplicates(module
, el
, pdn
);
996 if (ret
!= LDB_SUCCESS
) {
997 talloc_free(tmp_ctx
);
1001 new_values
= talloc_array(tmp_ctx
, struct ldb_val
, el
->num_values
);
1002 if (new_values
== NULL
) {
1003 ldb_module_oom(module
);
1004 talloc_free(tmp_ctx
);
1005 return LDB_ERR_OPERATIONS_ERROR
;
1008 for (i
= 0; i
< el
->num_values
; i
++) {
1009 struct parsed_dn
*p
= &pdn
[i
];
1010 ret
= replmd_build_la_val(el
->values
, p
->v
, p
->dsdb_dn
,
1011 &ac
->our_invocation_id
,
1013 if (ret
!= LDB_SUCCESS
) {
1014 talloc_free(tmp_ctx
);
1018 ret
= replmd_defer_add_backlink(module
, replmd_private
,
1020 forward_dn
, &p
->guid
, true, sa
,
1022 if (ret
!= LDB_SUCCESS
) {
1023 talloc_free(tmp_ctx
);
1027 new_values
[i
] = *p
->v
;
1029 el
->values
= talloc_steal(mem_ctx
, new_values
);
1031 talloc_free(tmp_ctx
);
1035 static int replmd_add_make_extended_dn(struct ldb_request
*req
,
1036 const DATA_BLOB
*guid_blob
,
1037 struct ldb_dn
**_extended_dn
)
1040 const DATA_BLOB
*sid_blob
;
1041 /* Calculate an extended DN for any linked attributes */
1042 struct ldb_dn
*extended_dn
= ldb_dn_copy(req
, req
->op
.add
.message
->dn
);
1044 return LDB_ERR_OPERATIONS_ERROR
;
1046 ret
= ldb_dn_set_extended_component(extended_dn
, "GUID", guid_blob
);
1047 if (ret
!= LDB_SUCCESS
) {
1051 sid_blob
= ldb_msg_find_ldb_val(req
->op
.add
.message
, "objectSID");
1052 if (sid_blob
!= NULL
) {
1053 ret
= ldb_dn_set_extended_component(extended_dn
, "SID", sid_blob
);
1054 if (ret
!= LDB_SUCCESS
) {
1058 *_extended_dn
= extended_dn
;
1063 intercept add requests
1065 static int replmd_add(struct ldb_module
*module
, struct ldb_request
*req
)
1067 struct ldb_context
*ldb
;
1068 struct ldb_control
*control
;
1069 struct replmd_replicated_request
*ac
;
1070 enum ndr_err_code ndr_err
;
1071 struct ldb_request
*down_req
;
1072 struct ldb_message
*msg
;
1073 const DATA_BLOB
*guid_blob
;
1074 DATA_BLOB guid_blob_stack
;
1076 uint8_t guid_data
[16];
1077 struct replPropertyMetaDataBlob nmd
;
1078 struct ldb_val nmd_value
;
1079 struct ldb_dn
*extended_dn
= NULL
;
1082 * The use of a time_t here seems odd, but as the NTTIME
1083 * elements are actually declared as NTTIME_1sec in the IDL,
1084 * getting a higher resolution timestamp is not required.
1086 time_t t
= time(NULL
);
1091 unsigned int functional_level
;
1093 bool allow_add_guid
= false;
1094 bool remove_current_guid
= false;
1095 bool is_urgent
= false;
1096 bool is_schema_nc
= false;
1097 struct ldb_message_element
*objectclass_el
;
1098 struct replmd_private
*replmd_private
=
1099 talloc_get_type_abort(ldb_module_get_private(module
), struct replmd_private
);
1101 /* check if there's a show relax control (used by provision to say 'I know what I'm doing') */
1102 control
= ldb_request_get_control(req
, LDB_CONTROL_RELAX_OID
);
1104 allow_add_guid
= true;
1107 /* do not manipulate our control entries */
1108 if (ldb_dn_is_special(req
->op
.add
.message
->dn
)) {
1109 return ldb_next_request(module
, req
);
1112 ldb
= ldb_module_get_ctx(module
);
1114 ldb_debug(ldb
, LDB_DEBUG_TRACE
, "replmd_add\n");
1116 guid_blob
= ldb_msg_find_ldb_val(req
->op
.add
.message
, "objectGUID");
1117 if (guid_blob
!= NULL
) {
1118 if (!allow_add_guid
) {
1119 ldb_set_errstring(ldb
,
1120 "replmd_add: it's not allowed to add an object with objectGUID!");
1121 return LDB_ERR_UNWILLING_TO_PERFORM
;
1123 NTSTATUS status
= GUID_from_data_blob(guid_blob
,&guid
);
1124 if (!NT_STATUS_IS_OK(status
)) {
1125 ldb_set_errstring(ldb
,
1126 "replmd_add: Unable to parse the 'objectGUID' as a GUID!");
1127 return LDB_ERR_UNWILLING_TO_PERFORM
;
1129 /* we remove this attribute as it can be a string and
1130 * will not be treated correctly and then we will re-add
1131 * it later on in the good format */
1132 remove_current_guid
= true;
1136 guid
= GUID_random();
1138 guid_blob_stack
= data_blob_const(guid_data
, sizeof(guid_data
));
1140 /* This can't fail */
1141 ndr_push_struct_into_fixed_blob(&guid_blob_stack
, &guid
,
1142 (ndr_push_flags_fn_t
)ndr_push_GUID
);
1143 guid_blob
= &guid_blob_stack
;
1146 ac
= replmd_ctx_init(module
, req
);
1148 return ldb_module_oom(module
);
1151 functional_level
= dsdb_functional_level(ldb
);
1153 /* Get a sequence number from the backend */
1154 ret
= ldb_sequence_number(ldb
, LDB_SEQ_NEXT
, &ac
->seq_num
);
1155 if (ret
!= LDB_SUCCESS
) {
1160 /* we have to copy the message as the caller might have it as a const */
1161 msg
= ldb_msg_copy_shallow(ac
, req
->op
.add
.message
);
1165 return LDB_ERR_OPERATIONS_ERROR
;
1168 /* generated times */
1169 unix_to_nt_time(&now
, t
);
1170 time_str
= ldb_timestring(msg
, t
);
1174 return LDB_ERR_OPERATIONS_ERROR
;
1176 if (remove_current_guid
) {
1177 ldb_msg_remove_attr(msg
,"objectGUID");
1181 * remove autogenerated attributes
1183 ldb_msg_remove_attr(msg
, "whenCreated");
1184 ldb_msg_remove_attr(msg
, "whenChanged");
1185 ldb_msg_remove_attr(msg
, "uSNCreated");
1186 ldb_msg_remove_attr(msg
, "uSNChanged");
1187 ldb_msg_remove_attr(msg
, "replPropertyMetaData");
1190 * readd replicated attributes
1192 ret
= ldb_msg_add_string(msg
, "whenCreated", time_str
);
1193 if (ret
!= LDB_SUCCESS
) {
1199 /* build the replication meta_data */
1202 nmd
.ctr
.ctr1
.count
= msg
->num_elements
;
1203 nmd
.ctr
.ctr1
.array
= talloc_array(msg
,
1204 struct replPropertyMetaData1
,
1205 nmd
.ctr
.ctr1
.count
);
1206 if (!nmd
.ctr
.ctr1
.array
) {
1209 return LDB_ERR_OPERATIONS_ERROR
;
1212 is_schema_nc
= ldb_dn_compare_base(replmd_private
->schema_dn
, msg
->dn
) == 0;
1214 for (i
=0; i
< msg
->num_elements
;) {
1215 struct ldb_message_element
*e
= &msg
->elements
[i
];
1216 struct replPropertyMetaData1
*m
= &nmd
.ctr
.ctr1
.array
[ni
];
1217 const struct dsdb_attribute
*sa
;
1219 if (e
->name
[0] == '@') {
1224 sa
= dsdb_attribute_by_lDAPDisplayName(ac
->schema
, e
->name
);
1226 ldb_debug_set(ldb
, LDB_DEBUG_ERROR
,
1227 "replmd_add: attribute '%s' not defined in schema\n",
1230 return LDB_ERR_NO_SUCH_ATTRIBUTE
;
1233 if ((sa
->systemFlags
& DS_FLAG_ATTR_NOT_REPLICATED
) || (sa
->systemFlags
& DS_FLAG_ATTR_IS_CONSTRUCTED
)) {
1234 /* if the attribute is not replicated (0x00000001)
1235 * or constructed (0x00000004) it has no metadata
1241 if (sa
->linkID
!= 0 && functional_level
> DS_DOMAIN_FUNCTION_2000
) {
1242 if (extended_dn
== NULL
) {
1243 ret
= replmd_add_make_extended_dn(req
,
1246 if (ret
!= LDB_SUCCESS
) {
1253 * Prepare the context for the backlinks and
1254 * create metadata for the forward links. The
1255 * backlinks are created in
1256 * replmd_op_callback() after the successful
1257 * ADD of the object.
1259 ret
= replmd_add_fix_la(module
, msg
->elements
,
1264 if (ret
!= LDB_SUCCESS
) {
1268 /* linked attributes are not stored in
1269 replPropertyMetaData in FL above w2k */
1274 m
->attid
= dsdb_attribute_get_attid(sa
, is_schema_nc
);
1276 if (m
->attid
== DRSUAPI_ATTID_isDeleted
) {
1277 const struct ldb_val
*rdn_val
= ldb_dn_get_rdn_val(msg
->dn
);
1280 if (rdn_val
== NULL
) {
1283 return LDB_ERR_OPERATIONS_ERROR
;
1286 rdn
= (const char*)rdn_val
->data
;
1287 if (strcmp(rdn
, "Deleted Objects") == 0) {
1289 * Set the originating_change_time to 29/12/9999 at 23:59:59
1290 * as specified in MS-ADTS 7.1.1.4.2 Deleted Objects Container
1292 m
->originating_change_time
= DELETED_OBJECT_CONTAINER_CHANGE_TIME
;
1294 m
->originating_change_time
= now
;
1297 m
->originating_change_time
= now
;
1299 m
->originating_invocation_id
= ac
->our_invocation_id
;
1300 m
->originating_usn
= ac
->seq_num
;
1301 m
->local_usn
= ac
->seq_num
;
1304 if (!(e
->flags
& DSDB_FLAG_INTERNAL_FORCE_META_DATA
)) {
1309 e
->flags
&= ~DSDB_FLAG_INTERNAL_FORCE_META_DATA
;
1311 if (e
->num_values
!= 0) {
1316 ldb_msg_remove_element(msg
, e
);
1319 /* fix meta data count */
1320 nmd
.ctr
.ctr1
.count
= ni
;
1323 * sort meta data array
1325 ret
= replmd_replPropertyMetaDataCtr1_sort_and_verify(ldb
, &nmd
.ctr
.ctr1
, msg
->dn
);
1326 if (ret
!= LDB_SUCCESS
) {
1327 ldb_asprintf_errstring(ldb
, "%s: error during direct ADD: %s", __func__
, ldb_errstring(ldb
));
1332 /* generated NDR encoded values */
1333 ndr_err
= ndr_push_struct_blob(&nmd_value
, msg
,
1335 (ndr_push_flags_fn_t
)ndr_push_replPropertyMetaDataBlob
);
1336 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err
)) {
1339 return LDB_ERR_OPERATIONS_ERROR
;
1343 * add the autogenerated values
1345 ret
= dsdb_msg_add_guid(msg
, &guid
, "objectGUID");
1346 if (ret
!= LDB_SUCCESS
) {
1351 ret
= ldb_msg_add_string(msg
, "whenChanged", time_str
);
1352 if (ret
!= LDB_SUCCESS
) {
1357 ret
= samdb_msg_add_uint64(ldb
, msg
, msg
, "uSNCreated", ac
->seq_num
);
1358 if (ret
!= LDB_SUCCESS
) {
1363 ret
= samdb_msg_add_uint64(ldb
, msg
, msg
, "uSNChanged", ac
->seq_num
);
1364 if (ret
!= LDB_SUCCESS
) {
1369 ret
= ldb_msg_add_value(msg
, "replPropertyMetaData", &nmd_value
, NULL
);
1370 if (ret
!= LDB_SUCCESS
) {
1377 * sort the attributes by attid before storing the object
1379 replmd_ldb_message_sort(msg
, ac
->schema
);
1382 * Assert that we do have an objectClass
1384 objectclass_el
= ldb_msg_find_element(msg
, "objectClass");
1385 if (objectclass_el
== NULL
) {
1386 ldb_asprintf_errstring(ldb
, __location__
1387 ": objectClass missing on %s\n",
1388 ldb_dn_get_linearized(msg
->dn
));
1390 return LDB_ERR_OBJECT_CLASS_VIOLATION
;
1392 is_urgent
= replmd_check_urgent_objectclass(objectclass_el
,
1393 REPL_URGENT_ON_CREATE
);
1395 ac
->is_urgent
= is_urgent
;
1396 ret
= ldb_build_add_req(&down_req
, ldb
, ac
,
1399 ac
, replmd_op_callback
,
1402 LDB_REQ_SET_LOCATION(down_req
);
1403 if (ret
!= LDB_SUCCESS
) {
1408 /* current partition control is needed by "replmd_op_callback" */
1409 if (ldb_request_get_control(req
, DSDB_CONTROL_CURRENT_PARTITION_OID
) == NULL
) {
1410 ret
= ldb_request_add_control(down_req
,
1411 DSDB_CONTROL_CURRENT_PARTITION_OID
,
1413 if (ret
!= LDB_SUCCESS
) {
1419 if (functional_level
== DS_DOMAIN_FUNCTION_2000
) {
1420 ret
= ldb_request_add_control(down_req
, DSDB_CONTROL_APPLY_LINKS
, false, NULL
);
1421 if (ret
!= LDB_SUCCESS
) {
1427 /* mark the control done */
1429 control
->critical
= 0;
1431 /* go on with the call chain */
1432 return ldb_next_request(module
, down_req
);
1437 * update the replPropertyMetaData for one element
1439 static int replmd_update_rpmd_element(struct ldb_context
*ldb
,
1440 struct ldb_message
*msg
,
1441 struct ldb_message_element
*el
,
1442 struct ldb_message_element
*old_el
,
1443 struct replPropertyMetaDataBlob
*omd
,
1444 const struct dsdb_schema
*schema
,
1446 const struct GUID
*our_invocation_id
,
1449 bool is_forced_rodc
,
1450 struct ldb_request
*req
)
1453 const struct dsdb_attribute
*a
;
1454 struct replPropertyMetaData1
*md1
;
1455 bool may_skip
= false;
1458 a
= dsdb_attribute_by_lDAPDisplayName(schema
, el
->name
);
1460 if (ldb_request_get_control(req
, LDB_CONTROL_RELAX_OID
)) {
1461 /* allow this to make it possible for dbcheck
1462 to remove bad attributes */
1466 DEBUG(0,(__location__
": Unable to find attribute %s in schema\n",
1468 return LDB_ERR_OPERATIONS_ERROR
;
1471 attid
= dsdb_attribute_get_attid(a
, is_schema_nc
);
1473 if ((a
->systemFlags
& DS_FLAG_ATTR_NOT_REPLICATED
) || (a
->systemFlags
& DS_FLAG_ATTR_IS_CONSTRUCTED
)) {
1478 * if the attribute's value haven't changed, and this isn't
1479 * just a delete of everything then return LDB_SUCCESS Unless
1480 * we have the provision control or if the attribute is
1481 * interSiteTopologyGenerator as this page explain:
1482 * http://support.microsoft.com/kb/224815 this attribute is
1483 * periodicaly written by the DC responsible for the intersite
1484 * generation in a given site
1486 * Unchanged could be deleting or replacing an already-gone
1487 * thing with an unconstrained delete/empty replace or a
1488 * replace with the same value, but not an add with the same
1489 * value because that could be about adding a duplicate (which
1490 * is for someone else to error out on).
1492 if (old_el
!= NULL
&& ldb_msg_element_equal_ordered(el
, old_el
)) {
1493 if (LDB_FLAG_MOD_TYPE(el
->flags
) == LDB_FLAG_MOD_REPLACE
) {
1496 } else if (old_el
== NULL
&& el
->num_values
== 0) {
1497 if (LDB_FLAG_MOD_TYPE(el
->flags
) == LDB_FLAG_MOD_REPLACE
) {
1499 } else if (LDB_FLAG_MOD_TYPE(el
->flags
) == LDB_FLAG_MOD_DELETE
) {
1502 } else if (a
->linkID
!= 0 && LDB_FLAG_MOD_TYPE(el
->flags
) == LDB_FLAG_MOD_DELETE
&&
1503 ldb_request_get_control(req
, DSDB_CONTROL_REPLMD_VANISH_LINKS
) != NULL
) {
1505 * We intentionally skip the version bump when attempting to
1508 * The control is set by dbcheck and expunge-tombstones which
1509 * both attempt to be non-replicating. Otherwise, making an
1510 * alteration to the replication state would trigger a
1511 * broadcast of all expunged objects.
1516 if (el
->flags
& DSDB_FLAG_INTERNAL_FORCE_META_DATA
) {
1518 el
->flags
&= ~DSDB_FLAG_INTERNAL_FORCE_META_DATA
;
1522 if (strcmp(el
->name
, "interSiteTopologyGenerator") != 0 &&
1523 !ldb_request_get_control(req
, LDB_CONTROL_PROVISION_OID
)) {
1525 * allow this to make it possible for dbcheck
1526 * to rebuild broken metadata
1532 for (i
=0; i
<omd
->ctr
.ctr1
.count
; i
++) {
1534 * First check if we find it under the msDS-IntID,
1535 * then check if we find it under the OID and
1538 * This allows the administrator to simply re-write
1539 * the attributes and so restore replication, which is
1540 * likely what they will try to do.
1542 if (attid
== omd
->ctr
.ctr1
.array
[i
].attid
) {
1546 if (a
->attributeID_id
== omd
->ctr
.ctr1
.array
[i
].attid
) {
1551 if (a
->linkID
!= 0 && dsdb_functional_level(ldb
) > DS_DOMAIN_FUNCTION_2000
) {
1552 /* linked attributes are not stored in
1553 replPropertyMetaData in FL above w2k, but we do
1554 raise the seqnum for the object */
1555 if (*seq_num
== 0 &&
1556 ldb_sequence_number(ldb
, LDB_SEQ_NEXT
, seq_num
) != LDB_SUCCESS
) {
1557 return LDB_ERR_OPERATIONS_ERROR
;
1562 if (i
== omd
->ctr
.ctr1
.count
) {
1563 /* we need to add a new one */
1564 omd
->ctr
.ctr1
.array
= talloc_realloc(msg
, omd
->ctr
.ctr1
.array
,
1565 struct replPropertyMetaData1
, omd
->ctr
.ctr1
.count
+1);
1566 if (omd
->ctr
.ctr1
.array
== NULL
) {
1568 return LDB_ERR_OPERATIONS_ERROR
;
1570 omd
->ctr
.ctr1
.count
++;
1571 ZERO_STRUCT(omd
->ctr
.ctr1
.array
[i
]);
1574 /* Get a new sequence number from the backend. We only do this
1575 * if we have a change that requires a new
1576 * replPropertyMetaData element
1578 if (*seq_num
== 0) {
1579 int ret
= ldb_sequence_number(ldb
, LDB_SEQ_NEXT
, seq_num
);
1580 if (ret
!= LDB_SUCCESS
) {
1581 return LDB_ERR_OPERATIONS_ERROR
;
1585 md1
= &omd
->ctr
.ctr1
.array
[i
];
1589 if (md1
->attid
== DRSUAPI_ATTID_isDeleted
) {
1590 const struct ldb_val
*rdn_val
= ldb_dn_get_rdn_val(msg
->dn
);
1593 if (rdn_val
== NULL
) {
1595 return LDB_ERR_OPERATIONS_ERROR
;
1598 rdn
= (const char*)rdn_val
->data
;
1599 if (strcmp(rdn
, "Deleted Objects") == 0) {
1601 * Set the originating_change_time to 29/12/9999 at 23:59:59
1602 * as specified in MS-ADTS 7.1.1.4.2 Deleted Objects Container
1604 md1
->originating_change_time
= DELETED_OBJECT_CONTAINER_CHANGE_TIME
;
1606 md1
->originating_change_time
= now
;
1609 md1
->originating_change_time
= now
;
1611 md1
->originating_invocation_id
= *our_invocation_id
;
1612 md1
->originating_usn
= *seq_num
;
1613 md1
->local_usn
= *seq_num
;
1615 if (is_forced_rodc
) {
1616 /* Force version to 0 to be overriden later via replication */
1624 * Bump the replPropertyMetaData version on an attribute, and if it
1625 * has changed (or forced by leaving rdn_old NULL), update the value
1628 * This is important, as calling a modify operation may not change the
1629 * version number if the values appear unchanged, but a rename between
1630 * parents bumps this value.
1633 static int replmd_update_rpmd_rdn_attr(struct ldb_context
*ldb
,
1634 struct ldb_message
*msg
,
1635 const struct ldb_val
*rdn_new
,
1636 const struct ldb_val
*rdn_old
,
1637 struct replPropertyMetaDataBlob
*omd
,
1638 struct replmd_replicated_request
*ar
,
1641 bool is_forced_rodc
)
1643 const char *rdn_name
= ldb_dn_get_rdn_name(msg
->dn
);
1644 const struct dsdb_attribute
*rdn_attr
=
1645 dsdb_attribute_by_lDAPDisplayName(ar
->schema
, rdn_name
);
1646 const char *attr_name
= rdn_attr
!= NULL
?
1647 rdn_attr
->lDAPDisplayName
:
1649 struct ldb_message_element new_el
= {
1650 .flags
= LDB_FLAG_MOD_REPLACE
,
1653 .values
= discard_const_p(struct ldb_val
, rdn_new
)
1655 struct ldb_message_element old_el
= {
1656 .flags
= LDB_FLAG_MOD_REPLACE
,
1658 .num_values
= rdn_old
? 1 : 0,
1659 .values
= discard_const_p(struct ldb_val
, rdn_old
)
1662 if (ldb_msg_element_equal_ordered(&new_el
, &old_el
) == false) {
1663 int ret
= ldb_msg_add(msg
, &new_el
, LDB_FLAG_MOD_REPLACE
);
1664 if (ret
!= LDB_SUCCESS
) {
1665 return ldb_oom(ldb
);
1669 return replmd_update_rpmd_element(ldb
, msg
, &new_el
, NULL
,
1670 omd
, ar
->schema
, &ar
->seq_num
,
1671 &ar
->our_invocation_id
,
1672 now
, is_schema_nc
, is_forced_rodc
,
1677 static uint64_t find_max_local_usn(struct replPropertyMetaDataBlob omd
)
1679 uint32_t count
= omd
.ctr
.ctr1
.count
;
1682 for (i
=0; i
< count
; i
++) {
1683 struct replPropertyMetaData1 m
= omd
.ctr
.ctr1
.array
[i
];
1684 if (max
< m
.local_usn
) {
1692 * update the replPropertyMetaData object each time we modify an
1693 * object. This is needed for DRS replication, as the merge on the
1694 * client is based on this object
1696 static int replmd_update_rpmd(struct ldb_module
*module
,
1697 const struct dsdb_schema
*schema
,
1698 struct ldb_request
*req
,
1699 const char * const *rename_attrs
,
1700 struct ldb_message
*msg
, uint64_t *seq_num
,
1701 time_t t
, bool is_schema_nc
,
1702 bool *is_urgent
, bool *rodc
)
1704 const struct ldb_val
*omd_value
;
1705 enum ndr_err_code ndr_err
;
1706 struct replPropertyMetaDataBlob omd
;
1709 const struct GUID
*our_invocation_id
;
1711 const char * const *attrs
= NULL
;
1712 const char * const attrs2
[] = { "uSNChanged", "objectClass", "instanceType", NULL
};
1713 struct ldb_result
*res
;
1714 struct ldb_context
*ldb
;
1715 struct ldb_message_element
*objectclass_el
;
1716 enum urgent_situation situation
;
1717 bool rmd_is_provided
;
1718 bool rmd_is_just_resorted
= false;
1719 const char *not_rename_attrs
[4 + msg
->num_elements
];
1720 bool is_forced_rodc
= false;
1723 attrs
= rename_attrs
;
1725 for (i
= 0; i
< msg
->num_elements
; i
++) {
1726 not_rename_attrs
[i
] = msg
->elements
[i
].name
;
1728 not_rename_attrs
[i
] = "replPropertyMetaData";
1729 not_rename_attrs
[i
+1] = "objectClass";
1730 not_rename_attrs
[i
+2] = "instanceType";
1731 not_rename_attrs
[i
+3] = NULL
;
1732 attrs
= not_rename_attrs
;
1735 ldb
= ldb_module_get_ctx(module
);
1737 ret
= samdb_rodc(ldb
, rodc
);
1738 if (ret
!= LDB_SUCCESS
) {
1739 DEBUG(4, (__location__
": unable to tell if we are an RODC\n"));
1744 ldb_request_get_control(req
, DSDB_CONTROL_FORCE_RODC_LOCAL_CHANGE
)) {
1745 is_forced_rodc
= true;
1748 our_invocation_id
= samdb_ntds_invocation_id(ldb
);
1749 if (!our_invocation_id
) {
1750 /* this happens during an initial vampire while
1751 updating the schema */
1752 DEBUG(5,("No invocationID - skipping replPropertyMetaData update\n"));
1756 unix_to_nt_time(&now
, t
);
1758 if (ldb_request_get_control(req
, DSDB_CONTROL_CHANGEREPLMETADATA_OID
)) {
1759 rmd_is_provided
= true;
1760 if (ldb_request_get_control(req
, DSDB_CONTROL_CHANGEREPLMETADATA_RESORT_OID
)) {
1761 rmd_is_just_resorted
= true;
1764 rmd_is_provided
= false;
1767 /* if isDeleted is present and is TRUE, then we consider we are deleting,
1768 * otherwise we consider we are updating */
1769 if (ldb_msg_check_string_attribute(msg
, "isDeleted", "TRUE")) {
1770 situation
= REPL_URGENT_ON_DELETE
;
1771 } else if (rename_attrs
) {
1772 situation
= REPL_URGENT_ON_CREATE
| REPL_URGENT_ON_DELETE
;
1774 situation
= REPL_URGENT_ON_UPDATE
;
1777 if (rmd_is_provided
) {
1778 /* In this case the change_replmetadata control was supplied */
1779 /* We check that it's the only attribute that is provided
1780 * (it's a rare case so it's better to keep the code simplier)
1781 * We also check that the highest local_usn is bigger or the same as
1784 if( msg
->num_elements
!= 1 ||
1785 strncmp(msg
->elements
[0].name
,
1786 "replPropertyMetaData", 20) ) {
1787 DEBUG(0,(__location__
": changereplmetada control called without "\
1788 "a specified replPropertyMetaData attribute or with others\n"));
1789 return LDB_ERR_OPERATIONS_ERROR
;
1791 if (situation
!= REPL_URGENT_ON_UPDATE
) {
1792 DEBUG(0,(__location__
": changereplmetada control can't be called when deleting an object\n"));
1793 return LDB_ERR_OPERATIONS_ERROR
;
1795 omd_value
= ldb_msg_find_ldb_val(msg
, "replPropertyMetaData");
1797 DEBUG(0,(__location__
": replPropertyMetaData was not specified for Object %s\n",
1798 ldb_dn_get_linearized(msg
->dn
)));
1799 return LDB_ERR_OPERATIONS_ERROR
;
1801 ndr_err
= ndr_pull_struct_blob(omd_value
, msg
, &omd
,
1802 (ndr_pull_flags_fn_t
)ndr_pull_replPropertyMetaDataBlob
);
1803 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err
)) {
1804 DEBUG(0,(__location__
": Failed to parse replPropertyMetaData for %s\n",
1805 ldb_dn_get_linearized(msg
->dn
)));
1806 return LDB_ERR_OPERATIONS_ERROR
;
1809 ret
= dsdb_module_search_dn(module
, msg
, &res
, msg
->dn
, attrs2
,
1810 DSDB_FLAG_NEXT_MODULE
|
1811 DSDB_SEARCH_SHOW_RECYCLED
|
1812 DSDB_SEARCH_SHOW_EXTENDED_DN
|
1813 DSDB_SEARCH_SHOW_DN_IN_STORAGE_FORMAT
|
1814 DSDB_SEARCH_REVEAL_INTERNALS
, req
);
1816 if (ret
!= LDB_SUCCESS
) {
1820 if (rmd_is_just_resorted
== false) {
1821 *seq_num
= find_max_local_usn(omd
);
1823 db_seq
= ldb_msg_find_attr_as_uint64(res
->msgs
[0], "uSNChanged", 0);
1826 * The test here now allows for a new
1827 * replPropertyMetaData with no change, if was
1828 * just dbcheck re-sorting the values.
1830 if (*seq_num
<= db_seq
) {
1831 DEBUG(0,(__location__
": changereplmetada control provided but max(local_usn)" \
1832 " is less than uSNChanged (max = %lld uSNChanged = %lld)\n",
1833 (long long)*seq_num
, (long long)db_seq
));
1834 return LDB_ERR_OPERATIONS_ERROR
;
1839 /* search for the existing replPropertyMetaDataBlob. We need
1840 * to use REVEAL and ask for DNs in storage format to support
1841 * the check for values being the same in
1842 * replmd_update_rpmd_element()
1844 ret
= dsdb_module_search_dn(module
, msg
, &res
, msg
->dn
, attrs
,
1845 DSDB_FLAG_NEXT_MODULE
|
1846 DSDB_SEARCH_SHOW_RECYCLED
|
1847 DSDB_SEARCH_SHOW_EXTENDED_DN
|
1848 DSDB_SEARCH_SHOW_DN_IN_STORAGE_FORMAT
|
1849 DSDB_SEARCH_REVEAL_INTERNALS
, req
);
1850 if (ret
!= LDB_SUCCESS
) {
1854 omd_value
= ldb_msg_find_ldb_val(res
->msgs
[0], "replPropertyMetaData");
1856 DEBUG(0,(__location__
": Object %s does not have a replPropertyMetaData attribute\n",
1857 ldb_dn_get_linearized(msg
->dn
)));
1858 return LDB_ERR_OPERATIONS_ERROR
;
1861 ndr_err
= ndr_pull_struct_blob(omd_value
, msg
, &omd
,
1862 (ndr_pull_flags_fn_t
)ndr_pull_replPropertyMetaDataBlob
);
1863 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err
)) {
1864 DEBUG(0,(__location__
": Failed to parse replPropertyMetaData for %s\n",
1865 ldb_dn_get_linearized(msg
->dn
)));
1866 return LDB_ERR_OPERATIONS_ERROR
;
1869 if (omd
.version
!= 1) {
1870 DEBUG(0,(__location__
": bad version %u in replPropertyMetaData for %s\n",
1871 omd
.version
, ldb_dn_get_linearized(msg
->dn
)));
1872 return LDB_ERR_OPERATIONS_ERROR
;
1875 for (i
=0; i
<msg
->num_elements
;) {
1876 struct ldb_message_element
*el
= &msg
->elements
[i
];
1877 struct ldb_message_element
*old_el
;
1879 old_el
= ldb_msg_find_element(res
->msgs
[0], el
->name
);
1880 ret
= replmd_update_rpmd_element(ldb
, msg
, el
, old_el
,
1881 &omd
, schema
, seq_num
,
1886 if (ret
!= LDB_SUCCESS
) {
1890 if (!*is_urgent
&& (situation
== REPL_URGENT_ON_UPDATE
)) {
1891 *is_urgent
= replmd_check_urgent_attribute(el
);
1894 if (!(el
->flags
& DSDB_FLAG_INTERNAL_FORCE_META_DATA
)) {
1899 el
->flags
&= ~DSDB_FLAG_INTERNAL_FORCE_META_DATA
;
1901 if (el
->num_values
!= 0) {
1906 ldb_msg_remove_element(msg
, el
);
1911 * Assert that we have an objectClass attribute - this is major
1912 * corruption if we don't have this!
1914 objectclass_el
= ldb_msg_find_element(res
->msgs
[0], "objectClass");
1915 if (objectclass_el
!= NULL
) {
1917 * Now check if this objectClass means we need to do urgent replication
1919 if (!*is_urgent
&& replmd_check_urgent_objectclass(objectclass_el
,
1923 } else if (!ldb_request_get_control(req
, DSDB_CONTROL_DBCHECK
)) {
1924 ldb_asprintf_errstring(ldb
, __location__
1925 ": objectClass missing on %s\n",
1926 ldb_dn_get_linearized(msg
->dn
));
1927 return LDB_ERR_OBJECT_CLASS_VIOLATION
;
1931 * replmd_update_rpmd_element has done an update if the
1934 if (*seq_num
!= 0 || rmd_is_just_resorted
== true) {
1935 struct ldb_val
*md_value
;
1936 struct ldb_message_element
*el
;
1938 /*if we are RODC and this is a DRSR update then its ok*/
1939 if (!ldb_request_get_control(req
, DSDB_CONTROL_REPLICATED_UPDATE_OID
)
1940 && !ldb_request_get_control(req
, DSDB_CONTROL_DBCHECK_MODIFY_RO_REPLICA
)
1941 && !is_forced_rodc
) {
1942 unsigned instanceType
;
1945 ldb_set_errstring(ldb
, "RODC modify is forbidden!");
1946 return LDB_ERR_REFERRAL
;
1949 instanceType
= ldb_msg_find_attr_as_uint(res
->msgs
[0], "instanceType", INSTANCE_TYPE_WRITE
);
1950 if (!(instanceType
& INSTANCE_TYPE_WRITE
)) {
1951 return ldb_error(ldb
, LDB_ERR_UNWILLING_TO_PERFORM
,
1952 "cannot change replicated attribute on partial replica");
1956 md_value
= talloc(msg
, struct ldb_val
);
1957 if (md_value
== NULL
) {
1959 return LDB_ERR_OPERATIONS_ERROR
;
1962 ret
= replmd_replPropertyMetaDataCtr1_sort_and_verify(ldb
, &omd
.ctr
.ctr1
, msg
->dn
);
1963 if (ret
!= LDB_SUCCESS
) {
1964 ldb_asprintf_errstring(ldb
, "%s: %s", __func__
, ldb_errstring(ldb
));
1968 ndr_err
= ndr_push_struct_blob(md_value
, msg
, &omd
,
1969 (ndr_push_flags_fn_t
)ndr_push_replPropertyMetaDataBlob
);
1970 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err
)) {
1971 DEBUG(0,(__location__
": Failed to marshall replPropertyMetaData for %s\n",
1972 ldb_dn_get_linearized(msg
->dn
)));
1973 return LDB_ERR_OPERATIONS_ERROR
;
1976 ret
= ldb_msg_add_empty(msg
, "replPropertyMetaData", LDB_FLAG_MOD_REPLACE
, &el
);
1977 if (ret
!= LDB_SUCCESS
) {
1978 DEBUG(0,(__location__
": Failed to add updated replPropertyMetaData %s\n",
1979 ldb_dn_get_linearized(msg
->dn
)));
1984 el
->values
= md_value
;
1990 static int parsed_dn_compare(struct parsed_dn
*pdn1
, struct parsed_dn
*pdn2
)
1992 int ret
= ndr_guid_compare(&pdn1
->guid
, &pdn2
->guid
);
1994 return data_blob_cmp(&pdn1
->dsdb_dn
->extra_part
,
1995 &pdn2
->dsdb_dn
->extra_part
);
2001 get a series of message element values as an array of DNs and GUIDs
2002 the result is sorted by GUID
2004 static int get_parsed_dns(struct ldb_module
*module
, TALLOC_CTX
*mem_ctx
,
2005 struct ldb_message_element
*el
, struct parsed_dn
**pdn
,
2006 const char *ldap_oid
, struct ldb_request
*parent
)
2009 bool values_are_sorted
= true;
2010 struct ldb_context
*ldb
= ldb_module_get_ctx(module
);
2017 (*pdn
) = talloc_array(mem_ctx
, struct parsed_dn
, el
->num_values
);
2019 ldb_module_oom(module
);
2020 return LDB_ERR_OPERATIONS_ERROR
;
2023 for (i
=0; i
<el
->num_values
; i
++) {
2024 struct ldb_val
*v
= &el
->values
[i
];
2027 struct parsed_dn
*p
;
2031 p
->dsdb_dn
= dsdb_dn_parse(*pdn
, ldb
, v
, ldap_oid
);
2032 if (p
->dsdb_dn
== NULL
) {
2033 return LDB_ERR_INVALID_DN_SYNTAX
;
2036 dn
= p
->dsdb_dn
->dn
;
2038 status
= dsdb_get_extended_dn_guid(dn
, &p
->guid
, "GUID");
2039 if (NT_STATUS_EQUAL(status
, NT_STATUS_OBJECT_NAME_NOT_FOUND
) ||
2040 unlikely(GUID_all_zero(&p
->guid
))) {
2041 /* we got a DN without a GUID - go find the GUID */
2042 int ret
= dsdb_module_guid_by_dn(module
, dn
, &p
->guid
, parent
);
2043 if (ret
!= LDB_SUCCESS
) {
2044 ldb_asprintf_errstring(ldb
, "Unable to find GUID for DN %s\n",
2045 ldb_dn_get_linearized(dn
));
2046 if (ret
== LDB_ERR_NO_SUCH_OBJECT
&&
2047 LDB_FLAG_MOD_TYPE(el
->flags
) == LDB_FLAG_MOD_DELETE
&&
2048 ldb_attr_cmp(el
->name
, "member") == 0) {
2049 return LDB_ERR_UNWILLING_TO_PERFORM
;
2053 ret
= dsdb_set_extended_dn_guid(dn
, &p
->guid
, "GUID");
2054 if (ret
!= LDB_SUCCESS
) {
2057 } else if (!NT_STATUS_IS_OK(status
)) {
2058 return LDB_ERR_OPERATIONS_ERROR
;
2060 if (i
> 0 && values_are_sorted
) {
2061 int cmp
= parsed_dn_compare(p
, &(*pdn
)[i
- 1]);
2063 values_are_sorted
= false;
2066 /* keep a pointer to the original ldb_val */
2069 if (! values_are_sorted
) {
2070 TYPESAFE_QSORT(*pdn
, el
->num_values
, parsed_dn_compare
);
2076 * Get a series of trusted message element values. The result is sorted by
2077 * GUID, even though the GUIDs might not be known. That works because we trust
2078 * the database to give us the elements like that if the
2079 * replmd_private->sorted_links flag is set.
2081 * We also ensure that the links are in the Functional Level 2003
2082 * linked attributes format.
2084 static int get_parsed_dns_trusted(struct ldb_module
*module
,
2085 struct replmd_private
*replmd_private
,
2086 TALLOC_CTX
*mem_ctx
,
2087 struct ldb_message_element
*el
,
2088 struct parsed_dn
**pdn
,
2089 const char *ldap_oid
,
2090 struct ldb_request
*parent
)
2099 if (!replmd_private
->sorted_links
) {
2100 /* We need to sort the list. This is the slow old path we want
2103 ret
= get_parsed_dns(module
, mem_ctx
, el
, pdn
, ldap_oid
,
2105 if (ret
!= LDB_SUCCESS
) {
2109 /* Here we get a list of 'struct parsed_dns' without the parsing */
2110 *pdn
= talloc_zero_array(mem_ctx
, struct parsed_dn
,
2113 ldb_module_oom(module
);
2114 return LDB_ERR_OPERATIONS_ERROR
;
2117 for (i
= 0; i
< el
->num_values
; i
++) {
2118 (*pdn
)[i
].v
= &el
->values
[i
];
2123 * This upgrades links to FL2003 style, and sorts the result
2124 * if that was needed.
2126 * TODO: Add a database feature that asserts we have no FL2000
2127 * style links to avoid this check or add a feature that
2128 * uses a similar check to find sorted/unsorted links
2129 * for an on-the-fly upgrade.
2132 ret
= replmd_check_upgrade_links(ldb_module_get_ctx(module
),
2133 *pdn
, el
->num_values
,
2136 if (ret
!= LDB_SUCCESS
) {
2144 Return LDB_SUCCESS if a parsed_dn list contains no duplicate values,
2145 otherwise an error code. For compatibility the error code differs depending
2146 on whether or not the attribute is "member".
2148 As always, the parsed_dn list is assumed to be sorted.
2150 static int check_parsed_dn_duplicates(struct ldb_module
*module
,
2151 struct ldb_message_element
*el
,
2152 struct parsed_dn
*pdn
)
2155 struct ldb_context
*ldb
= ldb_module_get_ctx(module
);
2157 for (i
= 1; i
< el
->num_values
; i
++) {
2158 struct parsed_dn
*p
= &pdn
[i
];
2159 if (parsed_dn_compare(p
, &pdn
[i
- 1]) == 0) {
2160 ldb_asprintf_errstring(ldb
,
2161 "Linked attribute %s has "
2162 "multiple identical values",
2164 if (ldb_attr_cmp(el
->name
, "member") == 0) {
2165 return LDB_ERR_ENTRY_ALREADY_EXISTS
;
2167 return LDB_ERR_ATTRIBUTE_OR_VALUE_EXISTS
;
2175 build a new extended DN, including all meta data fields
2177 RMD_FLAGS = DSDB_RMD_FLAG_* bits
2178 RMD_ADDTIME = originating_add_time
2179 RMD_INVOCID = originating_invocation_id
2180 RMD_CHANGETIME = originating_change_time
2181 RMD_ORIGINATING_USN = originating_usn
2182 RMD_LOCAL_USN = local_usn
2183 RMD_VERSION = version
2185 static int replmd_build_la_val(TALLOC_CTX
*mem_ctx
, struct ldb_val
*v
,
2186 struct dsdb_dn
*dsdb_dn
,
2187 const struct GUID
*invocation_id
,
2188 uint64_t local_usn
, NTTIME nttime
)
2190 return replmd_set_la_val(mem_ctx
, v
, dsdb_dn
, NULL
, invocation_id
,
2191 local_usn
, local_usn
, nttime
,
2192 RMD_VERSION_INITIAL
, false);
2195 static int replmd_update_la_val(TALLOC_CTX
*mem_ctx
, struct ldb_val
*v
, struct dsdb_dn
*dsdb_dn
,
2196 struct dsdb_dn
*old_dsdb_dn
, const struct GUID
*invocation_id
,
2197 uint64_t seq_num
, uint64_t local_usn
, NTTIME nttime
,
2201 check if any links need upgrading from w2k format
2203 static int replmd_check_upgrade_links(struct ldb_context
*ldb
,
2204 struct parsed_dn
*dns
, uint32_t count
,
2205 struct ldb_message_element
*el
,
2206 const char *ldap_oid
)
2209 const struct GUID
*invocation_id
= NULL
;
2210 for (i
=0; i
<count
; i
++) {
2214 if (dns
[i
].dsdb_dn
== NULL
) {
2215 ret
= really_parse_trusted_dn(dns
, ldb
, &dns
[i
],
2217 if (ret
!= LDB_SUCCESS
) {
2218 return LDB_ERR_INVALID_DN_SYNTAX
;
2222 status
= dsdb_get_extended_dn_uint32(dns
[i
].dsdb_dn
->dn
,
2223 &version
, "RMD_VERSION");
2224 if (!NT_STATUS_EQUAL(status
, NT_STATUS_OBJECT_NAME_NOT_FOUND
)) {
2226 * We optimistically assume they are all the same; if
2227 * the first one is fixed, they are all fixed.
2229 * If the first one was *not* fixed and we find a
2230 * later one that is, that is an occasion to shout
2236 DEBUG(0, ("Mixed w2k and fixed format "
2237 "linked attributes\n"));
2241 if (invocation_id
== NULL
) {
2242 invocation_id
= samdb_ntds_invocation_id(ldb
);
2243 if (invocation_id
== NULL
) {
2244 return LDB_ERR_OPERATIONS_ERROR
;
2249 /* it's an old one that needs upgrading */
2250 ret
= replmd_update_la_val(el
->values
, dns
[i
].v
,
2251 dns
[i
].dsdb_dn
, dns
[i
].dsdb_dn
,
2252 invocation_id
, 1, 1, 0, false);
2253 if (ret
!= LDB_SUCCESS
) {
2259 * This sort() is critical for the operation of
2260 * get_parsed_dns_trusted() because callers of this function
2261 * expect a sorted list, and FL2000 style links are not
2262 * sorted. In particular, as well as the upgrade case,
2263 * get_parsed_dns_trusted() is called from
2264 * replmd_delete_remove_link() even in FL2000 mode
2266 * We do not normally pay the cost of the qsort() due to the
2267 * early return in the RMD_VERSION found case.
2269 TYPESAFE_QSORT(dns
, count
, parsed_dn_compare
);
2274 Sets the value for a linked attribute, including all meta data fields
2276 see replmd_build_la_val for value names
2278 static int replmd_set_la_val(TALLOC_CTX
*mem_ctx
, struct ldb_val
*v
, struct dsdb_dn
*dsdb_dn
,
2279 struct dsdb_dn
*old_dsdb_dn
, const struct GUID
*invocation_id
,
2280 uint64_t usn
, uint64_t local_usn
, NTTIME nttime
,
2281 uint32_t version
, bool deleted
)
2283 struct ldb_dn
*dn
= dsdb_dn
->dn
;
2284 const char *tstring
, *usn_string
, *flags_string
;
2285 struct ldb_val tval
;
2287 struct ldb_val usnv
, local_usnv
;
2288 struct ldb_val vers
, flagsv
;
2289 const struct ldb_val
*old_addtime
= NULL
;
2292 const char *dnstring
;
2294 uint32_t rmd_flags
= deleted
?DSDB_RMD_FLAG_DELETED
:0;
2296 tstring
= talloc_asprintf(mem_ctx
, "%llu", (unsigned long long)nttime
);
2298 return LDB_ERR_OPERATIONS_ERROR
;
2300 tval
= data_blob_string_const(tstring
);
2302 usn_string
= talloc_asprintf(mem_ctx
, "%llu", (unsigned long long)usn
);
2304 return LDB_ERR_OPERATIONS_ERROR
;
2306 usnv
= data_blob_string_const(usn_string
);
2308 usn_string
= talloc_asprintf(mem_ctx
, "%llu", (unsigned long long)local_usn
);
2310 return LDB_ERR_OPERATIONS_ERROR
;
2312 local_usnv
= data_blob_string_const(usn_string
);
2314 status
= GUID_to_ndr_blob(invocation_id
, dn
, &iid
);
2315 if (!NT_STATUS_IS_OK(status
)) {
2316 return LDB_ERR_OPERATIONS_ERROR
;
2319 flags_string
= talloc_asprintf(mem_ctx
, "%u", rmd_flags
);
2320 if (!flags_string
) {
2321 return LDB_ERR_OPERATIONS_ERROR
;
2323 flagsv
= data_blob_string_const(flags_string
);
2325 ret
= ldb_dn_set_extended_component(dn
, "RMD_FLAGS", &flagsv
);
2326 if (ret
!= LDB_SUCCESS
) return ret
;
2328 /* get the ADDTIME from the original */
2329 if (old_dsdb_dn
!= NULL
) {
2330 old_addtime
= ldb_dn_get_extended_component(old_dsdb_dn
->dn
,
2333 if (old_addtime
== NULL
) {
2334 old_addtime
= &tval
;
2336 if (dsdb_dn
!= old_dsdb_dn
||
2337 ldb_dn_get_extended_component(dn
, "RMD_ADDTIME") == NULL
) {
2338 ret
= ldb_dn_set_extended_component(dn
, "RMD_ADDTIME", old_addtime
);
2339 if (ret
!= LDB_SUCCESS
) return ret
;
2342 /* use our invocation id */
2343 ret
= ldb_dn_set_extended_component(dn
, "RMD_INVOCID", &iid
);
2344 if (ret
!= LDB_SUCCESS
) return ret
;
2346 /* changetime is the current time */
2347 ret
= ldb_dn_set_extended_component(dn
, "RMD_CHANGETIME", &tval
);
2348 if (ret
!= LDB_SUCCESS
) return ret
;
2350 /* update the USN */
2351 ret
= ldb_dn_set_extended_component(dn
, "RMD_ORIGINATING_USN", &usnv
);
2352 if (ret
!= LDB_SUCCESS
) return ret
;
2354 ret
= ldb_dn_set_extended_component(dn
, "RMD_LOCAL_USN", &local_usnv
);
2355 if (ret
!= LDB_SUCCESS
) return ret
;
2357 vstring
= talloc_asprintf(mem_ctx
, "%lu", (unsigned long)version
);
2358 vers
= data_blob_string_const(vstring
);
2359 ret
= ldb_dn_set_extended_component(dn
, "RMD_VERSION", &vers
);
2360 if (ret
!= LDB_SUCCESS
) return ret
;
2362 dnstring
= dsdb_dn_get_extended_linearized(mem_ctx
, dsdb_dn
, 1);
2363 if (dnstring
== NULL
) {
2364 return LDB_ERR_OPERATIONS_ERROR
;
2366 *v
= data_blob_string_const(dnstring
);
2372 * Updates the value for a linked attribute, including all meta data fields
2374 static int replmd_update_la_val(TALLOC_CTX
*mem_ctx
, struct ldb_val
*v
, struct dsdb_dn
*dsdb_dn
,
2375 struct dsdb_dn
*old_dsdb_dn
, const struct GUID
*invocation_id
,
2376 uint64_t usn
, uint64_t local_usn
, NTTIME nttime
,
2379 uint32_t old_version
;
2380 uint32_t version
= RMD_VERSION_INITIAL
;
2384 * We're updating the linked attribute locally, so increase the version
2385 * by 1 so that other DCs will see the change when it gets replicated out
2387 status
= dsdb_get_extended_dn_uint32(old_dsdb_dn
->dn
, &old_version
,
2390 if (NT_STATUS_IS_OK(status
)) {
2391 version
= old_version
+ 1;
2394 return replmd_set_la_val(mem_ctx
, v
, dsdb_dn
, old_dsdb_dn
, invocation_id
,
2395 usn
, local_usn
, nttime
, version
, deleted
);
2399 handle adding a linked attribute
2401 static int replmd_modify_la_add(struct ldb_module
*module
,
2402 struct replmd_private
*replmd_private
,
2403 struct replmd_replicated_request
*ac
,
2404 struct ldb_message
*msg
,
2405 struct ldb_message_element
*el
,
2406 struct ldb_message_element
*old_el
,
2407 const struct dsdb_attribute
*schema_attr
,
2409 struct ldb_dn
*msg_dn
,
2410 struct ldb_request
*parent
)
2413 struct parsed_dn
*dns
, *old_dns
;
2414 TALLOC_CTX
*tmp_ctx
= talloc_new(msg
);
2416 struct ldb_val
*new_values
= NULL
;
2417 unsigned old_num_values
= old_el
? old_el
->num_values
: 0;
2418 unsigned num_values
= 0;
2419 unsigned max_num_values
;
2420 struct ldb_context
*ldb
= ldb_module_get_ctx(module
);
2422 unix_to_nt_time(&now
, t
);
2424 /* get the DNs to be added, fully parsed.
2426 * We need full parsing because they came off the wire and we don't
2427 * trust them, besides which we need their details to know where to put
2430 ret
= get_parsed_dns(module
, tmp_ctx
, el
, &dns
,
2431 schema_attr
->syntax
->ldap_oid
, parent
);
2432 if (ret
!= LDB_SUCCESS
) {
2433 talloc_free(tmp_ctx
);
2437 /* get the existing DNs, lazily parsed */
2438 ret
= get_parsed_dns_trusted(module
, replmd_private
,
2439 tmp_ctx
, old_el
, &old_dns
,
2440 schema_attr
->syntax
->ldap_oid
, parent
);
2442 if (ret
!= LDB_SUCCESS
) {
2443 talloc_free(tmp_ctx
);
2447 max_num_values
= old_num_values
+ el
->num_values
;
2448 if (max_num_values
< old_num_values
) {
2449 DEBUG(0, ("we seem to have overflow in replmd_modify_la_add. "
2450 "old values: %u, new values: %u, sum: %u\n",
2451 old_num_values
, el
->num_values
, max_num_values
));
2452 talloc_free(tmp_ctx
);
2453 return LDB_ERR_OPERATIONS_ERROR
;
2456 new_values
= talloc_zero_array(tmp_ctx
, struct ldb_val
, max_num_values
);
2458 if (new_values
== NULL
) {
2459 ldb_module_oom(module
);
2460 talloc_free(tmp_ctx
);
2461 return LDB_ERR_OPERATIONS_ERROR
;
2465 * For each new value, find where it would go in the list. If there is
2466 * a matching GUID there, we update the existing value; otherwise we
2470 for (i
= 0; i
< el
->num_values
; i
++) {
2471 struct parsed_dn
*exact
;
2472 struct parsed_dn
*next
;
2474 int err
= parsed_dn_find(ldb
, old_dns
, old_num_values
,
2477 dns
[i
].dsdb_dn
->extra_part
, 0,
2479 schema_attr
->syntax
->ldap_oid
,
2481 if (err
!= LDB_SUCCESS
) {
2482 talloc_free(tmp_ctx
);
2486 if (ac
->fix_link_sid
) {
2487 char *fixed_dnstring
= NULL
;
2488 struct dom_sid tmp_sid
= { 0, };
2489 DATA_BLOB sid_blob
= data_blob_null
;
2490 enum ndr_err_code ndr_err
;
2494 if (exact
== NULL
) {
2495 talloc_free(tmp_ctx
);
2496 return ldb_operr(ldb
);
2499 if (dns
[i
].dsdb_dn
->dn_format
!= DSDB_NORMAL_DN
) {
2500 talloc_free(tmp_ctx
);
2501 return ldb_operr(ldb
);
2505 * Only "<GUID=...><SID=...>" is allowed.
2507 * We get the GUID to just to find the old
2508 * value and the SID in order to add it
2509 * to the found value.
2512 num
= ldb_dn_get_comp_num(dns
[i
].dsdb_dn
->dn
);
2514 talloc_free(tmp_ctx
);
2515 return ldb_operr(ldb
);
2518 num
= ldb_dn_get_extended_comp_num(dns
[i
].dsdb_dn
->dn
);
2520 talloc_free(tmp_ctx
);
2521 return ldb_operr(ldb
);
2524 status
= dsdb_get_extended_dn_sid(exact
->dsdb_dn
->dn
,
2526 if (NT_STATUS_EQUAL(status
, NT_STATUS_OBJECT_NAME_NOT_FOUND
)) {
2527 /* this is what we expect */
2528 } else if (NT_STATUS_IS_OK(status
)) {
2529 struct GUID_txt_buf guid_str
;
2530 ldb_debug_set(ldb
, LDB_DEBUG_FATAL
,
2531 "i[%u] SID NOT MISSING... Attribute %s already "
2532 "exists for target GUID %s, SID %s, DN: %s",
2534 GUID_buf_string(&exact
->guid
,
2536 dom_sid_string(tmp_ctx
, &tmp_sid
),
2537 dsdb_dn_get_extended_linearized(tmp_ctx
,
2538 exact
->dsdb_dn
, 1));
2539 talloc_free(tmp_ctx
);
2540 return LDB_ERR_ATTRIBUTE_OR_VALUE_EXISTS
;
2542 talloc_free(tmp_ctx
);
2543 return ldb_operr(ldb
);
2546 status
= dsdb_get_extended_dn_sid(dns
[i
].dsdb_dn
->dn
,
2548 if (!NT_STATUS_IS_OK(status
)) {
2549 struct GUID_txt_buf guid_str
;
2550 ldb_asprintf_errstring(ldb
,
2551 "NO SID PROVIDED... Attribute %s already "
2552 "exists for target GUID %s",
2554 GUID_buf_string(&exact
->guid
,
2556 talloc_free(tmp_ctx
);
2557 return LDB_ERR_ATTRIBUTE_OR_VALUE_EXISTS
;
2560 ndr_err
= ndr_push_struct_blob(&sid_blob
, tmp_ctx
, &tmp_sid
,
2561 (ndr_push_flags_fn_t
)ndr_push_dom_sid
);
2562 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err
)) {
2563 talloc_free(tmp_ctx
);
2564 return ldb_operr(ldb
);
2567 ret
= ldb_dn_set_extended_component(exact
->dsdb_dn
->dn
, "SID", &sid_blob
);
2568 data_blob_free(&sid_blob
);
2569 if (ret
!= LDB_SUCCESS
) {
2570 talloc_free(tmp_ctx
);
2574 fixed_dnstring
= dsdb_dn_get_extended_linearized(
2575 new_values
, exact
->dsdb_dn
, 1);
2576 if (fixed_dnstring
== NULL
) {
2577 talloc_free(tmp_ctx
);
2578 return ldb_operr(ldb
);
2582 * We just replace the existing value...
2584 *exact
->v
= data_blob_string_const(fixed_dnstring
);
2589 if (exact
!= NULL
) {
2591 * We are trying to add one that exists, which is only
2592 * allowed if it was previously deleted.
2594 * When we do undelete a link we change it in place.
2595 * It will be copied across into the right spot in due
2599 rmd_flags
= dsdb_dn_rmd_flags(exact
->dsdb_dn
->dn
);
2601 if (!(rmd_flags
& DSDB_RMD_FLAG_DELETED
)) {
2602 struct GUID_txt_buf guid_str
;
2603 ldb_asprintf_errstring(ldb
,
2604 "Attribute %s already "
2605 "exists for target GUID %s",
2607 GUID_buf_string(&exact
->guid
,
2609 talloc_free(tmp_ctx
);
2610 /* error codes for 'member' need to be
2612 if (ldb_attr_cmp(el
->name
, "member") == 0) {
2613 return LDB_ERR_ENTRY_ALREADY_EXISTS
;
2615 return LDB_ERR_ATTRIBUTE_OR_VALUE_EXISTS
;
2619 ret
= replmd_update_la_val(new_values
, exact
->v
,
2622 &ac
->our_invocation_id
,
2623 ac
->seq_num
, ac
->seq_num
,
2625 if (ret
!= LDB_SUCCESS
) {
2626 talloc_free(tmp_ctx
);
2630 ret
= replmd_add_backlink(module
, replmd_private
,
2637 if (ret
!= LDB_SUCCESS
) {
2638 talloc_free(tmp_ctx
);
2644 * Here we don't have an exact match.
2646 * If next is NULL, this one goes beyond the end of the
2647 * existing list, so we need to add all of those ones first.
2649 * If next is not NULL, we need to add all the ones before
2653 offset
= old_num_values
;
2655 /* next should have been parsed, but let's make sure */
2656 if (next
->dsdb_dn
== NULL
) {
2657 ret
= really_parse_trusted_dn(tmp_ctx
, ldb
, next
,
2658 schema_attr
->syntax
->ldap_oid
);
2659 if (ret
!= LDB_SUCCESS
) {
2663 offset
= MIN(next
- old_dns
, old_num_values
);
2666 /* put all the old ones before next on the list */
2667 for (; j
< offset
; j
++) {
2668 new_values
[num_values
] = *old_dns
[j
].v
;
2672 ret
= replmd_add_backlink(module
, replmd_private
,
2677 /* Make the new linked attribute ldb_val. */
2678 ret
= replmd_build_la_val(new_values
, &new_values
[num_values
],
2679 dns
[i
].dsdb_dn
, &ac
->our_invocation_id
,
2681 if (ret
!= LDB_SUCCESS
) {
2682 talloc_free(tmp_ctx
);
2686 if (ret
!= LDB_SUCCESS
) {
2687 talloc_free(tmp_ctx
);
2691 /* copy the rest of the old ones (if any) */
2692 for (; j
< old_num_values
; j
++) {
2693 new_values
[num_values
] = *old_dns
[j
].v
;
2697 talloc_steal(msg
->elements
, new_values
);
2698 if (old_el
!= NULL
) {
2699 talloc_steal(msg
->elements
, old_el
->values
);
2701 el
->values
= new_values
;
2702 el
->num_values
= num_values
;
2704 talloc_free(tmp_ctx
);
2706 /* we now tell the backend to replace all existing values
2707 with the one we have constructed */
2708 el
->flags
= LDB_FLAG_MOD_REPLACE
;
2715 handle deleting all active linked attributes
2717 static int replmd_modify_la_delete(struct ldb_module
*module
,
2718 struct replmd_private
*replmd_private
,
2719 struct replmd_replicated_request
*ac
,
2720 struct ldb_message
*msg
,
2721 struct ldb_message_element
*el
,
2722 struct ldb_message_element
*old_el
,
2723 const struct dsdb_attribute
*schema_attr
,
2725 struct ldb_dn
*msg_dn
,
2726 struct ldb_request
*parent
)
2729 struct parsed_dn
*dns
, *old_dns
;
2730 TALLOC_CTX
*tmp_ctx
= NULL
;
2732 struct ldb_context
*ldb
= ldb_module_get_ctx(module
);
2733 struct ldb_control
*vanish_links_ctrl
= NULL
;
2734 bool vanish_links
= false;
2735 unsigned int num_to_delete
= el
->num_values
;
2739 unix_to_nt_time(&now
, t
);
2741 if (old_el
== NULL
|| old_el
->num_values
== 0) {
2742 /* there is nothing to delete... */
2743 if (num_to_delete
== 0) {
2744 /* and we're deleting nothing, so that's OK */
2747 return LDB_ERR_NO_SUCH_ATTRIBUTE
;
2750 tmp_ctx
= talloc_new(msg
);
2751 if (tmp_ctx
== NULL
) {
2752 return LDB_ERR_OPERATIONS_ERROR
;
2755 ret
= get_parsed_dns(module
, tmp_ctx
, el
, &dns
,
2756 schema_attr
->syntax
->ldap_oid
, parent
);
2757 if (ret
!= LDB_SUCCESS
) {
2758 talloc_free(tmp_ctx
);
2762 ret
= get_parsed_dns_trusted(module
, replmd_private
,
2763 tmp_ctx
, old_el
, &old_dns
,
2764 schema_attr
->syntax
->ldap_oid
, parent
);
2766 if (ret
!= LDB_SUCCESS
) {
2767 talloc_free(tmp_ctx
);
2772 vanish_links_ctrl
= ldb_request_get_control(parent
, DSDB_CONTROL_REPLMD_VANISH_LINKS
);
2773 if (vanish_links_ctrl
) {
2774 vanish_links
= true;
2775 vanish_links_ctrl
->critical
= false;
2779 /* we empty out el->values here to avoid damage if we return early. */
2784 * If vanish links is set, we are actually removing members of
2785 * old_el->values; otherwise we are just marking them deleted.
2787 * There is a special case when no values are given: we remove them
2788 * all. When we have the vanish_links control we just have to remove
2789 * the backlinks and change our element to replace the existing values
2790 * with the empty list.
2793 if (num_to_delete
== 0) {
2794 for (i
= 0; i
< old_el
->num_values
; i
++) {
2795 struct parsed_dn
*p
= &old_dns
[i
];
2796 if (p
->dsdb_dn
== NULL
) {
2797 ret
= really_parse_trusted_dn(tmp_ctx
, ldb
, p
,
2798 schema_attr
->syntax
->ldap_oid
);
2799 if (ret
!= LDB_SUCCESS
) {
2803 ret
= replmd_add_backlink(module
, replmd_private
,
2804 ac
->schema
, msg_dn
, &p
->guid
,
2807 if (ret
!= LDB_SUCCESS
) {
2808 talloc_free(tmp_ctx
);
2815 rmd_flags
= dsdb_dn_rmd_flags(p
->dsdb_dn
->dn
);
2816 if (rmd_flags
& DSDB_RMD_FLAG_DELETED
) {
2820 ret
= replmd_update_la_val(old_el
->values
, p
->v
,
2821 p
->dsdb_dn
, p
->dsdb_dn
,
2822 &ac
->our_invocation_id
,
2823 ac
->seq_num
, ac
->seq_num
,
2825 if (ret
!= LDB_SUCCESS
) {
2826 talloc_free(tmp_ctx
);
2832 el
->flags
= LDB_FLAG_MOD_REPLACE
;
2833 talloc_free(tmp_ctx
);
2839 for (i
= 0; i
< num_to_delete
; i
++) {
2840 struct parsed_dn
*p
= &dns
[i
];
2841 struct parsed_dn
*exact
= NULL
;
2842 struct parsed_dn
*next
= NULL
;
2843 ret
= parsed_dn_find(ldb
, old_dns
, old_el
->num_values
,
2846 p
->dsdb_dn
->extra_part
, 0,
2848 schema_attr
->syntax
->ldap_oid
,
2850 if (ret
!= LDB_SUCCESS
) {
2851 talloc_free(tmp_ctx
);
2854 if (exact
== NULL
) {
2855 struct GUID_txt_buf buf
;
2856 ldb_asprintf_errstring(ldb
, "Attribute %s doesn't "
2857 "exist for target GUID %s",
2859 GUID_buf_string(&p
->guid
, &buf
));
2860 if (ldb_attr_cmp(el
->name
, "member") == 0) {
2861 talloc_free(tmp_ctx
);
2862 return LDB_ERR_UNWILLING_TO_PERFORM
;
2864 talloc_free(tmp_ctx
);
2865 return LDB_ERR_NO_SUCH_ATTRIBUTE
;
2870 if (CHECK_DEBUGLVL(5)) {
2871 rmd_flags
= dsdb_dn_rmd_flags(exact
->dsdb_dn
->dn
);
2872 if ((rmd_flags
& DSDB_RMD_FLAG_DELETED
)) {
2873 struct GUID_txt_buf buf
;
2874 const char *guid_str
= \
2875 GUID_buf_string(&p
->guid
, &buf
);
2876 DEBUG(5, ("Deleting deleted linked "
2877 "attribute %s to %s, because "
2878 "vanish_links control is set\n",
2879 el
->name
, guid_str
));
2883 /* remove the backlink */
2884 ret
= replmd_add_backlink(module
,
2891 if (ret
!= LDB_SUCCESS
) {
2892 talloc_free(tmp_ctx
);
2896 /* We flag the deletion and tidy it up later. */
2901 rmd_flags
= dsdb_dn_rmd_flags(exact
->dsdb_dn
->dn
);
2903 if (rmd_flags
& DSDB_RMD_FLAG_DELETED
) {
2904 struct GUID_txt_buf buf
;
2905 const char *guid_str
= GUID_buf_string(&p
->guid
, &buf
);
2906 ldb_asprintf_errstring(ldb
, "Attribute %s already "
2907 "deleted for target GUID %s",
2908 el
->name
, guid_str
);
2909 if (ldb_attr_cmp(el
->name
, "member") == 0) {
2910 talloc_free(tmp_ctx
);
2911 return LDB_ERR_UNWILLING_TO_PERFORM
;
2913 talloc_free(tmp_ctx
);
2914 return LDB_ERR_NO_SUCH_ATTRIBUTE
;
2918 ret
= replmd_update_la_val(old_el
->values
, exact
->v
,
2919 exact
->dsdb_dn
, exact
->dsdb_dn
,
2920 &ac
->our_invocation_id
,
2921 ac
->seq_num
, ac
->seq_num
,
2923 if (ret
!= LDB_SUCCESS
) {
2924 talloc_free(tmp_ctx
);
2927 ret
= replmd_add_backlink(module
, replmd_private
,
2932 if (ret
!= LDB_SUCCESS
) {
2933 talloc_free(tmp_ctx
);
2940 struct ldb_val
*tmp_vals
= NULL
;
2942 tmp_vals
= talloc_array(tmp_ctx
, struct ldb_val
,
2943 old_el
->num_values
);
2944 if (tmp_vals
== NULL
) {
2945 talloc_free(tmp_ctx
);
2946 return ldb_module_oom(module
);
2948 for (i
= 0; i
< old_el
->num_values
; i
++) {
2949 if (old_dns
[i
].v
== NULL
) {
2952 tmp_vals
[j
] = *old_dns
[i
].v
;
2955 for (i
= 0; i
< j
; i
++) {
2956 old_el
->values
[i
] = tmp_vals
[i
];
2958 old_el
->num_values
= j
;
2961 el
->values
= talloc_steal(msg
->elements
, old_el
->values
);
2962 el
->num_values
= old_el
->num_values
;
2964 talloc_free(tmp_ctx
);
2966 /* we now tell the backend to replace all existing values
2967 with the one we have constructed */
2968 el
->flags
= LDB_FLAG_MOD_REPLACE
;
2974 handle replacing a linked attribute
2976 static int replmd_modify_la_replace(struct ldb_module
*module
,
2977 struct replmd_private
*replmd_private
,
2978 struct replmd_replicated_request
*ac
,
2979 struct ldb_message
*msg
,
2980 struct ldb_message_element
*el
,
2981 struct ldb_message_element
*old_el
,
2982 const struct dsdb_attribute
*schema_attr
,
2984 struct ldb_dn
*msg_dn
,
2985 struct ldb_request
*parent
)
2987 unsigned int i
, old_i
, new_i
;
2988 struct parsed_dn
*dns
, *old_dns
;
2989 TALLOC_CTX
*tmp_ctx
= talloc_new(msg
);
2991 struct ldb_context
*ldb
= ldb_module_get_ctx(module
);
2992 struct ldb_val
*new_values
= NULL
;
2993 const char *ldap_oid
= schema_attr
->syntax
->ldap_oid
;
2994 unsigned int old_num_values
;
2995 unsigned int repl_num_values
;
2996 unsigned int max_num_values
;
2999 unix_to_nt_time(&now
, t
);
3002 * The replace operation is unlike the replace and delete cases in that
3003 * we need to look at every existing link to see whether it is being
3004 * retained or deleted. In other words, we can't avoid parsing the GUIDs.
3006 * As we are trying to combine two sorted lists, the algorithm we use
3007 * is akin to the merge phase of a merge sort. We interleave the two
3008 * lists, doing different things depending on which side the current
3011 * There are three main cases, with some sub-cases.
3013 * - a DN is in the old list but not the new one. It needs to be
3014 * marked as deleted (but left in the list).
3015 * - maybe it is already deleted, and we have less to do.
3017 * - a DN is in both lists. The old data gets replaced by the new,
3018 * and the list doesn't grow. The old link may have been marked as
3019 * deleted, in which case we undelete it.
3021 * - a DN is in the new list only. We add it in the right place.
3024 old_num_values
= old_el
? old_el
->num_values
: 0;
3025 repl_num_values
= el
->num_values
;
3026 max_num_values
= old_num_values
+ repl_num_values
;
3028 if (max_num_values
== 0) {
3029 /* There is nothing to do! */
3033 ret
= get_parsed_dns(module
, tmp_ctx
, el
, &dns
, ldap_oid
, parent
);
3034 if (ret
!= LDB_SUCCESS
) {
3035 talloc_free(tmp_ctx
);
3039 ret
= check_parsed_dn_duplicates(module
, el
, dns
);
3040 if (ret
!= LDB_SUCCESS
) {
3041 talloc_free(tmp_ctx
);
3045 ret
= get_parsed_dns(module
, tmp_ctx
, old_el
, &old_dns
,
3047 if (ret
!= LDB_SUCCESS
) {
3048 talloc_free(tmp_ctx
);
3052 ret
= replmd_check_upgrade_links(ldb
, old_dns
, old_num_values
,
3054 if (ret
!= LDB_SUCCESS
) {
3055 talloc_free(tmp_ctx
);
3059 new_values
= talloc_array(tmp_ctx
, struct ldb_val
, max_num_values
);
3060 if (new_values
== NULL
) {
3061 ldb_module_oom(module
);
3062 talloc_free(tmp_ctx
);
3063 return LDB_ERR_OPERATIONS_ERROR
;
3068 for (i
= 0; i
< max_num_values
; i
++) {
3070 struct parsed_dn
*old_p
, *new_p
;
3071 if (old_i
< old_num_values
&& new_i
< repl_num_values
) {
3072 old_p
= &old_dns
[old_i
];
3073 new_p
= &dns
[new_i
];
3074 cmp
= parsed_dn_compare(old_p
, new_p
);
3075 } else if (old_i
< old_num_values
) {
3076 /* the new list is empty, read the old list */
3077 old_p
= &old_dns
[old_i
];
3080 } else if (new_i
< repl_num_values
) {
3081 /* the old list is empty, read new list */
3083 new_p
= &dns
[new_i
];
3091 * An old ones that come before the next replacement
3092 * (if any). We mark it as deleted and add it to the
3095 uint32_t rmd_flags
= dsdb_dn_rmd_flags(old_p
->dsdb_dn
->dn
);
3096 if ((rmd_flags
& DSDB_RMD_FLAG_DELETED
) == 0) {
3097 ret
= replmd_update_la_val(new_values
, old_p
->v
,
3100 &ac
->our_invocation_id
,
3101 ac
->seq_num
, ac
->seq_num
,
3103 if (ret
!= LDB_SUCCESS
) {
3104 talloc_free(tmp_ctx
);
3108 ret
= replmd_add_backlink(module
, replmd_private
,
3111 &old_p
->guid
, false,
3114 if (ret
!= LDB_SUCCESS
) {
3115 talloc_free(tmp_ctx
);
3119 new_values
[i
] = *old_p
->v
;
3121 } else if (cmp
== 0) {
3123 * We are overwriting one. If it was previously
3124 * deleted, we need to add a backlink.
3126 * Note that if any RMD_FLAGs in an extended new DN
3131 ret
= replmd_update_la_val(new_values
, old_p
->v
,
3134 &ac
->our_invocation_id
,
3135 ac
->seq_num
, ac
->seq_num
,
3137 if (ret
!= LDB_SUCCESS
) {
3138 talloc_free(tmp_ctx
);
3142 rmd_flags
= dsdb_dn_rmd_flags(old_p
->dsdb_dn
->dn
);
3143 if ((rmd_flags
& DSDB_RMD_FLAG_DELETED
) != 0) {
3144 ret
= replmd_add_backlink(module
, replmd_private
,
3150 if (ret
!= LDB_SUCCESS
) {
3151 talloc_free(tmp_ctx
);
3156 new_values
[i
] = *old_p
->v
;
3161 * Replacements that don't match an existing one. We
3162 * just add them to the final list.
3164 ret
= replmd_build_la_val(new_values
,
3167 &ac
->our_invocation_id
,
3169 if (ret
!= LDB_SUCCESS
) {
3170 talloc_free(tmp_ctx
);
3173 ret
= replmd_add_backlink(module
, replmd_private
,
3179 if (ret
!= LDB_SUCCESS
) {
3180 talloc_free(tmp_ctx
);
3183 new_values
[i
] = *new_p
->v
;
3187 if (old_el
!= NULL
) {
3188 talloc_steal(msg
->elements
, old_el
->values
);
3190 el
->values
= talloc_steal(msg
->elements
, new_values
);
3192 talloc_free(tmp_ctx
);
3194 el
->flags
= LDB_FLAG_MOD_REPLACE
;
3201 handle linked attributes in modify requests
3203 static int replmd_modify_handle_linked_attribs(struct ldb_module
*module
,
3204 struct replmd_private
*replmd_private
,
3205 struct replmd_replicated_request
*ac
,
3206 struct ldb_message
*msg
,
3208 struct ldb_request
*parent
)
3210 struct ldb_result
*res
;
3213 struct ldb_context
*ldb
= ldb_module_get_ctx(module
);
3214 struct ldb_message
*old_msg
;
3216 if (dsdb_functional_level(ldb
) == DS_DOMAIN_FUNCTION_2000
) {
3218 * Nothing special is required for modifying or vanishing links
3219 * in fl2000 since they are just strings in a multi-valued
3222 struct ldb_control
*ctrl
= ldb_request_get_control(parent
,
3223 DSDB_CONTROL_REPLMD_VANISH_LINKS
);
3225 ctrl
->critical
= false;
3233 * We should restrict this to the intersection of the list of
3234 * linked attributes in the schema and the list of attributes
3237 * This will help performance a little, as otherwise we have
3238 * to allocate the entire object value-by-value.
3240 ret
= dsdb_module_search_dn(module
, msg
, &res
, msg
->dn
, NULL
,
3241 DSDB_FLAG_NEXT_MODULE
|
3242 DSDB_SEARCH_SHOW_RECYCLED
|
3243 DSDB_SEARCH_REVEAL_INTERNALS
|
3244 DSDB_SEARCH_SHOW_DN_IN_STORAGE_FORMAT
,
3246 if (ret
!= LDB_SUCCESS
) {
3250 old_msg
= res
->msgs
[0];
3252 for (i
=0; i
<msg
->num_elements
; i
++) {
3253 struct ldb_message_element
*el
= &msg
->elements
[i
];
3254 struct ldb_message_element
*old_el
, *new_el
;
3255 unsigned int mod_type
= LDB_FLAG_MOD_TYPE(el
->flags
);
3256 const struct dsdb_attribute
*schema_attr
3257 = dsdb_attribute_by_lDAPDisplayName(ac
->schema
, el
->name
);
3259 ldb_asprintf_errstring(ldb
,
3260 "%s: attribute %s is not a valid attribute in schema",
3261 __FUNCTION__
, el
->name
);
3262 return LDB_ERR_OBJECT_CLASS_VIOLATION
;
3264 if (schema_attr
->linkID
== 0) {
3267 if ((schema_attr
->linkID
& 1) == 1) {
3269 struct ldb_control
*ctrl
;
3271 ctrl
= ldb_request_get_control(parent
,
3272 DSDB_CONTROL_REPLMD_VANISH_LINKS
);
3274 ctrl
->critical
= false;
3277 ctrl
= ldb_request_get_control(parent
,
3278 DSDB_CONTROL_DBCHECK
);
3284 /* Odd is for the target. Illegal to modify */
3285 ldb_asprintf_errstring(ldb
,
3286 "attribute %s must not be modified directly, it is a linked attribute", el
->name
);
3287 return LDB_ERR_UNWILLING_TO_PERFORM
;
3289 old_el
= ldb_msg_find_element(old_msg
, el
->name
);
3291 case LDB_FLAG_MOD_REPLACE
:
3292 ret
= replmd_modify_la_replace(module
, replmd_private
,
3293 ac
, msg
, el
, old_el
,
3298 case LDB_FLAG_MOD_DELETE
:
3299 ret
= replmd_modify_la_delete(module
, replmd_private
,
3300 ac
, msg
, el
, old_el
,
3305 case LDB_FLAG_MOD_ADD
:
3306 ret
= replmd_modify_la_add(module
, replmd_private
,
3307 ac
, msg
, el
, old_el
,
3313 ldb_asprintf_errstring(ldb
,
3314 "invalid flags 0x%x for %s linked attribute",
3315 el
->flags
, el
->name
);
3316 return LDB_ERR_UNWILLING_TO_PERFORM
;
3318 if (dsdb_check_single_valued_link(schema_attr
, el
) != LDB_SUCCESS
) {
3319 ldb_asprintf_errstring(ldb
,
3320 "Attribute %s is single valued but more than one value has been supplied",
3322 /* Return codes as found on Windows 2012r2 */
3323 if (mod_type
== LDB_FLAG_MOD_REPLACE
) {
3324 return LDB_ERR_CONSTRAINT_VIOLATION
;
3326 return LDB_ERR_ATTRIBUTE_OR_VALUE_EXISTS
;
3329 el
->flags
|= LDB_FLAG_INTERNAL_DISABLE_SINGLE_VALUE_CHECK
;
3332 if (ret
!= LDB_SUCCESS
) {
3336 ldb_msg_remove_attr(old_msg
, el
->name
);
3338 ldb_msg_add_empty(old_msg
, el
->name
, 0, &new_el
);
3339 new_el
->num_values
= el
->num_values
;
3340 new_el
->values
= talloc_steal(msg
->elements
, el
->values
);
3342 /* TODO: this relises a bit too heavily on the exact
3343 behaviour of ldb_msg_find_element and
3344 ldb_msg_remove_element */
3345 old_el
= ldb_msg_find_element(msg
, el
->name
);
3347 ldb_msg_remove_element(msg
, old_el
);
3357 static int send_rodc_referral(struct ldb_request
*req
,
3358 struct ldb_context
*ldb
,
3361 char *referral
= NULL
;
3362 struct loadparm_context
*lp_ctx
= NULL
;
3363 struct ldb_dn
*fsmo_role_dn
= NULL
;
3364 struct ldb_dn
*role_owner_dn
= NULL
;
3365 const char *domain
= NULL
;
3368 lp_ctx
= talloc_get_type(ldb_get_opaque(ldb
, "loadparm"),
3369 struct loadparm_context
);
3371 werr
= dsdb_get_fsmo_role_info(req
, ldb
, DREPL_PDC_MASTER
,
3372 &fsmo_role_dn
, &role_owner_dn
);
3374 if (W_ERROR_IS_OK(werr
)) {
3375 struct ldb_dn
*server_dn
= ldb_dn_copy(req
, role_owner_dn
);
3376 if (server_dn
!= NULL
) {
3377 ldb_dn_remove_child_components(server_dn
, 1);
3378 domain
= samdb_dn_to_dnshostname(ldb
, req
,
3383 if (domain
== NULL
) {
3384 domain
= lpcfg_dnsdomain(lp_ctx
);
3387 referral
= talloc_asprintf(req
, "ldap://%s/%s",
3389 ldb_dn_get_linearized(dn
));
3390 if (referral
== NULL
) {
3392 return LDB_ERR_OPERATIONS_ERROR
;
3395 return ldb_module_send_referral(req
, referral
);
3399 static int replmd_modify(struct ldb_module
*module
, struct ldb_request
*req
)
3401 struct ldb_context
*ldb
;
3402 struct replmd_replicated_request
*ac
;
3403 struct ldb_request
*down_req
;
3404 struct ldb_message
*msg
;
3405 time_t t
= time(NULL
);
3407 bool is_urgent
= false, rodc
= false;
3408 bool is_schema_nc
= false;
3409 unsigned int functional_level
;
3410 const struct ldb_message_element
*guid_el
= NULL
;
3411 struct ldb_control
*sd_propagation_control
;
3412 struct ldb_control
*fix_links_control
= NULL
;
3413 struct ldb_control
*fix_dn_name_control
= NULL
;
3414 struct ldb_control
*fix_dn_sid_control
= NULL
;
3415 struct replmd_private
*replmd_private
=
3416 talloc_get_type(ldb_module_get_private(module
), struct replmd_private
);
3418 /* do not manipulate our control entries */
3419 if (ldb_dn_is_special(req
->op
.mod
.message
->dn
)) {
3420 return ldb_next_request(module
, req
);
3423 sd_propagation_control
= ldb_request_get_control(req
,
3424 DSDB_CONTROL_SEC_DESC_PROPAGATION_OID
);
3425 if (sd_propagation_control
!= NULL
) {
3426 if (req
->op
.mod
.message
->num_elements
!= 1) {
3427 return ldb_module_operr(module
);
3429 ret
= strcmp(req
->op
.mod
.message
->elements
[0].name
,
3430 "nTSecurityDescriptor");
3432 return ldb_module_operr(module
);
3435 return ldb_next_request(module
, req
);
3438 ldb
= ldb_module_get_ctx(module
);
3440 fix_links_control
= ldb_request_get_control(req
,
3441 DSDB_CONTROL_DBCHECK_FIX_DUPLICATE_LINKS
);
3442 if (fix_links_control
!= NULL
) {
3443 struct dsdb_schema
*schema
= NULL
;
3444 const struct dsdb_attribute
*sa
= NULL
;
3446 if (req
->op
.mod
.message
->num_elements
!= 1) {
3447 return ldb_module_operr(module
);
3450 if (req
->op
.mod
.message
->elements
[0].flags
!= LDB_FLAG_MOD_REPLACE
) {
3451 return ldb_module_operr(module
);
3454 schema
= dsdb_get_schema(ldb
, req
);
3455 if (schema
== NULL
) {
3456 return ldb_module_operr(module
);
3459 sa
= dsdb_attribute_by_lDAPDisplayName(schema
,
3460 req
->op
.mod
.message
->elements
[0].name
);
3462 return ldb_module_operr(module
);
3465 if (sa
->linkID
== 0) {
3466 return ldb_module_operr(module
);
3469 fix_links_control
->critical
= false;
3470 return ldb_next_request(module
, req
);
3473 fix_dn_name_control
= ldb_request_get_control(req
,
3474 DSDB_CONTROL_DBCHECK_FIX_LINK_DN_NAME
);
3475 if (fix_dn_name_control
!= NULL
) {
3476 struct dsdb_schema
*schema
= NULL
;
3477 const struct dsdb_attribute
*sa
= NULL
;
3479 if (req
->op
.mod
.message
->num_elements
!= 2) {
3480 return ldb_module_operr(module
);
3483 if (req
->op
.mod
.message
->elements
[0].flags
!= LDB_FLAG_MOD_DELETE
) {
3484 return ldb_module_operr(module
);
3487 if (req
->op
.mod
.message
->elements
[1].flags
!= LDB_FLAG_MOD_ADD
) {
3488 return ldb_module_operr(module
);
3491 if (req
->op
.mod
.message
->elements
[0].num_values
!= 1) {
3492 return ldb_module_operr(module
);
3495 if (req
->op
.mod
.message
->elements
[1].num_values
!= 1) {
3496 return ldb_module_operr(module
);
3499 schema
= dsdb_get_schema(ldb
, req
);
3500 if (schema
== NULL
) {
3501 return ldb_module_operr(module
);
3504 if (ldb_attr_cmp(req
->op
.mod
.message
->elements
[0].name
,
3505 req
->op
.mod
.message
->elements
[1].name
) != 0) {
3506 return ldb_module_operr(module
);
3509 sa
= dsdb_attribute_by_lDAPDisplayName(schema
,
3510 req
->op
.mod
.message
->elements
[0].name
);
3512 return ldb_module_operr(module
);
3515 if (sa
->dn_format
== DSDB_INVALID_DN
) {
3516 return ldb_module_operr(module
);
3519 if (sa
->linkID
!= 0) {
3520 return ldb_module_operr(module
);
3524 * If we are run from dbcheck and we are not updating
3525 * a link (as these would need to be sorted and so
3526 * can't go via such a simple update, then do not
3527 * trigger replicated updates and a new USN from this
3528 * change, it wasn't a real change, just a new
3529 * (correct) string DN
3532 fix_dn_name_control
->critical
= false;
3533 return ldb_next_request(module
, req
);
3536 ldb_debug(ldb
, LDB_DEBUG_TRACE
, "replmd_modify\n");
3538 guid_el
= ldb_msg_find_element(req
->op
.mod
.message
, "objectGUID");
3539 if (guid_el
!= NULL
) {
3540 ldb_set_errstring(ldb
,
3541 "replmd_modify: it's not allowed to change the objectGUID!");
3542 return LDB_ERR_CONSTRAINT_VIOLATION
;
3545 ac
= replmd_ctx_init(module
, req
);
3547 return ldb_module_oom(module
);
3550 functional_level
= dsdb_functional_level(ldb
);
3552 /* we have to copy the message as the caller might have it as a const */
3553 msg
= ldb_msg_copy_shallow(ac
, req
->op
.mod
.message
);
3557 return LDB_ERR_OPERATIONS_ERROR
;
3560 fix_dn_sid_control
= ldb_request_get_control(req
,
3561 DSDB_CONTROL_DBCHECK_FIX_LINK_DN_SID
);
3562 if (fix_dn_sid_control
!= NULL
) {
3563 const struct dsdb_attribute
*sa
= NULL
;
3565 if (msg
->num_elements
!= 1) {
3567 return ldb_module_operr(module
);
3570 if (msg
->elements
[0].flags
!= LDB_FLAG_MOD_ADD
) {
3572 return ldb_module_operr(module
);
3575 if (msg
->elements
[0].num_values
!= 1) {
3577 return ldb_module_operr(module
);
3580 sa
= dsdb_attribute_by_lDAPDisplayName(ac
->schema
,
3581 msg
->elements
[0].name
);
3584 return ldb_module_operr(module
);
3587 if (sa
->dn_format
!= DSDB_NORMAL_DN
) {
3589 return ldb_module_operr(module
);
3592 fix_dn_sid_control
->critical
= false;
3593 ac
->fix_link_sid
= true;
3595 goto handle_linked_attribs
;
3598 ldb_msg_remove_attr(msg
, "whenChanged");
3599 ldb_msg_remove_attr(msg
, "uSNChanged");
3601 is_schema_nc
= ldb_dn_compare_base(replmd_private
->schema_dn
, msg
->dn
) == 0;
3603 ret
= replmd_update_rpmd(module
, ac
->schema
, req
, NULL
,
3604 msg
, &ac
->seq_num
, t
, is_schema_nc
,
3606 if (rodc
&& (ret
== LDB_ERR_REFERRAL
)) {
3607 ret
= send_rodc_referral(req
, ldb
, msg
->dn
);
3613 if (ret
!= LDB_SUCCESS
) {
3618 handle_linked_attribs
:
3619 ret
= replmd_modify_handle_linked_attribs(module
, replmd_private
,
3621 if (ret
!= LDB_SUCCESS
) {
3627 * - replace the old object with the newly constructed one
3630 ac
->is_urgent
= is_urgent
;
3632 ret
= ldb_build_mod_req(&down_req
, ldb
, ac
,
3635 ac
, replmd_op_callback
,
3637 LDB_REQ_SET_LOCATION(down_req
);
3638 if (ret
!= LDB_SUCCESS
) {
3643 /* current partition control is needed by "replmd_op_callback" */
3644 if (ldb_request_get_control(req
, DSDB_CONTROL_CURRENT_PARTITION_OID
) == NULL
) {
3645 ret
= ldb_request_add_control(down_req
,
3646 DSDB_CONTROL_CURRENT_PARTITION_OID
,
3648 if (ret
!= LDB_SUCCESS
) {
3654 /* If we are in functional level 2000, then
3655 * replmd_modify_handle_linked_attribs will have done
3657 if (functional_level
== DS_DOMAIN_FUNCTION_2000
) {
3658 ret
= ldb_request_add_control(down_req
, DSDB_CONTROL_APPLY_LINKS
, false, NULL
);
3659 if (ret
!= LDB_SUCCESS
) {
3665 talloc_steal(down_req
, msg
);
3667 /* we only change whenChanged and uSNChanged if the seq_num
3669 if (ac
->seq_num
!= 0) {
3670 ret
= add_time_element(msg
, "whenChanged", t
);
3671 if (ret
!= LDB_SUCCESS
) {
3677 ret
= add_uint64_element(ldb
, msg
, "uSNChanged", ac
->seq_num
);
3678 if (ret
!= LDB_SUCCESS
) {
3685 /* go on with the call chain */
3686 return ldb_next_request(module
, down_req
);
3689 static int replmd_rename_callback(struct ldb_request
*req
, struct ldb_reply
*ares
);
3692 handle a rename request
3694 On a rename we need to do an extra ldb_modify which sets the
3695 whenChanged and uSNChanged attributes. We do this in a callback after the success.
3697 static int replmd_rename(struct ldb_module
*module
, struct ldb_request
*req
)
3699 struct ldb_context
*ldb
;
3700 struct replmd_replicated_request
*ac
;
3702 struct ldb_request
*down_req
;
3704 /* do not manipulate our control entries */
3705 if (ldb_dn_is_special(req
->op
.mod
.message
->dn
)) {
3706 return ldb_next_request(module
, req
);
3709 ldb
= ldb_module_get_ctx(module
);
3711 ldb_debug(ldb
, LDB_DEBUG_TRACE
, "replmd_rename\n");
3713 ac
= replmd_ctx_init(module
, req
);
3715 return ldb_module_oom(module
);
3718 ret
= ldb_build_rename_req(&down_req
, ldb
, ac
,
3719 ac
->req
->op
.rename
.olddn
,
3720 ac
->req
->op
.rename
.newdn
,
3722 ac
, replmd_rename_callback
,
3724 LDB_REQ_SET_LOCATION(down_req
);
3725 if (ret
!= LDB_SUCCESS
) {
3730 /* go on with the call chain */
3731 return ldb_next_request(module
, down_req
);
3734 /* After the rename is compleated, update the whenchanged etc */
3735 static int replmd_rename_callback(struct ldb_request
*req
, struct ldb_reply
*ares
)
3737 struct ldb_context
*ldb
;
3738 struct ldb_request
*down_req
;
3739 struct ldb_message
*msg
;
3740 const struct dsdb_attribute
*rdn_attr
;
3741 const char *rdn_name
;
3742 const struct ldb_val
*rdn_val
;
3743 const char *attrs
[5] = { NULL
, };
3744 time_t t
= time(NULL
);
3746 bool is_urgent
= false, rodc
= false;
3748 struct replmd_replicated_request
*ac
=
3749 talloc_get_type(req
->context
, struct replmd_replicated_request
);
3750 struct replmd_private
*replmd_private
=
3751 talloc_get_type(ldb_module_get_private(ac
->module
),
3752 struct replmd_private
);
3754 ldb
= ldb_module_get_ctx(ac
->module
);
3756 if (ares
->error
!= LDB_SUCCESS
) {
3757 return ldb_module_done(ac
->req
, ares
->controls
,
3758 ares
->response
, ares
->error
);
3761 if (ares
->type
!= LDB_REPLY_DONE
) {
3762 ldb_set_errstring(ldb
,
3763 "invalid ldb_reply_type in callback");
3765 return ldb_module_done(ac
->req
, NULL
, NULL
,
3766 LDB_ERR_OPERATIONS_ERROR
);
3770 * - replace the old object with the newly constructed one
3773 msg
= ldb_msg_new(ac
);
3776 return LDB_ERR_OPERATIONS_ERROR
;
3779 msg
->dn
= ac
->req
->op
.rename
.newdn
;
3781 is_schema_nc
= ldb_dn_compare_base(replmd_private
->schema_dn
, msg
->dn
) == 0;
3783 rdn_name
= ldb_dn_get_rdn_name(msg
->dn
);
3784 if (rdn_name
== NULL
) {
3786 return ldb_module_done(ac
->req
, NULL
, NULL
,
3790 /* normalize the rdn attribute name */
3791 rdn_attr
= dsdb_attribute_by_lDAPDisplayName(ac
->schema
, rdn_name
);
3792 if (rdn_attr
== NULL
) {
3794 return ldb_module_done(ac
->req
, NULL
, NULL
,
3797 rdn_name
= rdn_attr
->lDAPDisplayName
;
3799 rdn_val
= ldb_dn_get_rdn_val(msg
->dn
);
3800 if (rdn_val
== NULL
) {
3802 return ldb_module_done(ac
->req
, NULL
, NULL
,
3806 if (ldb_msg_add_empty(msg
, rdn_name
, LDB_FLAG_MOD_REPLACE
, NULL
) != 0) {
3808 return ldb_module_done(ac
->req
, NULL
, NULL
,
3811 if (ldb_msg_add_value(msg
, rdn_name
, rdn_val
, NULL
) != 0) {
3813 return ldb_module_done(ac
->req
, NULL
, NULL
,
3816 if (ldb_msg_add_empty(msg
, "name", LDB_FLAG_MOD_REPLACE
, NULL
) != 0) {
3818 return ldb_module_done(ac
->req
, NULL
, NULL
,
3821 if (ldb_msg_add_value(msg
, "name", rdn_val
, NULL
) != 0) {
3823 return ldb_module_done(ac
->req
, NULL
, NULL
,
3828 * here we let replmd_update_rpmd() only search for
3829 * the existing "replPropertyMetaData" and rdn_name attributes.
3831 * We do not want the existing "name" attribute as
3832 * the "name" attribute needs to get the version
3833 * updated on rename even if the rdn value hasn't changed.
3835 * This is the diff of the meta data, for a moved user
3836 * on a w2k8r2 server:
3839 * -dn: CN=sdf df,CN=Users,DC=bla,DC=base
3840 * +dn: CN=sdf df,OU=TestOU,DC=bla,DC=base
3841 * replPropertyMetaData: NDR: struct replPropertyMetaDataBlob
3842 * version : 0x00000001 (1)
3843 * reserved : 0x00000000 (0)
3844 * @@ -66,11 +66,11 @@ replPropertyMetaData: NDR: struct re
3845 * local_usn : 0x00000000000037a5 (14245)
3846 * array: struct replPropertyMetaData1
3847 * attid : DRSUAPI_ATTID_name (0x90001)
3848 * - version : 0x00000001 (1)
3849 * - originating_change_time : Wed Feb 9 17:20:49 2011 CET
3850 * + version : 0x00000002 (2)
3851 * + originating_change_time : Wed Apr 6 15:21:01 2011 CEST
3852 * originating_invocation_id: 0d36ca05-5507-4e62-aca3-354bab0d39e1
3853 * - originating_usn : 0x00000000000037a5 (14245)
3854 * - local_usn : 0x00000000000037a5 (14245)
3855 * + originating_usn : 0x0000000000003834 (14388)
3856 * + local_usn : 0x0000000000003834 (14388)
3857 * array: struct replPropertyMetaData1
3858 * attid : DRSUAPI_ATTID_userAccountControl (0x90008)
3859 * version : 0x00000004 (4)
3861 attrs
[0] = "replPropertyMetaData";
3862 attrs
[1] = "objectClass";
3863 attrs
[2] = "instanceType";
3864 attrs
[3] = rdn_name
;
3867 ret
= replmd_update_rpmd(ac
->module
, ac
->schema
, req
, attrs
,
3868 msg
, &ac
->seq_num
, t
,
3869 is_schema_nc
, &is_urgent
, &rodc
);
3870 if (rodc
&& (ret
== LDB_ERR_REFERRAL
)) {
3871 ret
= send_rodc_referral(req
, ldb
, ac
->req
->op
.rename
.olddn
);
3873 return ldb_module_done(req
, NULL
, NULL
, ret
);
3876 if (ret
!= LDB_SUCCESS
) {
3878 return ldb_module_done(ac
->req
, NULL
, NULL
, ret
);
3881 if (ac
->seq_num
== 0) {
3883 return ldb_module_done(ac
->req
, NULL
, NULL
,
3885 "internal error seq_num == 0"));
3887 ac
->is_urgent
= is_urgent
;
3889 ret
= ldb_build_mod_req(&down_req
, ldb
, ac
,
3892 ac
, replmd_op_callback
,
3894 LDB_REQ_SET_LOCATION(down_req
);
3895 if (ret
!= LDB_SUCCESS
) {
3900 /* current partition control is needed by "replmd_op_callback" */
3901 if (ldb_request_get_control(req
, DSDB_CONTROL_CURRENT_PARTITION_OID
) == NULL
) {
3902 ret
= ldb_request_add_control(down_req
,
3903 DSDB_CONTROL_CURRENT_PARTITION_OID
,
3905 if (ret
!= LDB_SUCCESS
) {
3911 talloc_steal(down_req
, msg
);
3913 ret
= add_time_element(msg
, "whenChanged", t
);
3914 if (ret
!= LDB_SUCCESS
) {
3920 ret
= add_uint64_element(ldb
, msg
, "uSNChanged", ac
->seq_num
);
3921 if (ret
!= LDB_SUCCESS
) {
3927 /* go on with the call chain - do the modify after the rename */
3928 return ldb_next_request(ac
->module
, down_req
);
3932 * remove links from objects that point at this object when an object
3933 * is deleted. We remove it from the NEXT module per MS-DRSR 5.160
3934 * RemoveObj which states that link removal due to the object being
3935 * deleted is NOT an originating update - they just go away!
3938 static int replmd_delete_remove_link(struct ldb_module
*module
,
3939 const struct dsdb_schema
*schema
,
3940 struct replmd_private
*replmd_private
,
3943 struct ldb_message_element
*el
,
3944 const struct dsdb_attribute
*sa
,
3945 struct ldb_request
*parent
)
3948 TALLOC_CTX
*tmp_ctx
= talloc_new(module
);
3949 struct ldb_context
*ldb
= ldb_module_get_ctx(module
);
3951 for (i
=0; i
<el
->num_values
; i
++) {
3952 struct dsdb_dn
*dsdb_dn
;
3954 struct ldb_message
*msg
;
3955 const struct dsdb_attribute
*target_attr
;
3956 struct ldb_message_element
*el2
;
3958 struct ldb_val dn_val
;
3959 uint32_t dsdb_flags
= 0;
3960 const char *attrs
[] = { NULL
, NULL
};
3961 struct ldb_result
*link_res
;
3962 struct ldb_message
*link_msg
;
3963 struct ldb_message_element
*link_el
;
3964 struct parsed_dn
*link_dns
;
3965 struct parsed_dn
*p
= NULL
, *unused
= NULL
;
3967 if (dsdb_dn_is_deleted_val(&el
->values
[i
])) {
3971 dsdb_dn
= dsdb_dn_parse(tmp_ctx
, ldb
, &el
->values
[i
], sa
->syntax
->ldap_oid
);
3973 talloc_free(tmp_ctx
);
3974 return LDB_ERR_OPERATIONS_ERROR
;
3977 /* remove the link */
3978 msg
= ldb_msg_new(tmp_ctx
);
3980 ldb_module_oom(module
);
3981 talloc_free(tmp_ctx
);
3982 return LDB_ERR_OPERATIONS_ERROR
;
3986 msg
->dn
= dsdb_dn
->dn
;
3988 target_attr
= dsdb_attribute_by_linkID(schema
, sa
->linkID
^ 1);
3989 if (target_attr
== NULL
) {
3992 attrs
[0] = target_attr
->lDAPDisplayName
;
3994 ret
= ldb_msg_add_empty(msg
, target_attr
->lDAPDisplayName
,
3995 LDB_FLAG_MOD_DELETE
, &el2
);
3996 if (ret
!= LDB_SUCCESS
) {
3997 ldb_module_oom(module
);
3998 talloc_free(tmp_ctx
);
3999 return LDB_ERR_OPERATIONS_ERROR
;
4002 ret
= dsdb_module_search_dn(module
, tmp_ctx
, &link_res
,
4004 DSDB_FLAG_NEXT_MODULE
|
4005 DSDB_SEARCH_SHOW_EXTENDED_DN
|
4006 DSDB_SEARCH_SHOW_RECYCLED
,
4009 if (ret
!= LDB_SUCCESS
) {
4010 talloc_free(tmp_ctx
);
4014 link_msg
= link_res
->msgs
[0];
4015 link_el
= ldb_msg_find_element(link_msg
,
4016 target_attr
->lDAPDisplayName
);
4017 if (link_el
== NULL
) {
4018 talloc_free(tmp_ctx
);
4019 return LDB_ERR_NO_SUCH_ATTRIBUTE
;
4023 * This call 'upgrades' the links in link_dns, but we
4024 * do not commit the result back into the database, so
4025 * this is safe to call in FL2000 or on databases that
4026 * have been run at that level in the past.
4028 ret
= get_parsed_dns_trusted(module
, replmd_private
, tmp_ctx
,
4030 target_attr
->syntax
->ldap_oid
, parent
);
4031 if (ret
!= LDB_SUCCESS
) {
4032 talloc_free(tmp_ctx
);
4036 ret
= parsed_dn_find(ldb
, link_dns
, link_el
->num_values
,
4040 target_attr
->syntax
->ldap_oid
, false);
4041 if (ret
!= LDB_SUCCESS
) {
4042 talloc_free(tmp_ctx
);
4047 ldb_asprintf_errstring(ldb_module_get_ctx(module
),
4048 "Failed to find forward link on %s "
4049 "as %s to remove backlink %s on %s",
4050 ldb_dn_get_linearized(msg
->dn
),
4051 target_attr
->lDAPDisplayName
,
4052 sa
->lDAPDisplayName
,
4053 ldb_dn_get_linearized(dn
));
4054 talloc_free(tmp_ctx
);
4055 return LDB_ERR_NO_SUCH_ATTRIBUTE
;
4059 /* This needs to get the Binary DN, by first searching */
4060 dn_str
= dsdb_dn_get_linearized(tmp_ctx
,
4063 dn_val
= data_blob_string_const(dn_str
);
4064 el2
->values
= &dn_val
;
4065 el2
->num_values
= 1;
4068 * Ensure that we tell the modification to vanish any linked
4069 * attributes (not simply mark them as isDeleted = TRUE)
4071 dsdb_flags
|= DSDB_REPLMD_VANISH_LINKS
;
4073 ret
= dsdb_module_modify(module
, msg
, dsdb_flags
|DSDB_FLAG_OWN_MODULE
, parent
);
4074 if (ret
!= LDB_SUCCESS
) {
4075 talloc_free(tmp_ctx
);
4079 talloc_free(tmp_ctx
);
4085 handle update of replication meta data for deletion of objects
4087 This also handles the mapping of delete to a rename operation
4088 to allow deletes to be replicated.
4090 It also handles the incoming deleted objects, to ensure they are
4091 fully deleted here. In that case re_delete is true, and we do not
4092 use this as a signal to change the deleted state, just reinforce it.
4095 static int replmd_delete_internals(struct ldb_module
*module
, struct ldb_request
*req
, bool re_delete
)
4097 int ret
= LDB_ERR_OTHER
;
4098 bool retb
, disallow_move_on_delete
;
4099 struct ldb_dn
*old_dn
= NULL
, *new_dn
= NULL
;
4100 const char *rdn_name
;
4101 const struct ldb_val
*rdn_value
, *new_rdn_value
;
4103 struct ldb_context
*ldb
= ldb_module_get_ctx(module
);
4104 const struct dsdb_schema
*schema
;
4105 struct ldb_message
*msg
, *old_msg
;
4106 struct ldb_message_element
*el
;
4107 TALLOC_CTX
*tmp_ctx
;
4108 struct ldb_result
*res
, *parent_res
;
4109 static const char * const preserved_attrs
[] = {
4110 /* yes, this really is a hard coded list. See MS-ADTS
4111 section 3.1.1.5.5.1.1 */
4114 "dNReferenceUpdate",
4125 "msDS-LastKnownRDN",
4131 "distinguishedName",
4135 "proxiedObjectName",
4137 "nTSecurityDescriptor",
4138 "replPropertyMetaData",
4140 "securityIdentifier",
4148 "userAccountControl",
4155 static const char * const all_attrs
[] = {
4156 DSDB_SECRET_ATTRIBUTES
,
4160 unsigned int i
, el_count
= 0;
4161 uint32_t dsdb_flags
= 0;
4162 struct replmd_private
*replmd_private
;
4163 enum deletion_state deletion_state
, next_deletion_state
;
4165 if (ldb_dn_is_special(req
->op
.del
.dn
)) {
4166 return ldb_next_request(module
, req
);
4170 * We have to allow dbcheck to remove an object that
4171 * is beyond repair, and to do so totally. This could
4172 * mean we we can get a partial object from the other
4173 * DC, causing havoc, so dbcheck suggests
4174 * re-replication first. dbcheck sets both DBCHECK
4175 * and RELAX in this situation.
4177 if (ldb_request_get_control(req
, LDB_CONTROL_RELAX_OID
)
4178 && ldb_request_get_control(req
, DSDB_CONTROL_DBCHECK
)) {
4179 /* really, really remove it */
4180 return ldb_next_request(module
, req
);
4183 tmp_ctx
= talloc_new(ldb
);
4186 return LDB_ERR_OPERATIONS_ERROR
;
4189 schema
= dsdb_get_schema(ldb
, tmp_ctx
);
4191 talloc_free(tmp_ctx
);
4192 return LDB_ERR_OPERATIONS_ERROR
;
4195 old_dn
= ldb_dn_copy(tmp_ctx
, req
->op
.del
.dn
);
4197 /* we need the complete msg off disk, so we can work out which
4198 attributes need to be removed */
4199 ret
= dsdb_module_search_dn(module
, tmp_ctx
, &res
, old_dn
, all_attrs
,
4200 DSDB_FLAG_NEXT_MODULE
|
4201 DSDB_SEARCH_SHOW_RECYCLED
|
4202 DSDB_SEARCH_REVEAL_INTERNALS
|
4203 DSDB_SEARCH_SHOW_DN_IN_STORAGE_FORMAT
, req
);
4204 if (ret
!= LDB_SUCCESS
) {
4205 ldb_asprintf_errstring(ldb_module_get_ctx(module
),
4206 "repmd_delete: Failed to %s %s, because we failed to find it: %s",
4207 re_delete
? "re-delete" : "delete",
4208 ldb_dn_get_linearized(old_dn
),
4209 ldb_errstring(ldb_module_get_ctx(module
)));
4210 talloc_free(tmp_ctx
);
4213 old_msg
= res
->msgs
[0];
4215 replmd_deletion_state(module
, old_msg
,
4217 &next_deletion_state
);
4219 /* This supports us noticing an incoming isDeleted and acting on it */
4221 SMB_ASSERT(deletion_state
> OBJECT_NOT_DELETED
);
4222 next_deletion_state
= deletion_state
;
4225 if (next_deletion_state
== OBJECT_REMOVED
) {
4227 * We have to prevent objects being deleted, even if
4228 * the administrator really wants them gone, as
4229 * without the tombstone, we can get a partial object
4230 * from the other DC, causing havoc.
4232 * The only other valid case is when the 180 day
4233 * timeout has expired, when relax is specified.
4235 if (ldb_request_get_control(req
, LDB_CONTROL_RELAX_OID
)) {
4236 /* it is already deleted - really remove it this time */
4237 talloc_free(tmp_ctx
);
4238 return ldb_next_request(module
, req
);
4241 ldb_asprintf_errstring(ldb
, "Refusing to delete tombstone object %s. "
4242 "This check is to prevent corruption of the replicated state.",
4243 ldb_dn_get_linearized(old_msg
->dn
));
4244 return LDB_ERR_UNWILLING_TO_PERFORM
;
4247 rdn_name
= ldb_dn_get_rdn_name(old_dn
);
4248 rdn_value
= ldb_dn_get_rdn_val(old_dn
);
4249 if ((rdn_name
== NULL
) || (rdn_value
== NULL
)) {
4250 talloc_free(tmp_ctx
);
4251 return ldb_operr(ldb
);
4254 msg
= ldb_msg_new(tmp_ctx
);
4256 ldb_module_oom(module
);
4257 talloc_free(tmp_ctx
);
4258 return LDB_ERR_OPERATIONS_ERROR
;
4263 /* consider the SYSTEM_FLAG_DISALLOW_MOVE_ON_DELETE flag */
4264 disallow_move_on_delete
=
4265 (ldb_msg_find_attr_as_int(old_msg
, "systemFlags", 0)
4266 & SYSTEM_FLAG_DISALLOW_MOVE_ON_DELETE
);
4268 /* work out where we will be renaming this object to */
4269 if (!disallow_move_on_delete
) {
4270 struct ldb_dn
*deleted_objects_dn
;
4271 ret
= dsdb_get_deleted_objects_dn(ldb
, tmp_ctx
, old_dn
,
4272 &deleted_objects_dn
);
4275 * We should not move objects if we can't find the
4276 * deleted objects DN. Not moving (or otherwise
4277 * harming) the Deleted Objects DN itself is handled
4280 if (re_delete
&& (ret
!= LDB_SUCCESS
)) {
4281 new_dn
= ldb_dn_get_parent(tmp_ctx
, old_dn
);
4282 if (new_dn
== NULL
) {
4283 ldb_module_oom(module
);
4284 talloc_free(tmp_ctx
);
4285 return LDB_ERR_OPERATIONS_ERROR
;
4287 } else if (ret
!= LDB_SUCCESS
) {
4288 /* this is probably an attempted delete on a partition
4289 * that doesn't allow delete operations, such as the
4290 * schema partition */
4291 ldb_asprintf_errstring(ldb
, "No Deleted Objects container for DN %s",
4292 ldb_dn_get_linearized(old_dn
));
4293 talloc_free(tmp_ctx
);
4294 return LDB_ERR_UNWILLING_TO_PERFORM
;
4296 new_dn
= deleted_objects_dn
;
4299 new_dn
= ldb_dn_get_parent(tmp_ctx
, old_dn
);
4300 if (new_dn
== NULL
) {
4301 ldb_module_oom(module
);
4302 talloc_free(tmp_ctx
);
4303 return LDB_ERR_OPERATIONS_ERROR
;
4307 /* get the objects GUID from the search we just did */
4308 guid
= samdb_result_guid(old_msg
, "objectGUID");
4310 if (deletion_state
== OBJECT_NOT_DELETED
) {
4312 ret
= replmd_make_deleted_child_dn(tmp_ctx
,
4315 rdn_name
, rdn_value
,
4318 if (ret
!= LDB_SUCCESS
) {
4319 talloc_free(tmp_ctx
);
4323 ret
= ldb_msg_add_string(msg
, "isDeleted", "TRUE");
4324 if (ret
!= LDB_SUCCESS
) {
4325 ldb_asprintf_errstring(ldb
, __location__
4326 ": Failed to add isDeleted string to the msg");
4327 talloc_free(tmp_ctx
);
4330 msg
->elements
[el_count
++].flags
= LDB_FLAG_MOD_REPLACE
;
4333 * No matter what has happened with other renames etc, try again to
4334 * get this to be under the deleted DN. See MS-DRSR 5.160 RemoveObj
4337 struct ldb_dn
*rdn
= ldb_dn_copy(tmp_ctx
, old_dn
);
4338 retb
= ldb_dn_remove_base_components(rdn
, ldb_dn_get_comp_num(rdn
) - 1);
4340 ldb_asprintf_errstring(ldb
, __location__
4341 ": Unable to add a prepare rdn of %s",
4342 ldb_dn_get_linearized(rdn
));
4343 talloc_free(tmp_ctx
);
4344 return LDB_ERR_OPERATIONS_ERROR
;
4346 SMB_ASSERT(ldb_dn_get_comp_num(rdn
) == 1);
4348 retb
= ldb_dn_add_child(new_dn
, rdn
);
4350 ldb_asprintf_errstring(ldb
, __location__
4351 ": Unable to add rdn %s to base dn: %s",
4352 ldb_dn_get_linearized(rdn
),
4353 ldb_dn_get_linearized(new_dn
));
4354 talloc_free(tmp_ctx
);
4355 return LDB_ERR_OPERATIONS_ERROR
;
4360 now we need to modify the object in the following ways:
4362 - add isDeleted=TRUE
4363 - update rDN and name, with new rDN
4364 - remove linked attributes
4365 - remove objectCategory and sAMAccountType
4366 - remove attribs not on the preserved list
4367 - preserved if in above list, or is rDN
4368 - remove all linked attribs from this object
4369 - remove all links from other objects to this object
4370 - add lastKnownParent
4371 - update replPropertyMetaData?
4373 see MS-ADTS "Tombstone Requirements" section 3.1.1.5.5.1.1
4376 if (deletion_state
== OBJECT_NOT_DELETED
) {
4377 struct ldb_dn
*parent_dn
= ldb_dn_get_parent(tmp_ctx
, old_dn
);
4378 char *parent_dn_str
= NULL
;
4380 /* we need the storage form of the parent GUID */
4381 ret
= dsdb_module_search_dn(module
, tmp_ctx
, &parent_res
,
4383 DSDB_FLAG_NEXT_MODULE
|
4384 DSDB_SEARCH_SHOW_DN_IN_STORAGE_FORMAT
|
4385 DSDB_SEARCH_REVEAL_INTERNALS
|
4386 DSDB_SEARCH_SHOW_RECYCLED
, req
);
4387 if (ret
!= LDB_SUCCESS
) {
4388 ldb_asprintf_errstring(ldb_module_get_ctx(module
),
4389 "repmd_delete: Failed to %s %s, "
4390 "because we failed to find it's parent (%s): %s",
4391 re_delete
? "re-delete" : "delete",
4392 ldb_dn_get_linearized(old_dn
),
4393 ldb_dn_get_linearized(parent_dn
),
4394 ldb_errstring(ldb_module_get_ctx(module
)));
4395 talloc_free(tmp_ctx
);
4400 * Now we can use the DB version,
4401 * it will have the extended DN info in it
4403 parent_dn
= parent_res
->msgs
[0]->dn
;
4404 parent_dn_str
= ldb_dn_get_extended_linearized(tmp_ctx
,
4407 if (parent_dn_str
== NULL
) {
4408 talloc_free(tmp_ctx
);
4409 return ldb_module_oom(module
);
4412 ret
= ldb_msg_add_steal_string(msg
, "lastKnownParent",
4414 if (ret
!= LDB_SUCCESS
) {
4415 ldb_asprintf_errstring(ldb
, __location__
4416 ": Failed to add lastKnownParent "
4417 "string when deleting %s",
4418 ldb_dn_get_linearized(old_dn
));
4419 talloc_free(tmp_ctx
);
4422 msg
->elements
[el_count
++].flags
= LDB_FLAG_MOD_REPLACE
;
4424 if (next_deletion_state
== OBJECT_DELETED
) {
4425 ret
= ldb_msg_add_value(msg
, "msDS-LastKnownRDN", rdn_value
, NULL
);
4426 if (ret
!= LDB_SUCCESS
) {
4427 ldb_asprintf_errstring(ldb
, __location__
4428 ": Failed to add msDS-LastKnownRDN "
4429 "string when deleting %s",
4430 ldb_dn_get_linearized(old_dn
));
4431 talloc_free(tmp_ctx
);
4434 msg
->elements
[el_count
++].flags
= LDB_FLAG_MOD_ADD
;
4438 switch (next_deletion_state
) {
4440 case OBJECT_RECYCLED
:
4441 case OBJECT_TOMBSTONE
:
4444 * MS-ADTS 3.1.1.5.5.1.1 Tombstone Requirements
4445 * describes what must be removed from a tombstone
4448 * MS-ADTS 3.1.1.5.5.1.3 Recycled-Object Requirements
4449 * describes what must be removed from a recycled
4455 * we also mark it as recycled, meaning this object can't be
4456 * recovered (we are stripping its attributes).
4457 * This is done only if we have this schema object of course ...
4458 * This behavior is identical to the one of Windows 2008R2 which
4459 * always set the isRecycled attribute, even if the recycle-bin is
4460 * not activated and what ever the forest level is.
4462 if (dsdb_attribute_by_lDAPDisplayName(schema
, "isRecycled") != NULL
) {
4463 ret
= ldb_msg_add_string(msg
, "isRecycled", "TRUE");
4464 if (ret
!= LDB_SUCCESS
) {
4465 DEBUG(0,(__location__
": Failed to add isRecycled string to the msg\n"));
4466 ldb_module_oom(module
);
4467 talloc_free(tmp_ctx
);
4470 msg
->elements
[el_count
++].flags
= LDB_FLAG_MOD_REPLACE
;
4473 replmd_private
= talloc_get_type(ldb_module_get_private(module
),
4474 struct replmd_private
);
4475 /* work out which of the old attributes we will be removing */
4476 for (i
=0; i
<old_msg
->num_elements
; i
++) {
4477 const struct dsdb_attribute
*sa
;
4478 el
= &old_msg
->elements
[i
];
4479 sa
= dsdb_attribute_by_lDAPDisplayName(schema
, el
->name
);
4481 talloc_free(tmp_ctx
);
4482 return LDB_ERR_OPERATIONS_ERROR
;
4484 if (ldb_attr_cmp(el
->name
, rdn_name
) == 0) {
4485 /* don't remove the rDN */
4489 if (sa
->linkID
& 1) {
4491 we have a backlink in this object
4492 that needs to be removed. We're not
4493 allowed to remove it directly
4494 however, so we instead setup a
4495 modify to delete the corresponding
4498 ret
= replmd_delete_remove_link(module
, schema
,
4502 if (ret
== LDB_SUCCESS
) {
4504 * now we continue, which means we
4505 * won't remove this backlink
4511 if (ret
!= LDB_ERR_NO_SUCH_ATTRIBUTE
) {
4512 const char *old_dn_str
4513 = ldb_dn_get_linearized(old_dn
);
4514 ldb_asprintf_errstring(ldb
,
4516 ": Failed to remove backlink of "
4517 "%s when deleting %s: %s",
4520 ldb_errstring(ldb
));
4521 talloc_free(tmp_ctx
);
4522 return LDB_ERR_OPERATIONS_ERROR
;
4526 * Otherwise vanish the link, we are
4527 * out of sync and the controlling
4528 * object does not have the source
4532 dsdb_flags
|= DSDB_REPLMD_VANISH_LINKS
;
4534 } else if (sa
->linkID
== 0) {
4535 if (ldb_attr_in_list(preserved_attrs
, el
->name
)) {
4538 if (sa
->searchFlags
& SEARCH_FLAG_PRESERVEONDELETE
) {
4543 * Ensure that we tell the modification to vanish any linked
4544 * attributes (not simply mark them as isDeleted = TRUE)
4546 dsdb_flags
|= DSDB_REPLMD_VANISH_LINKS
;
4548 ret
= ldb_msg_add_empty(msg
, el
->name
, LDB_FLAG_MOD_DELETE
, &el
);
4549 if (ret
!= LDB_SUCCESS
) {
4550 talloc_free(tmp_ctx
);
4551 ldb_module_oom(module
);
4558 case OBJECT_DELETED
:
4560 * MS-ADTS 3.1.1.5.5.1.2 Deleted-Object Requirements
4561 * describes what must be removed from a deleted
4565 ret
= ldb_msg_add_empty(msg
, "objectCategory", LDB_FLAG_MOD_REPLACE
, NULL
);
4566 if (ret
!= LDB_SUCCESS
) {
4567 talloc_free(tmp_ctx
);
4568 ldb_module_oom(module
);
4572 ret
= ldb_msg_add_empty(msg
, "sAMAccountType", LDB_FLAG_MOD_REPLACE
, NULL
);
4573 if (ret
!= LDB_SUCCESS
) {
4574 talloc_free(tmp_ctx
);
4575 ldb_module_oom(module
);
4585 if (deletion_state
== OBJECT_NOT_DELETED
) {
4586 const struct dsdb_attribute
*sa
;
4588 /* work out what the new rdn value is, for updating the
4589 rDN and name fields */
4590 new_rdn_value
= ldb_dn_get_rdn_val(new_dn
);
4591 if (new_rdn_value
== NULL
) {
4592 talloc_free(tmp_ctx
);
4593 return ldb_operr(ldb
);
4596 sa
= dsdb_attribute_by_lDAPDisplayName(schema
, rdn_name
);
4598 talloc_free(tmp_ctx
);
4599 return LDB_ERR_OPERATIONS_ERROR
;
4602 ret
= ldb_msg_add_value(msg
, sa
->lDAPDisplayName
, new_rdn_value
,
4604 if (ret
!= LDB_SUCCESS
) {
4605 talloc_free(tmp_ctx
);
4608 el
->flags
= LDB_FLAG_MOD_REPLACE
;
4610 el
= ldb_msg_find_element(old_msg
, "name");
4612 ret
= ldb_msg_add_value(msg
, "name", new_rdn_value
, &el
);
4613 if (ret
!= LDB_SUCCESS
) {
4614 talloc_free(tmp_ctx
);
4617 el
->flags
= LDB_FLAG_MOD_REPLACE
;
4622 * TODO: Per MS-DRSR 5.160 RemoveObj we should remove links directly, not as an originating update!
4627 * No matter what has happned with other renames, try again to
4628 * get this to be under the deleted DN.
4630 if (strcmp(ldb_dn_get_linearized(old_dn
), ldb_dn_get_linearized(new_dn
)) != 0) {
4631 /* now rename onto the new DN */
4632 ret
= dsdb_module_rename(module
, old_dn
, new_dn
, DSDB_FLAG_NEXT_MODULE
, req
);
4633 if (ret
!= LDB_SUCCESS
){
4634 DEBUG(0,(__location__
": Failed to rename object from '%s' to '%s' - %s\n",
4635 ldb_dn_get_linearized(old_dn
),
4636 ldb_dn_get_linearized(new_dn
),
4637 ldb_errstring(ldb
)));
4638 talloc_free(tmp_ctx
);
4644 ret
= dsdb_module_modify(module
, msg
, dsdb_flags
|DSDB_FLAG_OWN_MODULE
, req
);
4645 if (ret
!= LDB_SUCCESS
) {
4646 ldb_asprintf_errstring(ldb
, "replmd_delete: Failed to modify object %s in delete - %s",
4647 ldb_dn_get_linearized(old_dn
), ldb_errstring(ldb
));
4648 talloc_free(tmp_ctx
);
4652 talloc_free(tmp_ctx
);
4654 return ldb_module_done(req
, NULL
, NULL
, LDB_SUCCESS
);
4657 static int replmd_delete(struct ldb_module
*module
, struct ldb_request
*req
)
4659 return replmd_delete_internals(module
, req
, false);
4663 static int replmd_replicated_request_error(struct replmd_replicated_request
*ar
, int ret
)
4668 static int replmd_replicated_request_werror(struct replmd_replicated_request
*ar
, WERROR status
)
4670 int ret
= LDB_ERR_OTHER
;
4671 /* TODO: do some error mapping */
4673 /* Let the caller know the full WERROR */
4674 ar
->objs
->error
= status
;
4680 static struct replPropertyMetaData1
*
4681 replmd_replPropertyMetaData1_find_attid(struct replPropertyMetaDataBlob
*md_blob
,
4682 enum drsuapi_DsAttributeId attid
)
4685 struct replPropertyMetaDataCtr1
*rpmd_ctr
= &md_blob
->ctr
.ctr1
;
4687 for (i
= 0; i
< rpmd_ctr
->count
; i
++) {
4688 if (rpmd_ctr
->array
[i
].attid
== attid
) {
4689 return &rpmd_ctr
->array
[i
];
4697 return true if an update is newer than an existing entry
4698 see section 5.11 of MS-ADTS
4700 static bool replmd_update_is_newer(const struct GUID
*current_invocation_id
,
4701 const struct GUID
*update_invocation_id
,
4702 uint32_t current_version
,
4703 uint32_t update_version
,
4704 NTTIME current_change_time
,
4705 NTTIME update_change_time
)
4707 if (update_version
!= current_version
) {
4708 return update_version
> current_version
;
4710 if (update_change_time
!= current_change_time
) {
4711 return update_change_time
> current_change_time
;
4713 return GUID_compare(update_invocation_id
, current_invocation_id
) > 0;
4716 static bool replmd_replPropertyMetaData1_is_newer(struct replPropertyMetaData1
*cur_m
,
4717 struct replPropertyMetaData1
*new_m
)
4719 return replmd_update_is_newer(&cur_m
->originating_invocation_id
,
4720 &new_m
->originating_invocation_id
,
4723 cur_m
->originating_change_time
,
4724 new_m
->originating_change_time
);
4727 static bool replmd_replPropertyMetaData1_new_should_be_taken(uint32_t dsdb_repl_flags
,
4728 struct replPropertyMetaData1
*cur_m
,
4729 struct replPropertyMetaData1
*new_m
)
4734 * If the new replPropertyMetaData entry for this attribute is
4735 * not provided (this happens in the case where we look for
4736 * ATTID_name, but the name was not changed), then the local
4737 * state is clearly still current, as the remote
4738 * server didn't send it due to being older the high watermark
4741 if (new_m
== NULL
) {
4745 if (dsdb_repl_flags
& DSDB_REPL_FLAG_PRIORITISE_INCOMING
) {
4747 * if we compare equal then do an
4748 * update. This is used when a client
4749 * asks for a FULL_SYNC, and can be
4750 * used to recover a corrupt
4753 * This call is a bit tricky, what we
4754 * are doing it turning the 'is_newer'
4755 * call into a 'not is older' by
4756 * swapping cur_m and new_m, and negating the
4759 cmp
= !replmd_replPropertyMetaData1_is_newer(new_m
,
4762 cmp
= replmd_replPropertyMetaData1_is_newer(cur_m
,
4770 form a DN for a deleted (DEL:) or conflict (CNF:) DN
4772 static int replmd_make_prefix_child_dn(TALLOC_CTX
*tmp_ctx
,
4773 struct ldb_context
*ldb
,
4775 const char *four_char_prefix
,
4776 const char *rdn_name
,
4777 const struct ldb_val
*rdn_value
,
4780 struct ldb_val deleted_child_rdn_val
;
4781 struct GUID_txt_buf guid_str
;
4784 GUID_buf_string(&guid
, &guid_str
);
4786 retb
= ldb_dn_add_child_fmt(dn
, "X=Y");
4788 ldb_asprintf_errstring(ldb
, __location__
4789 ": Unable to add a formatted child to dn: %s",
4790 ldb_dn_get_linearized(dn
));
4791 return LDB_ERR_OPERATIONS_ERROR
;
4795 * TODO: Per MS-ADTS 3.1.1.5.5 Delete Operation
4796 * we should truncate this value to ensure the RDN is not more than 255 chars.
4798 * However we MS-ADTS 3.1.1.5.1.2 Naming Constraints indicates that:
4800 * "Naming constraints are not enforced for replicated
4801 * updates." so this is safe and we don't have to work out not
4802 * splitting a UTF8 char right now.
4804 deleted_child_rdn_val
= ldb_val_dup(tmp_ctx
, rdn_value
);
4807 * sizeof(guid_str.buf) will always be longer than
4808 * strlen(guid_str.buf) but we allocate using this and
4809 * waste the trailing bytes to avoid scaring folks
4810 * with memcpy() using strlen() below
4813 deleted_child_rdn_val
.data
4814 = talloc_realloc(tmp_ctx
, deleted_child_rdn_val
.data
,
4816 rdn_value
->length
+ 5
4817 + sizeof(guid_str
.buf
));
4818 if (!deleted_child_rdn_val
.data
) {
4819 ldb_asprintf_errstring(ldb
, __location__
4820 ": Unable to add a formatted child to dn: %s",
4821 ldb_dn_get_linearized(dn
));
4822 return LDB_ERR_OPERATIONS_ERROR
;
4825 deleted_child_rdn_val
.length
=
4826 rdn_value
->length
+ 5
4827 + strlen(guid_str
.buf
);
4829 SMB_ASSERT(deleted_child_rdn_val
.length
<
4830 talloc_get_size(deleted_child_rdn_val
.data
));
4833 * talloc won't allocate more than 256MB so we can't
4834 * overflow but just to be sure
4836 if (deleted_child_rdn_val
.length
< rdn_value
->length
) {
4837 return LDB_ERR_OPERATIONS_ERROR
;
4840 deleted_child_rdn_val
.data
[rdn_value
->length
] = 0x0a;
4841 memcpy(&deleted_child_rdn_val
.data
[rdn_value
->length
+ 1],
4842 four_char_prefix
, 4);
4843 memcpy(&deleted_child_rdn_val
.data
[rdn_value
->length
+ 5],
4845 sizeof(guid_str
.buf
));
4847 /* Now set the value into the RDN, without parsing it */
4848 ldb_dn_set_component(dn
, 0, rdn_name
,
4849 deleted_child_rdn_val
);
4858 static struct ldb_dn
*replmd_conflict_dn(TALLOC_CTX
*mem_ctx
,
4859 struct ldb_context
*ldb
,
4863 const struct ldb_val
*rdn_val
;
4864 const char *rdn_name
;
4865 struct ldb_dn
*new_dn
;
4868 rdn_val
= ldb_dn_get_rdn_val(dn
);
4869 rdn_name
= ldb_dn_get_rdn_name(dn
);
4870 if (!rdn_val
|| !rdn_name
) {
4874 new_dn
= ldb_dn_get_parent(mem_ctx
, dn
);
4879 ret
= replmd_make_prefix_child_dn(mem_ctx
,
4885 if (ret
!= LDB_SUCCESS
) {
4894 static int replmd_make_deleted_child_dn(TALLOC_CTX
*tmp_ctx
,
4895 struct ldb_context
*ldb
,
4897 const char *rdn_name
,
4898 const struct ldb_val
*rdn_value
,
4901 return replmd_make_prefix_child_dn(tmp_ctx
,
4911 perform a modify operation which sets the rDN and name attributes to
4912 their current values. This has the effect of changing these
4913 attributes to have been last updated by the current DC. This is
4914 needed to ensure that renames performed as part of conflict
4915 resolution are propogated to other DCs
4917 static int replmd_name_modify(struct replmd_replicated_request
*ar
,
4918 struct ldb_request
*req
, struct ldb_dn
*dn
)
4920 struct ldb_message
*msg
;
4921 const char *rdn_name
;
4922 const struct ldb_val
*rdn_val
;
4923 const struct dsdb_attribute
*rdn_attr
;
4926 msg
= ldb_msg_new(req
);
4932 rdn_name
= ldb_dn_get_rdn_name(dn
);
4933 if (rdn_name
== NULL
) {
4937 /* normalize the rdn attribute name */
4938 rdn_attr
= dsdb_attribute_by_lDAPDisplayName(ar
->schema
, rdn_name
);
4939 if (rdn_attr
== NULL
) {
4942 rdn_name
= rdn_attr
->lDAPDisplayName
;
4944 rdn_val
= ldb_dn_get_rdn_val(dn
);
4945 if (rdn_val
== NULL
) {
4949 if (ldb_msg_add_empty(msg
, rdn_name
, LDB_FLAG_MOD_REPLACE
, NULL
) != 0) {
4952 if (ldb_msg_add_value(msg
, rdn_name
, rdn_val
, NULL
) != 0) {
4955 if (ldb_msg_add_empty(msg
, "name", LDB_FLAG_MOD_REPLACE
, NULL
) != 0) {
4958 if (ldb_msg_add_value(msg
, "name", rdn_val
, NULL
) != 0) {
4963 * We have to mark this as a replicated update otherwise
4964 * schema_data may reject a rename in the schema partition
4967 ret
= dsdb_module_modify(ar
->module
, msg
,
4968 DSDB_FLAG_OWN_MODULE
|DSDB_FLAG_REPLICATED_UPDATE
,
4970 if (ret
!= LDB_SUCCESS
) {
4971 DEBUG(0,(__location__
": Failed to modify rDN/name of DN being DRS renamed '%s' - %s",
4972 ldb_dn_get_linearized(dn
),
4973 ldb_errstring(ldb_module_get_ctx(ar
->module
))));
4983 DEBUG(0,(__location__
": Failed to setup modify rDN/name of DN being DRS renamed '%s'",
4984 ldb_dn_get_linearized(dn
)));
4985 return LDB_ERR_OPERATIONS_ERROR
;
4990 callback for conflict DN handling where we have renamed the incoming
4991 record. After renaming it, we need to ensure the change of name and
4992 rDN for the incoming record is seen as an originating update by this DC.
4994 This also handles updating lastKnownParent for entries sent to lostAndFound
4996 static int replmd_op_name_modify_callback(struct ldb_request
*req
, struct ldb_reply
*ares
)
4998 struct replmd_replicated_request
*ar
=
4999 talloc_get_type_abort(req
->context
, struct replmd_replicated_request
);
5000 struct ldb_dn
*conflict_dn
= NULL
;
5003 if (ares
->error
!= LDB_SUCCESS
) {
5004 /* call the normal callback for everything except success */
5005 return replmd_op_callback(req
, ares
);
5008 switch (req
->operation
) {
5010 conflict_dn
= req
->op
.add
.message
->dn
;
5013 conflict_dn
= req
->op
.mod
.message
->dn
;
5016 smb_panic("replmd_op_name_modify_callback called in unknown circumstances");
5019 /* perform a modify of the rDN and name of the record */
5020 ret
= replmd_name_modify(ar
, req
, conflict_dn
);
5021 if (ret
!= LDB_SUCCESS
) {
5023 return replmd_op_callback(req
, ares
);
5026 if (ar
->objs
->objects
[ar
->index_current
].last_known_parent
) {
5027 struct ldb_message
*msg
= ldb_msg_new(req
);
5029 ldb_module_oom(ar
->module
);
5030 return LDB_ERR_OPERATIONS_ERROR
;
5033 msg
->dn
= req
->op
.add
.message
->dn
;
5035 ret
= ldb_msg_add_steal_string(msg
, "lastKnownParent",
5036 ldb_dn_get_extended_linearized(msg
, ar
->objs
->objects
[ar
->index_current
].last_known_parent
, 1));
5037 if (ret
!= LDB_SUCCESS
) {
5038 DEBUG(0,(__location__
": Failed to add lastKnownParent string to the msg\n"));
5039 ldb_module_oom(ar
->module
);
5042 msg
->elements
[0].flags
= LDB_FLAG_MOD_REPLACE
;
5044 ret
= dsdb_module_modify(ar
->module
, msg
, DSDB_FLAG_OWN_MODULE
, req
);
5045 if (ret
!= LDB_SUCCESS
) {
5046 DEBUG(0,(__location__
": Failed to modify lastKnownParent of lostAndFound DN '%s' - %s",
5047 ldb_dn_get_linearized(msg
->dn
),
5048 ldb_errstring(ldb_module_get_ctx(ar
->module
))));
5054 return replmd_op_callback(req
, ares
);
5058 callback for replmd_replicated_apply_add()
5059 This copes with the creation of conflict records in the case where
5060 the DN exists, but with a different objectGUID
5062 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
))
5064 struct ldb_dn
*conflict_dn
;
5065 struct replmd_replicated_request
*ar
=
5066 talloc_get_type_abort(req
->context
, struct replmd_replicated_request
);
5067 struct ldb_result
*res
;
5068 const char *attrs
[] = { "replPropertyMetaData", "objectGUID", NULL
};
5070 const struct ldb_val
*omd_value
;
5071 struct replPropertyMetaDataBlob omd
, *rmd
;
5072 enum ndr_err_code ndr_err
;
5073 bool rename_incoming_record
, rodc
;
5074 struct replPropertyMetaData1
*rmd_name
, *omd_name
;
5075 struct ldb_message
*msg
;
5076 struct ldb_request
*down_req
= NULL
;
5078 /* call the normal callback for success */
5079 if (ares
->error
== LDB_SUCCESS
) {
5080 return callback(req
, ares
);
5084 * we have a conflict, and need to decide if we will keep the
5085 * new record or the old record
5088 msg
= ar
->objs
->objects
[ar
->index_current
].msg
;
5089 conflict_dn
= msg
->dn
;
5091 /* For failures other than conflicts, fail the whole operation here */
5092 if (ares
->error
!= LDB_ERR_ENTRY_ALREADY_EXISTS
) {
5093 ldb_asprintf_errstring(ldb_module_get_ctx(ar
->module
), "Failed to locally apply remote add of %s: %s",
5094 ldb_dn_get_linearized(conflict_dn
),
5095 ldb_errstring(ldb_module_get_ctx(ar
->module
)));
5097 return ldb_module_done(ar
->req
, NULL
, NULL
,
5098 LDB_ERR_OPERATIONS_ERROR
);
5101 ret
= samdb_rodc(ldb_module_get_ctx(ar
->module
), &rodc
);
5102 if (ret
!= LDB_SUCCESS
) {
5103 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
)));
5104 return ldb_module_done(ar
->req
, NULL
, NULL
,
5105 LDB_ERR_OPERATIONS_ERROR
);
5111 * We are on an RODC, or were a GC for this
5112 * partition, so we have to fail this until
5113 * someone who owns the partition sorts it
5116 ldb_asprintf_errstring(ldb_module_get_ctx(ar
->module
),
5117 "Conflict adding object '%s' from incoming replication as we are read only for the partition. \n"
5118 " - We must fail the operation until a master for this partition resolves the conflict",
5119 ldb_dn_get_linearized(conflict_dn
));
5120 ret
= LDB_ERR_OPERATIONS_ERROR
;
5125 * first we need the replPropertyMetaData attribute from the
5126 * local, conflicting record
5128 ret
= dsdb_module_search_dn(ar
->module
, req
, &res
, conflict_dn
,
5130 DSDB_FLAG_NEXT_MODULE
|
5131 DSDB_SEARCH_SHOW_DELETED
|
5132 DSDB_SEARCH_SHOW_RECYCLED
, req
);
5133 if (ret
!= LDB_SUCCESS
) {
5134 DEBUG(0,(__location__
": Unable to find object for conflicting record '%s'\n",
5135 ldb_dn_get_linearized(conflict_dn
)));
5139 omd_value
= ldb_msg_find_ldb_val(res
->msgs
[0], "replPropertyMetaData");
5140 if (omd_value
== NULL
) {
5141 DEBUG(0,(__location__
": Unable to find replPropertyMetaData for conflicting record '%s'\n",
5142 ldb_dn_get_linearized(conflict_dn
)));
5146 ndr_err
= ndr_pull_struct_blob(omd_value
, res
->msgs
[0], &omd
,
5147 (ndr_pull_flags_fn_t
)ndr_pull_replPropertyMetaDataBlob
);
5148 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err
)) {
5149 DEBUG(0,(__location__
": Failed to parse old replPropertyMetaData for %s\n",
5150 ldb_dn_get_linearized(conflict_dn
)));
5154 rmd
= ar
->objs
->objects
[ar
->index_current
].meta_data
;
5157 * we decide which is newer based on the RPMD on the name
5158 * attribute. See [MS-DRSR] ResolveNameConflict.
5160 * We expect omd_name to be present, as this is from a local
5161 * search, but while rmd_name should have been given to us by
5162 * the remote server, if it is missing we just prefer the
5164 * replmd_replPropertyMetaData1_new_should_be_taken()
5166 rmd_name
= replmd_replPropertyMetaData1_find_attid(rmd
, DRSUAPI_ATTID_name
);
5167 omd_name
= replmd_replPropertyMetaData1_find_attid(&omd
, DRSUAPI_ATTID_name
);
5169 DEBUG(0,(__location__
": Failed to find name attribute in local LDB replPropertyMetaData for %s\n",
5170 ldb_dn_get_linearized(conflict_dn
)));
5175 * Should we preserve the current record, and so rename the
5176 * incoming record to be a conflict?
5178 rename_incoming_record
5179 = !replmd_replPropertyMetaData1_new_should_be_taken(ar
->objs
->dsdb_repl_flags
& DSDB_REPL_FLAG_PRIORITISE_INCOMING
,
5180 omd_name
, rmd_name
);
5182 if (rename_incoming_record
) {
5184 struct ldb_dn
*new_dn
;
5186 guid
= samdb_result_guid(msg
, "objectGUID");
5187 if (GUID_all_zero(&guid
)) {
5188 DEBUG(0,(__location__
": Failed to find objectGUID for conflicting incoming record %s\n",
5189 ldb_dn_get_linearized(conflict_dn
)));
5192 new_dn
= replmd_conflict_dn(req
,
5193 ldb_module_get_ctx(ar
->module
),
5194 conflict_dn
, &guid
);
5195 if (new_dn
== NULL
) {
5196 DEBUG(0,(__location__
": Failed to form conflict DN for %s\n",
5197 ldb_dn_get_linearized(conflict_dn
)));
5201 DEBUG(2,(__location__
": Resolving conflict record via incoming rename '%s' -> '%s'\n",
5202 ldb_dn_get_linearized(conflict_dn
), ldb_dn_get_linearized(new_dn
)));
5204 /* re-submit the request, but with the new DN */
5205 callback
= replmd_op_name_modify_callback
;
5208 /* we are renaming the existing record */
5210 struct ldb_dn
*new_dn
;
5212 guid
= samdb_result_guid(res
->msgs
[0], "objectGUID");
5213 if (GUID_all_zero(&guid
)) {
5214 DEBUG(0,(__location__
": Failed to find objectGUID for existing conflict record %s\n",
5215 ldb_dn_get_linearized(conflict_dn
)));
5219 new_dn
= replmd_conflict_dn(req
,
5220 ldb_module_get_ctx(ar
->module
),
5221 conflict_dn
, &guid
);
5222 if (new_dn
== NULL
) {
5223 DEBUG(0,(__location__
": Failed to form conflict DN for %s\n",
5224 ldb_dn_get_linearized(conflict_dn
)));
5228 DEBUG(2,(__location__
": Resolving conflict record via existing-record rename '%s' -> '%s'\n",
5229 ldb_dn_get_linearized(conflict_dn
), ldb_dn_get_linearized(new_dn
)));
5231 ret
= dsdb_module_rename(ar
->module
, conflict_dn
, new_dn
,
5232 DSDB_FLAG_OWN_MODULE
, req
);
5233 if (ret
!= LDB_SUCCESS
) {
5234 DEBUG(0,(__location__
": Failed to rename conflict dn '%s' to '%s' - %s\n",
5235 ldb_dn_get_linearized(conflict_dn
),
5236 ldb_dn_get_linearized(new_dn
),
5237 ldb_errstring(ldb_module_get_ctx(ar
->module
))));
5242 * now we need to ensure that the rename is seen as an
5243 * originating update. We do that with a modify.
5245 ret
= replmd_name_modify(ar
, req
, new_dn
);
5246 if (ret
!= LDB_SUCCESS
) {
5250 DEBUG(2,(__location__
": With conflicting record renamed, re-apply replicated creation of '%s'\n",
5251 ldb_dn_get_linearized(req
->op
.add
.message
->dn
)));
5254 ret
= ldb_build_add_req(&down_req
,
5255 ldb_module_get_ctx(ar
->module
),
5262 if (ret
!= LDB_SUCCESS
) {
5265 LDB_REQ_SET_LOCATION(down_req
);
5267 /* current partition control needed by "repmd_op_callback" */
5268 ret
= ldb_request_add_control(down_req
,
5269 DSDB_CONTROL_CURRENT_PARTITION_OID
,
5271 if (ret
!= LDB_SUCCESS
) {
5272 return replmd_replicated_request_error(ar
, ret
);
5275 if (ar
->objs
->dsdb_repl_flags
& DSDB_REPL_FLAG_PARTIAL_REPLICA
) {
5276 /* this tells the partition module to make it a
5277 partial replica if creating an NC */
5278 ret
= ldb_request_add_control(down_req
,
5279 DSDB_CONTROL_PARTIAL_REPLICA
,
5281 if (ret
!= LDB_SUCCESS
) {
5282 return replmd_replicated_request_error(ar
, ret
);
5287 * Finally we re-run the add, otherwise the new record won't
5288 * exist, as we are here because of that exact failure!
5290 return ldb_next_request(ar
->module
, down_req
);
5293 /* on failure make the caller get the error. This means
5294 * replication will stop with an error, but there is not much
5297 if (ret
== LDB_SUCCESS
) {
5298 ret
= LDB_ERR_OPERATIONS_ERROR
;
5300 return ldb_module_done(ar
->req
, NULL
, NULL
,
5305 callback for replmd_replicated_apply_add()
5306 This copes with the creation of conflict records in the case where
5307 the DN exists, but with a different objectGUID
5309 static int replmd_op_add_callback(struct ldb_request
*req
, struct ldb_reply
*ares
)
5311 struct replmd_replicated_request
*ar
=
5312 talloc_get_type_abort(req
->context
, struct replmd_replicated_request
);
5314 if (ar
->objs
->objects
[ar
->index_current
].last_known_parent
) {
5315 /* This is like a conflict DN, where we put the object in LostAndFound
5316 see MS-DRSR 4.1.10.6.10 FindBestParentObject */
5317 return replmd_op_possible_conflict_callback(req
, ares
, replmd_op_name_modify_callback
);
5320 return replmd_op_possible_conflict_callback(req
, ares
, replmd_op_callback
);
5324 this is called when a new object comes in over DRS
5326 static int replmd_replicated_apply_add(struct replmd_replicated_request
*ar
)
5328 struct ldb_context
*ldb
;
5329 struct ldb_request
*change_req
;
5330 enum ndr_err_code ndr_err
;
5331 struct ldb_message
*msg
;
5332 struct replPropertyMetaDataBlob
*md
;
5333 struct ldb_val md_value
;
5336 bool remote_isDeleted
= false;
5339 time_t t
= time(NULL
);
5340 const struct ldb_val
*rdn_val
;
5341 struct replmd_private
*replmd_private
=
5342 talloc_get_type(ldb_module_get_private(ar
->module
),
5343 struct replmd_private
);
5344 unix_to_nt_time(&now
, t
);
5346 ldb
= ldb_module_get_ctx(ar
->module
);
5347 msg
= ar
->objs
->objects
[ar
->index_current
].msg
;
5348 md
= ar
->objs
->objects
[ar
->index_current
].meta_data
;
5349 is_schema_nc
= ldb_dn_compare_base(replmd_private
->schema_dn
, msg
->dn
) == 0;
5351 ret
= ldb_sequence_number(ldb
, LDB_SEQ_NEXT
, &ar
->seq_num
);
5352 if (ret
!= LDB_SUCCESS
) {
5353 return replmd_replicated_request_error(ar
, ret
);
5356 ret
= dsdb_msg_add_guid(msg
,
5357 &ar
->objs
->objects
[ar
->index_current
].object_guid
,
5359 if (ret
!= LDB_SUCCESS
) {
5360 return replmd_replicated_request_error(ar
, ret
);
5363 ret
= ldb_msg_add_string(msg
, "whenChanged", ar
->objs
->objects
[ar
->index_current
].when_changed
);
5364 if (ret
!= LDB_SUCCESS
) {
5365 return replmd_replicated_request_error(ar
, ret
);
5368 ret
= samdb_msg_add_uint64(ldb
, msg
, msg
, "uSNCreated", ar
->seq_num
);
5369 if (ret
!= LDB_SUCCESS
) {
5370 return replmd_replicated_request_error(ar
, ret
);
5373 ret
= samdb_msg_add_uint64(ldb
, msg
, msg
, "uSNChanged", ar
->seq_num
);
5374 if (ret
!= LDB_SUCCESS
) {
5375 return replmd_replicated_request_error(ar
, ret
);
5378 /* remove any message elements that have zero values */
5379 for (i
=0; i
<msg
->num_elements
; i
++) {
5380 struct ldb_message_element
*el
= &msg
->elements
[i
];
5382 if (el
->num_values
== 0) {
5383 if (ldb_attr_cmp(msg
->elements
[i
].name
, "objectClass") == 0) {
5384 ldb_asprintf_errstring(ldb
, __location__
5385 ": empty objectClass sent on %s, aborting replication\n",
5386 ldb_dn_get_linearized(msg
->dn
));
5387 return replmd_replicated_request_error(ar
, LDB_ERR_OBJECT_CLASS_VIOLATION
);
5390 DEBUG(4,(__location__
": Removing attribute %s with num_values==0\n",
5392 memmove(el
, el
+1, sizeof(*el
)*(msg
->num_elements
- (i
+1)));
5393 msg
->num_elements
--;
5400 struct GUID_txt_buf guid_txt
;
5402 char *s
= ldb_ldif_message_redacted_string(ldb
, ar
,
5405 DEBUG(8, ("DRS replication add message of %s:\n%s\n",
5406 GUID_buf_string(&ar
->objs
->objects
[ar
->index_current
].object_guid
, &guid_txt
),
5409 } else if (DEBUGLVL(4)) {
5410 struct GUID_txt_buf guid_txt
;
5411 DEBUG(4, ("DRS replication add DN of %s is %s\n",
5412 GUID_buf_string(&ar
->objs
->objects
[ar
->index_current
].object_guid
, &guid_txt
),
5413 ldb_dn_get_linearized(msg
->dn
)));
5415 remote_isDeleted
= ldb_msg_find_attr_as_bool(msg
,
5416 "isDeleted", false);
5419 * the meta data array is already sorted by the caller, except
5420 * for the RDN, which needs to be added.
5424 rdn_val
= ldb_dn_get_rdn_val(msg
->dn
);
5425 ret
= replmd_update_rpmd_rdn_attr(ldb
, msg
, rdn_val
, NULL
,
5426 md
, ar
, now
, is_schema_nc
,
5428 if (ret
!= LDB_SUCCESS
) {
5429 ldb_asprintf_errstring(ldb
, "%s: error during DRS repl ADD: %s", __func__
, ldb_errstring(ldb
));
5430 return replmd_replicated_request_error(ar
, ret
);
5433 ret
= replmd_replPropertyMetaDataCtr1_sort_and_verify(ldb
, &md
->ctr
.ctr1
, msg
->dn
);
5434 if (ret
!= LDB_SUCCESS
) {
5435 ldb_asprintf_errstring(ldb
, "%s: error during DRS repl ADD: %s", __func__
, ldb_errstring(ldb
));
5436 return replmd_replicated_request_error(ar
, ret
);
5439 for (i
=0; i
< md
->ctr
.ctr1
.count
; i
++) {
5440 md
->ctr
.ctr1
.array
[i
].local_usn
= ar
->seq_num
;
5442 ndr_err
= ndr_push_struct_blob(&md_value
, msg
, md
,
5443 (ndr_push_flags_fn_t
)ndr_push_replPropertyMetaDataBlob
);
5444 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err
)) {
5445 NTSTATUS nt_status
= ndr_map_error2ntstatus(ndr_err
);
5446 return replmd_replicated_request_werror(ar
, ntstatus_to_werror(nt_status
));
5448 ret
= ldb_msg_add_value(msg
, "replPropertyMetaData", &md_value
, NULL
);
5449 if (ret
!= LDB_SUCCESS
) {
5450 return replmd_replicated_request_error(ar
, ret
);
5453 replmd_ldb_message_sort(msg
, ar
->schema
);
5455 if (!remote_isDeleted
) {
5456 ret
= dsdb_module_schedule_sd_propagation(ar
->module
,
5457 ar
->objs
->partition_dn
,
5459 if (ret
!= LDB_SUCCESS
) {
5460 return replmd_replicated_request_error(ar
, ret
);
5464 ar
->isDeleted
= remote_isDeleted
;
5466 ret
= ldb_build_add_req(&change_req
,
5472 replmd_op_add_callback
,
5474 LDB_REQ_SET_LOCATION(change_req
);
5475 if (ret
!= LDB_SUCCESS
) return replmd_replicated_request_error(ar
, ret
);
5477 /* current partition control needed by "repmd_op_callback" */
5478 ret
= ldb_request_add_control(change_req
,
5479 DSDB_CONTROL_CURRENT_PARTITION_OID
,
5481 if (ret
!= LDB_SUCCESS
) return replmd_replicated_request_error(ar
, ret
);
5483 if (ar
->objs
->dsdb_repl_flags
& DSDB_REPL_FLAG_PARTIAL_REPLICA
) {
5484 /* this tells the partition module to make it a
5485 partial replica if creating an NC */
5486 ret
= ldb_request_add_control(change_req
,
5487 DSDB_CONTROL_PARTIAL_REPLICA
,
5489 if (ret
!= LDB_SUCCESS
) return replmd_replicated_request_error(ar
, ret
);
5492 return ldb_next_request(ar
->module
, change_req
);
5495 static int replmd_replicated_apply_search_for_parent_callback(struct ldb_request
*req
,
5496 struct ldb_reply
*ares
)
5498 struct replmd_replicated_request
*ar
= talloc_get_type(req
->context
,
5499 struct replmd_replicated_request
);
5503 return ldb_module_done(ar
->req
, NULL
, NULL
,
5504 LDB_ERR_OPERATIONS_ERROR
);
5508 * The error NO_SUCH_OBJECT is not expected, unless the search
5509 * base is the partition DN, and that case doesn't happen here
5510 * because then we wouldn't get a parent_guid_value in any
5513 if (ares
->error
!= LDB_SUCCESS
) {
5514 return ldb_module_done(ar
->req
, ares
->controls
,
5515 ares
->response
, ares
->error
);
5518 switch (ares
->type
) {
5519 case LDB_REPLY_ENTRY
:
5521 struct ldb_message
*parent_msg
= ares
->message
;
5522 struct ldb_message
*msg
= ar
->objs
->objects
[ar
->index_current
].msg
;
5523 struct ldb_dn
*parent_dn
= NULL
;
5526 if (!ldb_msg_check_string_attribute(msg
, "isDeleted", "TRUE")
5527 && ldb_msg_check_string_attribute(parent_msg
, "isDeleted", "TRUE")) {
5528 /* Per MS-DRSR 4.1.10.6.10
5529 * FindBestParentObject we need to move this
5530 * new object under a deleted object to
5532 struct ldb_dn
*nc_root
;
5534 ret
= dsdb_find_nc_root(ldb_module_get_ctx(ar
->module
), msg
, msg
->dn
, &nc_root
);
5535 if (ret
== LDB_ERR_NO_SUCH_OBJECT
) {
5536 ldb_asprintf_errstring(ldb_module_get_ctx(ar
->module
),
5537 "No suitable NC root found for %s. "
5538 "We need to move this object because parent object %s "
5539 "is deleted, but this object is not.",
5540 ldb_dn_get_linearized(msg
->dn
),
5541 ldb_dn_get_linearized(parent_msg
->dn
));
5542 return ldb_module_done(ar
->req
, NULL
, NULL
, LDB_ERR_OPERATIONS_ERROR
);
5543 } else if (ret
!= LDB_SUCCESS
) {
5544 ldb_asprintf_errstring(ldb_module_get_ctx(ar
->module
),
5545 "Unable to find NC root for %s: %s. "
5546 "We need to move this object because parent object %s "
5547 "is deleted, but this object is not.",
5548 ldb_dn_get_linearized(msg
->dn
),
5549 ldb_errstring(ldb_module_get_ctx(ar
->module
)),
5550 ldb_dn_get_linearized(parent_msg
->dn
));
5551 return ldb_module_done(ar
->req
, NULL
, NULL
, LDB_ERR_OPERATIONS_ERROR
);
5554 ret
= dsdb_wellknown_dn(ldb_module_get_ctx(ar
->module
), msg
,
5556 DS_GUID_LOSTANDFOUND_CONTAINER
,
5558 if (ret
!= LDB_SUCCESS
) {
5559 ldb_asprintf_errstring(ldb_module_get_ctx(ar
->module
),
5560 "Unable to find LostAndFound Container for %s "
5561 "in partition %s: %s. "
5562 "We need to move this object because parent object %s "
5563 "is deleted, but this object is not.",
5564 ldb_dn_get_linearized(msg
->dn
), ldb_dn_get_linearized(nc_root
),
5565 ldb_errstring(ldb_module_get_ctx(ar
->module
)),
5566 ldb_dn_get_linearized(parent_msg
->dn
));
5567 return ldb_module_done(ar
->req
, NULL
, NULL
, LDB_ERR_OPERATIONS_ERROR
);
5569 ar
->objs
->objects
[ar
->index_current
].last_known_parent
5570 = talloc_steal(ar
->objs
->objects
[ar
->index_current
].msg
, parent_msg
->dn
);
5574 = talloc_steal(ar
->objs
->objects
[ar
->index_current
].msg
, parent_msg
->dn
);
5577 ar
->objs
->objects
[ar
->index_current
].local_parent_dn
= parent_dn
;
5579 comp_num
= ldb_dn_get_comp_num(msg
->dn
);
5581 if (!ldb_dn_remove_base_components(msg
->dn
, comp_num
- 1)) {
5583 return ldb_module_done(ar
->req
, NULL
, NULL
, ldb_module_operr(ar
->module
));
5586 if (!ldb_dn_add_base(msg
->dn
, parent_dn
)) {
5588 return ldb_module_done(ar
->req
, NULL
, NULL
, ldb_module_operr(ar
->module
));
5592 case LDB_REPLY_REFERRAL
:
5593 /* we ignore referrals */
5596 case LDB_REPLY_DONE
:
5598 if (ar
->objs
->objects
[ar
->index_current
].local_parent_dn
== NULL
) {
5599 struct GUID_txt_buf str_buf
;
5600 if (ar
->search_msg
!= NULL
) {
5601 ldb_asprintf_errstring(ldb_module_get_ctx(ar
->module
),
5602 "No parent with GUID %s found for object locally known as %s",
5603 GUID_buf_string(ar
->objs
->objects
[ar
->index_current
].parent_guid
, &str_buf
),
5604 ldb_dn_get_linearized(ar
->search_msg
->dn
));
5606 ldb_asprintf_errstring(ldb_module_get_ctx(ar
->module
),
5607 "No parent with GUID %s found for object remotely known as %s",
5608 GUID_buf_string(ar
->objs
->objects
[ar
->index_current
].parent_guid
, &str_buf
),
5609 ldb_dn_get_linearized(ar
->objs
->objects
[ar
->index_current
].msg
->dn
));
5613 * This error code is really important, as it
5614 * is the flag back to the callers to retry
5615 * this with DRSUAPI_DRS_GET_ANC, and so get
5616 * the parent objects before the child
5619 return ldb_module_done(ar
->req
, NULL
, NULL
,
5620 replmd_replicated_request_werror(ar
, WERR_DS_DRA_MISSING_PARENT
));
5623 if (ar
->search_msg
!= NULL
) {
5624 ret
= replmd_replicated_apply_merge(ar
);
5626 ret
= replmd_replicated_apply_add(ar
);
5628 if (ret
!= LDB_SUCCESS
) {
5629 return ldb_module_done(ar
->req
, NULL
, NULL
, ret
);
5638 * Look for the parent object, so we put the new object in the right
5639 * place This is akin to NameObject in MS-DRSR - this routine and the
5640 * callbacks find the right parent name, and correct name for this
5644 static int replmd_replicated_apply_search_for_parent(struct replmd_replicated_request
*ar
)
5646 struct ldb_context
*ldb
;
5650 struct ldb_request
*search_req
;
5651 static const char *attrs
[] = {"isDeleted", NULL
};
5652 struct GUID_txt_buf guid_str_buf
;
5654 ldb
= ldb_module_get_ctx(ar
->module
);
5656 if (ar
->objs
->objects
[ar
->index_current
].parent_guid
== NULL
) {
5657 if (ar
->search_msg
!= NULL
) {
5658 return replmd_replicated_apply_merge(ar
);
5660 return replmd_replicated_apply_add(ar
);
5664 tmp_str
= GUID_buf_string(ar
->objs
->objects
[ar
->index_current
].parent_guid
,
5667 filter
= talloc_asprintf(ar
, "(objectGUID=%s)", tmp_str
);
5668 if (!filter
) return replmd_replicated_request_werror(ar
, WERR_NOT_ENOUGH_MEMORY
);
5670 ret
= ldb_build_search_req(&search_req
,
5673 ar
->objs
->partition_dn
,
5679 replmd_replicated_apply_search_for_parent_callback
,
5681 LDB_REQ_SET_LOCATION(search_req
);
5683 ret
= dsdb_request_add_controls(search_req
,
5684 DSDB_SEARCH_SHOW_RECYCLED
|
5685 DSDB_SEARCH_SHOW_DELETED
|
5686 DSDB_SEARCH_SHOW_EXTENDED_DN
);
5687 if (ret
!= LDB_SUCCESS
) {
5691 return ldb_next_request(ar
->module
, search_req
);
5695 handle renames that come in over DRS replication
5697 static int replmd_replicated_handle_rename(struct replmd_replicated_request
*ar
,
5698 struct ldb_message
*msg
,
5699 struct ldb_request
*parent
,
5703 TALLOC_CTX
*tmp_ctx
= talloc_new(msg
);
5704 struct ldb_result
*res
;
5705 struct ldb_dn
*conflict_dn
;
5706 const char *attrs
[] = { "replPropertyMetaData", "objectGUID", NULL
};
5707 const struct ldb_val
*omd_value
;
5708 struct replPropertyMetaDataBlob omd
, *rmd
;
5709 enum ndr_err_code ndr_err
;
5710 bool rename_incoming_record
, rodc
;
5711 struct replPropertyMetaData1
*rmd_name
, *omd_name
;
5712 struct ldb_dn
*new_dn
;
5715 DEBUG(4,("replmd_replicated_request rename %s => %s\n",
5716 ldb_dn_get_linearized(ar
->search_msg
->dn
),
5717 ldb_dn_get_linearized(msg
->dn
)));
5720 ret
= dsdb_module_rename(ar
->module
, ar
->search_msg
->dn
, msg
->dn
,
5721 DSDB_FLAG_NEXT_MODULE
, ar
->req
);
5722 if (ret
== LDB_SUCCESS
) {
5723 talloc_free(tmp_ctx
);
5728 if (ret
!= LDB_ERR_ENTRY_ALREADY_EXISTS
) {
5729 talloc_free(tmp_ctx
);
5730 ldb_asprintf_errstring(ldb_module_get_ctx(ar
->module
), "Failed to locally apply remote rename from %s to %s: %s",
5731 ldb_dn_get_linearized(ar
->search_msg
->dn
),
5732 ldb_dn_get_linearized(msg
->dn
),
5733 ldb_errstring(ldb_module_get_ctx(ar
->module
)));
5737 ret
= samdb_rodc(ldb_module_get_ctx(ar
->module
), &rodc
);
5738 if (ret
!= LDB_SUCCESS
) {
5739 ldb_asprintf_errstring(ldb_module_get_ctx(ar
->module
),
5740 "Failed to determine if we are an RODC when attempting to form conflict DN: %s",
5741 ldb_errstring(ldb_module_get_ctx(ar
->module
)));
5742 return LDB_ERR_OPERATIONS_ERROR
;
5745 * we have a conflict, and need to decide if we will keep the
5746 * new record or the old record
5749 conflict_dn
= msg
->dn
;
5753 * We are on an RODC, or were a GC for this
5754 * partition, so we have to fail this until
5755 * someone who owns the partition sorts it
5758 ldb_asprintf_errstring(ldb_module_get_ctx(ar
->module
),
5759 "Conflict adding object '%s' from incoming replication but we are read only for the partition. \n"
5760 " - We must fail the operation until a master for this partition resolves the conflict",
5761 ldb_dn_get_linearized(conflict_dn
));
5762 ret
= LDB_ERR_OPERATIONS_ERROR
;
5767 * first we need the replPropertyMetaData attribute from the
5770 ret
= dsdb_module_search_dn(ar
->module
, tmp_ctx
, &res
, conflict_dn
,
5772 DSDB_FLAG_NEXT_MODULE
|
5773 DSDB_SEARCH_SHOW_DELETED
|
5774 DSDB_SEARCH_SHOW_RECYCLED
, ar
->req
);
5775 if (ret
!= LDB_SUCCESS
) {
5776 DEBUG(0,(__location__
": Unable to find object for conflicting record '%s'\n",
5777 ldb_dn_get_linearized(conflict_dn
)));
5781 omd_value
= ldb_msg_find_ldb_val(res
->msgs
[0], "replPropertyMetaData");
5782 if (omd_value
== NULL
) {
5783 DEBUG(0,(__location__
": Unable to find replPropertyMetaData for conflicting record '%s'\n",
5784 ldb_dn_get_linearized(conflict_dn
)));
5788 ndr_err
= ndr_pull_struct_blob(omd_value
, res
->msgs
[0], &omd
,
5789 (ndr_pull_flags_fn_t
)ndr_pull_replPropertyMetaDataBlob
);
5790 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err
)) {
5791 DEBUG(0,(__location__
": Failed to parse old replPropertyMetaData for %s\n",
5792 ldb_dn_get_linearized(conflict_dn
)));
5796 rmd
= ar
->objs
->objects
[ar
->index_current
].meta_data
;
5799 * we decide which is newer based on the RPMD on the name
5800 * attribute. See [MS-DRSR] ResolveNameConflict.
5802 * We expect omd_name to be present, as this is from a local
5803 * search, but while rmd_name should have been given to us by
5804 * the remote server, if it is missing we just prefer the
5806 * replmd_replPropertyMetaData1_new_should_be_taken()
5808 rmd_name
= replmd_replPropertyMetaData1_find_attid(rmd
, DRSUAPI_ATTID_name
);
5809 omd_name
= replmd_replPropertyMetaData1_find_attid(&omd
, DRSUAPI_ATTID_name
);
5811 DEBUG(0,(__location__
": Failed to find name attribute in local LDB replPropertyMetaData for %s\n",
5812 ldb_dn_get_linearized(conflict_dn
)));
5817 * Should we preserve the current record, and so rename the
5818 * incoming record to be a conflict?
5820 rename_incoming_record
=
5821 !replmd_replPropertyMetaData1_new_should_be_taken(
5822 ar
->objs
->dsdb_repl_flags
& DSDB_REPL_FLAG_PRIORITISE_INCOMING
,
5823 omd_name
, rmd_name
);
5825 if (rename_incoming_record
) {
5827 new_dn
= replmd_conflict_dn(msg
,
5828 ldb_module_get_ctx(ar
->module
),
5830 &ar
->objs
->objects
[ar
->index_current
].object_guid
);
5831 if (new_dn
== NULL
) {
5832 ldb_asprintf_errstring(ldb_module_get_ctx(ar
->module
),
5833 "Failed to form conflict DN for %s\n",
5834 ldb_dn_get_linearized(msg
->dn
));
5836 return replmd_replicated_request_werror(ar
, WERR_NOT_ENOUGH_MEMORY
);
5839 ret
= dsdb_module_rename(ar
->module
, ar
->search_msg
->dn
, new_dn
,
5840 DSDB_FLAG_NEXT_MODULE
, ar
->req
);
5841 if (ret
!= LDB_SUCCESS
) {
5842 ldb_asprintf_errstring(ldb_module_get_ctx(ar
->module
),
5843 "Failed to rename incoming conflicting dn '%s' (was '%s') to '%s' - %s\n",
5844 ldb_dn_get_linearized(conflict_dn
),
5845 ldb_dn_get_linearized(ar
->search_msg
->dn
),
5846 ldb_dn_get_linearized(new_dn
),
5847 ldb_errstring(ldb_module_get_ctx(ar
->module
)));
5848 return replmd_replicated_request_werror(ar
, WERR_DS_DRA_DB_ERROR
);
5856 /* we are renaming the existing record */
5858 guid
= samdb_result_guid(res
->msgs
[0], "objectGUID");
5859 if (GUID_all_zero(&guid
)) {
5860 DEBUG(0,(__location__
": Failed to find objectGUID for existing conflict record %s\n",
5861 ldb_dn_get_linearized(conflict_dn
)));
5865 new_dn
= replmd_conflict_dn(tmp_ctx
,
5866 ldb_module_get_ctx(ar
->module
),
5867 conflict_dn
, &guid
);
5868 if (new_dn
== NULL
) {
5869 DEBUG(0,(__location__
": Failed to form conflict DN for %s\n",
5870 ldb_dn_get_linearized(conflict_dn
)));
5874 DEBUG(2,(__location__
": Resolving conflict record via existing-record rename '%s' -> '%s'\n",
5875 ldb_dn_get_linearized(conflict_dn
), ldb_dn_get_linearized(new_dn
)));
5877 ret
= dsdb_module_rename(ar
->module
, conflict_dn
, new_dn
,
5878 DSDB_FLAG_OWN_MODULE
, ar
->req
);
5879 if (ret
!= LDB_SUCCESS
) {
5880 DEBUG(0,(__location__
": Failed to rename conflict dn '%s' to '%s' - %s\n",
5881 ldb_dn_get_linearized(conflict_dn
),
5882 ldb_dn_get_linearized(new_dn
),
5883 ldb_errstring(ldb_module_get_ctx(ar
->module
))));
5888 * now we need to ensure that the rename is seen as an
5889 * originating update. We do that with a modify.
5891 ret
= replmd_name_modify(ar
, ar
->req
, new_dn
);
5892 if (ret
!= LDB_SUCCESS
) {
5896 DEBUG(2,(__location__
": With conflicting record renamed, re-apply replicated rename '%s' -> '%s'\n",
5897 ldb_dn_get_linearized(ar
->search_msg
->dn
),
5898 ldb_dn_get_linearized(msg
->dn
)));
5901 ret
= dsdb_module_rename(ar
->module
, ar
->search_msg
->dn
, msg
->dn
,
5902 DSDB_FLAG_NEXT_MODULE
, ar
->req
);
5903 if (ret
!= LDB_SUCCESS
) {
5904 DEBUG(0,(__location__
": After conflict resolution, failed to rename dn '%s' to '%s' - %s\n",
5905 ldb_dn_get_linearized(ar
->search_msg
->dn
),
5906 ldb_dn_get_linearized(msg
->dn
),
5907 ldb_errstring(ldb_module_get_ctx(ar
->module
))));
5911 talloc_free(tmp_ctx
);
5915 * On failure make the caller get the error
5916 * This means replication will stop with an error,
5917 * but there is not much else we can do. In the
5918 * LDB_ERR_ENTRY_ALREADY_EXISTS case this is exactly what is
5921 if (ret
== LDB_SUCCESS
) {
5922 ret
= LDB_ERR_OPERATIONS_ERROR
;
5925 talloc_free(tmp_ctx
);
5930 static int replmd_replicated_apply_merge(struct replmd_replicated_request
*ar
)
5932 struct ldb_context
*ldb
;
5933 struct ldb_request
*change_req
;
5934 enum ndr_err_code ndr_err
;
5935 struct ldb_message
*msg
;
5936 struct replPropertyMetaDataBlob
*rmd
;
5937 struct replPropertyMetaDataBlob omd
;
5938 const struct ldb_val
*omd_value
;
5939 struct replPropertyMetaDataBlob nmd
;
5940 struct ldb_val nmd_value
;
5941 struct GUID remote_parent_guid
;
5944 unsigned int removed_attrs
= 0;
5946 int (*callback
)(struct ldb_request
*req
, struct ldb_reply
*ares
) = replmd_op_callback
;
5947 bool isDeleted
= false;
5948 bool local_isDeleted
= false;
5949 bool remote_isDeleted
= false;
5950 bool take_remote_isDeleted
= false;
5951 bool sd_updated
= false;
5952 bool renamed
= false;
5953 bool is_schema_nc
= false;
5955 const struct ldb_val
*old_rdn
, *new_rdn
;
5956 struct replmd_private
*replmd_private
=
5957 talloc_get_type(ldb_module_get_private(ar
->module
),
5958 struct replmd_private
);
5960 time_t t
= time(NULL
);
5961 unix_to_nt_time(&now
, t
);
5963 ldb
= ldb_module_get_ctx(ar
->module
);
5964 msg
= ar
->objs
->objects
[ar
->index_current
].msg
;
5966 is_schema_nc
= ldb_dn_compare_base(replmd_private
->schema_dn
, msg
->dn
) == 0;
5968 rmd
= ar
->objs
->objects
[ar
->index_current
].meta_data
;
5972 /* find existing meta data */
5973 omd_value
= ldb_msg_find_ldb_val(ar
->search_msg
, "replPropertyMetaData");
5975 ndr_err
= ndr_pull_struct_blob(omd_value
, ar
, &omd
,
5976 (ndr_pull_flags_fn_t
)ndr_pull_replPropertyMetaDataBlob
);
5977 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err
)) {
5978 nt_status
= ndr_map_error2ntstatus(ndr_err
);
5979 return replmd_replicated_request_werror(ar
, ntstatus_to_werror(nt_status
));
5982 if (omd
.version
!= 1) {
5983 return replmd_replicated_request_werror(ar
, WERR_DS_DRA_INTERNAL_ERROR
);
5988 struct GUID_txt_buf guid_txt
;
5990 char *s
= ldb_ldif_message_redacted_string(ldb
, ar
,
5991 LDB_CHANGETYPE_MODIFY
, msg
);
5992 DEBUG(8, ("Initial DRS replication modify message of %s is:\n%s\n"
5995 GUID_buf_string(&ar
->objs
->objects
[ar
->index_current
].object_guid
, &guid_txt
),
5997 ndr_print_struct_string(s
,
5998 (ndr_print_fn_t
)ndr_print_replPropertyMetaDataBlob
,
5999 "existing replPropertyMetaData",
6001 ndr_print_struct_string(s
,
6002 (ndr_print_fn_t
)ndr_print_replPropertyMetaDataBlob
,
6003 "incoming replPropertyMetaData",
6006 } else if (DEBUGLVL(4)) {
6007 struct GUID_txt_buf guid_txt
;
6009 DEBUG(4, ("Initial DRS replication modify DN of %s is: %s\n",
6010 GUID_buf_string(&ar
->objs
->objects
[ar
->index_current
].object_guid
,
6012 ldb_dn_get_linearized(msg
->dn
)));
6015 local_isDeleted
= ldb_msg_find_attr_as_bool(ar
->search_msg
,
6016 "isDeleted", false);
6017 remote_isDeleted
= ldb_msg_find_attr_as_bool(msg
,
6018 "isDeleted", false);
6021 * Fill in the remote_parent_guid with the GUID or an all-zero
6024 if (ar
->objs
->objects
[ar
->index_current
].parent_guid
!= NULL
) {
6025 remote_parent_guid
= *ar
->objs
->objects
[ar
->index_current
].parent_guid
;
6027 remote_parent_guid
= GUID_zero();
6031 * To ensure we follow a complex rename chain around, we have
6032 * to confirm that the DN is the same (mostly to confirm the
6033 * RDN) and the parentGUID is the same.
6035 * This ensures we keep things under the correct parent, which
6036 * replmd_replicated_handle_rename() will do.
6039 if (strcmp(ldb_dn_get_linearized(msg
->dn
), ldb_dn_get_linearized(ar
->search_msg
->dn
)) == 0
6040 && GUID_equal(&remote_parent_guid
, &ar
->local_parent_guid
)) {
6044 * handle renames, even just by case that come in over
6045 * DRS. Changes in the parent DN don't hit us here,
6046 * because the search for a parent will clean up those
6049 * We also have already filtered out the case where
6050 * the peer has an older name to what we have (see
6051 * replmd_replicated_apply_search_callback())
6053 ret
= replmd_replicated_handle_rename(ar
, msg
, ar
->req
, &renamed
);
6056 if (ret
!= LDB_SUCCESS
) {
6057 ldb_debug(ldb
, LDB_DEBUG_FATAL
,
6058 "replmd_replicated_request rename %s => %s failed - %s\n",
6059 ldb_dn_get_linearized(ar
->search_msg
->dn
),
6060 ldb_dn_get_linearized(msg
->dn
),
6061 ldb_errstring(ldb
));
6062 return replmd_replicated_request_werror(ar
, WERR_DS_DRA_DB_ERROR
);
6065 if (renamed
== true) {
6067 * Set the callback to one that will fix up the name
6068 * metadata on the new conflict DN
6070 callback
= replmd_op_name_modify_callback
;
6075 nmd
.ctr
.ctr1
.count
= omd
.ctr
.ctr1
.count
+ rmd
->ctr
.ctr1
.count
;
6076 nmd
.ctr
.ctr1
.array
= talloc_array(ar
,
6077 struct replPropertyMetaData1
,
6078 nmd
.ctr
.ctr1
.count
);
6079 if (!nmd
.ctr
.ctr1
.array
) return replmd_replicated_request_werror(ar
, WERR_NOT_ENOUGH_MEMORY
);
6081 /* first copy the old meta data */
6082 for (i
=0; i
< omd
.ctr
.ctr1
.count
; i
++) {
6083 nmd
.ctr
.ctr1
.array
[ni
] = omd
.ctr
.ctr1
.array
[i
];
6088 /* now merge in the new meta data */
6089 for (i
=0; i
< rmd
->ctr
.ctr1
.count
; i
++) {
6092 for (j
=0; j
< ni
; j
++) {
6095 if (rmd
->ctr
.ctr1
.array
[i
].attid
!= nmd
.ctr
.ctr1
.array
[j
].attid
) {
6099 cmp
= replmd_replPropertyMetaData1_new_should_be_taken(
6100 ar
->objs
->dsdb_repl_flags
,
6101 &nmd
.ctr
.ctr1
.array
[j
],
6102 &rmd
->ctr
.ctr1
.array
[i
]);
6104 /* replace the entry */
6105 nmd
.ctr
.ctr1
.array
[j
] = rmd
->ctr
.ctr1
.array
[i
];
6106 if (ar
->seq_num
== 0) {
6107 ret
= ldb_sequence_number(ldb
, LDB_SEQ_NEXT
, &ar
->seq_num
);
6108 if (ret
!= LDB_SUCCESS
) {
6109 return replmd_replicated_request_error(ar
, ret
);
6112 nmd
.ctr
.ctr1
.array
[j
].local_usn
= ar
->seq_num
;
6113 switch (nmd
.ctr
.ctr1
.array
[j
].attid
) {
6114 case DRSUAPI_ATTID_ntSecurityDescriptor
:
6117 case DRSUAPI_ATTID_isDeleted
:
6118 take_remote_isDeleted
= true;
6127 if (rmd
->ctr
.ctr1
.array
[i
].attid
!= DRSUAPI_ATTID_instanceType
) {
6128 DEBUG(3,("Discarding older DRS attribute update to %s on %s from %s\n",
6129 msg
->elements
[i
-removed_attrs
].name
,
6130 ldb_dn_get_linearized(msg
->dn
),
6131 GUID_string(ar
, &rmd
->ctr
.ctr1
.array
[i
].originating_invocation_id
)));
6134 /* we don't want to apply this change so remove the attribute */
6135 ldb_msg_remove_element(msg
, &msg
->elements
[i
-removed_attrs
]);
6142 if (found
) continue;
6144 nmd
.ctr
.ctr1
.array
[ni
] = rmd
->ctr
.ctr1
.array
[i
];
6145 if (ar
->seq_num
== 0) {
6146 ret
= ldb_sequence_number(ldb
, LDB_SEQ_NEXT
, &ar
->seq_num
);
6147 if (ret
!= LDB_SUCCESS
) {
6148 return replmd_replicated_request_error(ar
, ret
);
6151 nmd
.ctr
.ctr1
.array
[ni
].local_usn
= ar
->seq_num
;
6152 switch (nmd
.ctr
.ctr1
.array
[ni
].attid
) {
6153 case DRSUAPI_ATTID_ntSecurityDescriptor
:
6156 case DRSUAPI_ATTID_isDeleted
:
6157 take_remote_isDeleted
= true;
6166 * finally correct the size of the meta_data array
6168 nmd
.ctr
.ctr1
.count
= ni
;
6170 new_rdn
= ldb_dn_get_rdn_val(msg
->dn
);
6171 old_rdn
= ldb_dn_get_rdn_val(ar
->search_msg
->dn
);
6174 ret
= replmd_update_rpmd_rdn_attr(ldb
, msg
, new_rdn
, old_rdn
,
6175 &nmd
, ar
, now
, is_schema_nc
,
6177 if (ret
!= LDB_SUCCESS
) {
6178 ldb_asprintf_errstring(ldb
, "%s: error during DRS repl merge: %s", __func__
, ldb_errstring(ldb
));
6179 return replmd_replicated_request_error(ar
, ret
);
6183 * sort the new meta data array
6185 ret
= replmd_replPropertyMetaDataCtr1_sort_and_verify(ldb
, &nmd
.ctr
.ctr1
, msg
->dn
);
6186 if (ret
!= LDB_SUCCESS
) {
6187 ldb_asprintf_errstring(ldb
, "%s: error during DRS repl merge: %s", __func__
, ldb_errstring(ldb
));
6192 * Work out if this object is deleted, so we can prune any extra attributes. See MS-DRSR 4.1.10.6.9
6195 * This also controls SD propagation below
6197 if (take_remote_isDeleted
) {
6198 isDeleted
= remote_isDeleted
;
6200 isDeleted
= local_isDeleted
;
6203 ar
->isDeleted
= isDeleted
;
6206 * check if some replicated attributes left, otherwise skip the ldb_modify() call
6208 if (msg
->num_elements
== 0) {
6209 ldb_debug(ldb
, LDB_DEBUG_TRACE
, "replmd_replicated_apply_merge[%u]: skip replace\n",
6212 return replmd_replicated_apply_isDeleted(ar
);
6215 ldb_debug(ldb
, LDB_DEBUG_TRACE
, "replmd_replicated_apply_merge[%u]: replace %u attributes\n",
6216 ar
->index_current
, msg
->num_elements
);
6222 if (sd_updated
&& !isDeleted
) {
6223 ret
= dsdb_module_schedule_sd_propagation(ar
->module
,
6224 ar
->objs
->partition_dn
,
6226 if (ret
!= LDB_SUCCESS
) {
6227 return ldb_operr(ldb
);
6231 /* create the meta data value */
6232 ndr_err
= ndr_push_struct_blob(&nmd_value
, msg
, &nmd
,
6233 (ndr_push_flags_fn_t
)ndr_push_replPropertyMetaDataBlob
);
6234 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err
)) {
6235 nt_status
= ndr_map_error2ntstatus(ndr_err
);
6236 return replmd_replicated_request_werror(ar
, ntstatus_to_werror(nt_status
));
6240 * when we know that we'll modify the record, add the whenChanged, uSNChanged
6241 * and replPopertyMetaData attributes
6243 ret
= ldb_msg_add_string(msg
, "whenChanged", ar
->objs
->objects
[ar
->index_current
].when_changed
);
6244 if (ret
!= LDB_SUCCESS
) {
6245 return replmd_replicated_request_error(ar
, ret
);
6247 ret
= samdb_msg_add_uint64(ldb
, msg
, msg
, "uSNChanged", ar
->seq_num
);
6248 if (ret
!= LDB_SUCCESS
) {
6249 return replmd_replicated_request_error(ar
, ret
);
6251 ret
= ldb_msg_add_value(msg
, "replPropertyMetaData", &nmd_value
, NULL
);
6252 if (ret
!= LDB_SUCCESS
) {
6253 return replmd_replicated_request_error(ar
, ret
);
6256 replmd_ldb_message_sort(msg
, ar
->schema
);
6258 /* we want to replace the old values */
6259 for (i
=0; i
< msg
->num_elements
; i
++) {
6260 msg
->elements
[i
].flags
= LDB_FLAG_MOD_REPLACE
;
6261 if (ldb_attr_cmp(msg
->elements
[i
].name
, "objectClass") == 0) {
6262 if (msg
->elements
[i
].num_values
== 0) {
6263 ldb_asprintf_errstring(ldb
, __location__
6264 ": objectClass removed on %s, aborting replication\n",
6265 ldb_dn_get_linearized(msg
->dn
));
6266 return replmd_replicated_request_error(ar
, LDB_ERR_OBJECT_CLASS_VIOLATION
);
6272 struct GUID_txt_buf guid_txt
;
6274 char *s
= ldb_ldif_message_redacted_string(ldb
, ar
,
6275 LDB_CHANGETYPE_MODIFY
,
6277 DEBUG(8, ("Final DRS replication modify message of %s:\n%s\n",
6278 GUID_buf_string(&ar
->objs
->objects
[ar
->index_current
].object_guid
,
6282 } else if (DEBUGLVL(4)) {
6283 struct GUID_txt_buf guid_txt
;
6285 DEBUG(4, ("Final DRS replication modify DN of %s is %s\n",
6286 GUID_buf_string(&ar
->objs
->objects
[ar
->index_current
].object_guid
,
6288 ldb_dn_get_linearized(msg
->dn
)));
6291 ret
= ldb_build_mod_req(&change_req
,
6299 LDB_REQ_SET_LOCATION(change_req
);
6300 if (ret
!= LDB_SUCCESS
) return replmd_replicated_request_error(ar
, ret
);
6302 /* current partition control needed by "repmd_op_callback" */
6303 ret
= ldb_request_add_control(change_req
,
6304 DSDB_CONTROL_CURRENT_PARTITION_OID
,
6306 if (ret
!= LDB_SUCCESS
) return replmd_replicated_request_error(ar
, ret
);
6308 return ldb_next_request(ar
->module
, change_req
);
6311 static int replmd_replicated_apply_search_callback(struct ldb_request
*req
,
6312 struct ldb_reply
*ares
)
6314 struct replmd_replicated_request
*ar
= talloc_get_type(req
->context
,
6315 struct replmd_replicated_request
);
6319 return ldb_module_done(ar
->req
, NULL
, NULL
,
6320 LDB_ERR_OPERATIONS_ERROR
);
6322 if (ares
->error
!= LDB_SUCCESS
&&
6323 ares
->error
!= LDB_ERR_NO_SUCH_OBJECT
) {
6324 return ldb_module_done(ar
->req
, ares
->controls
,
6325 ares
->response
, ares
->error
);
6328 switch (ares
->type
) {
6329 case LDB_REPLY_ENTRY
:
6330 ar
->search_msg
= talloc_steal(ar
, ares
->message
);
6333 case LDB_REPLY_REFERRAL
:
6334 /* we ignore referrals */
6337 case LDB_REPLY_DONE
:
6339 struct replPropertyMetaData1
*md_remote
;
6340 struct replPropertyMetaData1
*md_local
;
6342 struct replPropertyMetaDataBlob omd
;
6343 const struct ldb_val
*omd_value
;
6344 struct replPropertyMetaDataBlob
*rmd
;
6345 struct ldb_message
*msg
;
6347 ar
->objs
->objects
[ar
->index_current
].local_parent_dn
= NULL
;
6348 ar
->objs
->objects
[ar
->index_current
].last_known_parent
= NULL
;
6351 * This is the ADD case, find the appropriate parent,
6352 * as this object doesn't exist locally:
6354 if (ar
->search_msg
== NULL
) {
6355 ret
= replmd_replicated_apply_search_for_parent(ar
);
6356 if (ret
!= LDB_SUCCESS
) {
6357 return ldb_module_done(ar
->req
, NULL
, NULL
, ret
);
6364 * Otherwise, in the MERGE case, work out if we are
6365 * attempting a rename, and if so find the parent the
6366 * newly renamed object wants to belong under (which
6367 * may not be the parent in it's attached string DN
6369 rmd
= ar
->objs
->objects
[ar
->index_current
].meta_data
;
6373 /* find existing meta data */
6374 omd_value
= ldb_msg_find_ldb_val(ar
->search_msg
, "replPropertyMetaData");
6376 enum ndr_err_code ndr_err
;
6377 ndr_err
= ndr_pull_struct_blob(omd_value
, ar
, &omd
,
6378 (ndr_pull_flags_fn_t
)ndr_pull_replPropertyMetaDataBlob
);
6379 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err
)) {
6380 NTSTATUS nt_status
= ndr_map_error2ntstatus(ndr_err
);
6381 return replmd_replicated_request_werror(ar
, ntstatus_to_werror(nt_status
));
6384 if (omd
.version
!= 1) {
6385 return replmd_replicated_request_werror(ar
, WERR_DS_DRA_INTERNAL_ERROR
);
6389 ar
->local_parent_guid
= samdb_result_guid(ar
->search_msg
, "parentGUID");
6391 instanceType
= ldb_msg_find_attr_as_int(ar
->search_msg
, "instanceType", 0);
6392 if (((instanceType
& INSTANCE_TYPE_IS_NC_HEAD
) == 0)
6393 && GUID_all_zero(&ar
->local_parent_guid
)) {
6394 DEBUG(0, ("Refusing to replicate new version of %s "
6395 "as local object has an all-zero parentGUID attribute, "
6396 "despite not being an NC root\n",
6397 ldb_dn_get_linearized(ar
->search_msg
->dn
)));
6398 return replmd_replicated_request_werror(ar
, WERR_DS_DRA_INTERNAL_ERROR
);
6402 * now we need to check for double renames. We could have a
6403 * local rename pending which our replication partner hasn't
6404 * received yet. We choose which one wins by looking at the
6405 * attribute stamps on the two objects, the newer one wins.
6407 * This also simply applies the correct algorithms for
6408 * determining if a change was made to name at all, or
6409 * if the object has just been renamed under the same
6412 md_remote
= replmd_replPropertyMetaData1_find_attid(rmd
, DRSUAPI_ATTID_name
);
6413 md_local
= replmd_replPropertyMetaData1_find_attid(&omd
, DRSUAPI_ATTID_name
);
6415 DEBUG(0,(__location__
": Failed to find name attribute in local LDB replPropertyMetaData for %s\n",
6416 ldb_dn_get_linearized(ar
->search_msg
->dn
)));
6417 return replmd_replicated_request_werror(ar
, WERR_DS_DRA_DB_ERROR
);
6421 * if there is no name attribute given then we have to assume the
6422 * object we've received has the older name
6424 if (replmd_replPropertyMetaData1_new_should_be_taken(
6425 ar
->objs
->dsdb_repl_flags
& DSDB_REPL_FLAG_PRIORITISE_INCOMING
,
6426 md_local
, md_remote
)) {
6427 struct GUID_txt_buf p_guid_local
;
6428 struct GUID_txt_buf p_guid_remote
;
6429 msg
= ar
->objs
->objects
[ar
->index_current
].msg
;
6431 /* Merge on the existing object, with rename */
6433 DEBUG(4,(__location__
": Looking for new parent for object %s currently under %s "
6434 "as incoming object changing to %s under %s\n",
6435 ldb_dn_get_linearized(ar
->search_msg
->dn
),
6436 GUID_buf_string(&ar
->local_parent_guid
, &p_guid_local
),
6437 ldb_dn_get_linearized(msg
->dn
),
6438 GUID_buf_string(ar
->objs
->objects
[ar
->index_current
].parent_guid
,
6440 ret
= replmd_replicated_apply_search_for_parent(ar
);
6442 struct GUID_txt_buf p_guid_local
;
6443 struct GUID_txt_buf p_guid_remote
;
6444 msg
= ar
->objs
->objects
[ar
->index_current
].msg
;
6447 * Merge on the existing object, force no
6448 * rename (code below just to explain why in
6452 if (strcmp(ldb_dn_get_linearized(ar
->search_msg
->dn
),
6453 ldb_dn_get_linearized(msg
->dn
)) == 0) {
6454 if (ar
->objs
->objects
[ar
->index_current
].parent_guid
!= NULL
&&
6455 GUID_equal(&ar
->local_parent_guid
,
6456 ar
->objs
->objects
[ar
->index_current
].parent_guid
)
6458 DEBUG(4,(__location__
": Keeping object %s at under %s "
6459 "despite incoming object changing parent to %s\n",
6460 ldb_dn_get_linearized(ar
->search_msg
->dn
),
6461 GUID_buf_string(&ar
->local_parent_guid
, &p_guid_local
),
6462 GUID_buf_string(ar
->objs
->objects
[ar
->index_current
].parent_guid
,
6466 DEBUG(4,(__location__
": Keeping object %s at under %s "
6467 " and rejecting older rename to %s under %s\n",
6468 ldb_dn_get_linearized(ar
->search_msg
->dn
),
6469 GUID_buf_string(&ar
->local_parent_guid
, &p_guid_local
),
6470 ldb_dn_get_linearized(msg
->dn
),
6471 GUID_buf_string(ar
->objs
->objects
[ar
->index_current
].parent_guid
,
6475 * This assignment ensures that the strcmp()
6476 * and GUID_equal() calls in
6477 * replmd_replicated_apply_merge() avoids the
6480 ar
->objs
->objects
[ar
->index_current
].parent_guid
=
6481 &ar
->local_parent_guid
;
6483 msg
->dn
= ar
->search_msg
->dn
;
6484 ret
= replmd_replicated_apply_merge(ar
);
6486 if (ret
!= LDB_SUCCESS
) {
6487 return ldb_module_done(ar
->req
, NULL
, NULL
, ret
);
6497 * Stores the linked attributes received in the replication chunk - these get
6498 * applied at the end of the transaction. We also check that each linked
6499 * attribute is valid, i.e. source and target objects are known.
6501 static int replmd_store_linked_attributes(struct replmd_replicated_request
*ar
)
6503 int ret
= LDB_SUCCESS
;
6505 struct ldb_module
*module
= ar
->module
;
6506 struct replmd_private
*replmd_private
=
6507 talloc_get_type(ldb_module_get_private(module
), struct replmd_private
);
6508 struct ldb_context
*ldb
;
6510 ldb
= ldb_module_get_ctx(module
);
6512 DEBUG(4,("linked_attributes_count=%u\n", ar
->objs
->linked_attributes_count
));
6514 /* save away the linked attributes for the end of the transaction */
6515 for (i
= 0; i
< ar
->objs
->linked_attributes_count
; i
++) {
6516 struct la_entry
*la_entry
;
6518 if (replmd_private
->la_ctx
== NULL
) {
6519 replmd_private
->la_ctx
= talloc_new(replmd_private
);
6521 la_entry
= talloc(replmd_private
->la_ctx
, struct la_entry
);
6522 if (la_entry
== NULL
) {
6524 return LDB_ERR_OPERATIONS_ERROR
;
6526 la_entry
->la
= talloc(la_entry
, struct drsuapi_DsReplicaLinkedAttribute
);
6527 if (la_entry
->la
== NULL
) {
6528 talloc_free(la_entry
);
6530 return LDB_ERR_OPERATIONS_ERROR
;
6532 *la_entry
->la
= ar
->objs
->linked_attributes
[i
];
6533 la_entry
->dsdb_repl_flags
= ar
->objs
->dsdb_repl_flags
;
6535 /* we need to steal the non-scalars so they stay
6536 around until the end of the transaction */
6537 talloc_steal(la_entry
->la
, la_entry
->la
->identifier
);
6538 talloc_steal(la_entry
->la
, la_entry
->la
->value
.blob
);
6540 ret
= replmd_verify_linked_attribute(ar
, la_entry
);
6542 if (ret
!= LDB_SUCCESS
) {
6546 DLIST_ADD(replmd_private
->la_list
, la_entry
);
6552 static int replmd_replicated_uptodate_vector(struct replmd_replicated_request
*ar
);
6554 static int replmd_replicated_apply_next(struct replmd_replicated_request
*ar
)
6556 struct ldb_context
*ldb
;
6560 struct ldb_request
*search_req
;
6561 static const char *attrs
[] = { "repsFrom", "replUpToDateVector",
6562 "parentGUID", "instanceType",
6563 "replPropertyMetaData", "nTSecurityDescriptor",
6564 "isDeleted", NULL
};
6565 struct GUID_txt_buf guid_str_buf
;
6567 if (ar
->index_current
>= ar
->objs
->num_objects
) {
6570 * Now that we've applied all the objects, check the new linked
6571 * attributes and store them (we apply them in .prepare_commit)
6573 ret
= replmd_store_linked_attributes(ar
);
6575 if (ret
!= LDB_SUCCESS
) {
6579 /* done applying objects, move on to the next stage */
6580 return replmd_replicated_uptodate_vector(ar
);
6583 ldb
= ldb_module_get_ctx(ar
->module
);
6584 ar
->search_msg
= NULL
;
6585 ar
->isDeleted
= false;
6587 tmp_str
= GUID_buf_string(&ar
->objs
->objects
[ar
->index_current
].object_guid
,
6590 filter
= talloc_asprintf(ar
, "(objectGUID=%s)", tmp_str
);
6591 if (!filter
) return replmd_replicated_request_werror(ar
, WERR_NOT_ENOUGH_MEMORY
);
6593 ret
= ldb_build_search_req(&search_req
,
6596 ar
->objs
->partition_dn
,
6602 replmd_replicated_apply_search_callback
,
6604 LDB_REQ_SET_LOCATION(search_req
);
6606 ret
= dsdb_request_add_controls(search_req
, DSDB_SEARCH_SHOW_RECYCLED
);
6608 if (ret
!= LDB_SUCCESS
) {
6612 return ldb_next_request(ar
->module
, search_req
);
6616 * This is essentially a wrapper for replmd_replicated_apply_next()
6618 * This is needed to ensure that both codepaths call this handler.
6620 static int replmd_replicated_apply_isDeleted(struct replmd_replicated_request
*ar
)
6622 struct ldb_dn
*deleted_objects_dn
;
6623 struct ldb_message
*msg
= ar
->objs
->objects
[ar
->index_current
].msg
;
6624 int ret
= dsdb_get_deleted_objects_dn(ldb_module_get_ctx(ar
->module
), msg
, msg
->dn
,
6625 &deleted_objects_dn
);
6626 if (ar
->isDeleted
&& (ret
!= LDB_SUCCESS
|| ldb_dn_compare(msg
->dn
, deleted_objects_dn
) != 0)) {
6628 * Do a delete here again, so that if there is
6629 * anything local that conflicts with this
6630 * object being deleted, it is removed. This
6631 * includes links. See MS-DRSR 4.1.10.6.9
6634 * If the object is already deleted, and there
6635 * is no more work required, it doesn't do
6639 /* This has been updated to point to the DN we eventually did the modify on */
6641 struct ldb_request
*del_req
;
6642 struct ldb_result
*res
;
6644 TALLOC_CTX
*tmp_ctx
= talloc_new(ar
);
6646 ret
= ldb_oom(ldb_module_get_ctx(ar
->module
));
6650 res
= talloc_zero(tmp_ctx
, struct ldb_result
);
6652 ret
= ldb_oom(ldb_module_get_ctx(ar
->module
));
6653 talloc_free(tmp_ctx
);
6657 /* Build a delete request, which hopefully will artually turn into nothing */
6658 ret
= ldb_build_del_req(&del_req
, ldb_module_get_ctx(ar
->module
), tmp_ctx
,
6662 ldb_modify_default_callback
,
6664 LDB_REQ_SET_LOCATION(del_req
);
6665 if (ret
!= LDB_SUCCESS
) {
6666 talloc_free(tmp_ctx
);
6671 * This is the guts of the call, call back
6672 * into our delete code, but setting the
6673 * re_delete flag so we delete anything that
6674 * shouldn't be there on a deleted or recycled
6677 ret
= replmd_delete_internals(ar
->module
, del_req
, true);
6678 if (ret
== LDB_SUCCESS
) {
6679 ret
= ldb_wait(del_req
->handle
, LDB_WAIT_ALL
);
6682 talloc_free(tmp_ctx
);
6683 if (ret
!= LDB_SUCCESS
) {
6688 ar
->index_current
++;
6689 return replmd_replicated_apply_next(ar
);
6692 static int replmd_replicated_uptodate_modify_callback(struct ldb_request
*req
,
6693 struct ldb_reply
*ares
)
6695 struct ldb_context
*ldb
;
6696 struct replmd_replicated_request
*ar
= talloc_get_type(req
->context
,
6697 struct replmd_replicated_request
);
6698 ldb
= ldb_module_get_ctx(ar
->module
);
6701 return ldb_module_done(ar
->req
, NULL
, NULL
,
6702 LDB_ERR_OPERATIONS_ERROR
);
6704 if (ares
->error
!= LDB_SUCCESS
) {
6705 return ldb_module_done(ar
->req
, ares
->controls
,
6706 ares
->response
, ares
->error
);
6709 if (ares
->type
!= LDB_REPLY_DONE
) {
6710 ldb_asprintf_errstring(ldb
, "Invalid LDB reply type %d", ares
->type
);
6711 return ldb_module_done(ar
->req
, NULL
, NULL
,
6712 LDB_ERR_OPERATIONS_ERROR
);
6717 return ldb_module_done(ar
->req
, NULL
, NULL
, LDB_SUCCESS
);
6720 static int replmd_replicated_uptodate_modify(struct replmd_replicated_request
*ar
)
6722 struct ldb_context
*ldb
;
6723 struct ldb_request
*change_req
;
6724 enum ndr_err_code ndr_err
;
6725 struct ldb_message
*msg
;
6726 struct replUpToDateVectorBlob ouv
;
6727 const struct ldb_val
*ouv_value
;
6728 const struct drsuapi_DsReplicaCursor2CtrEx
*ruv
;
6729 struct replUpToDateVectorBlob nuv
;
6730 struct ldb_val nuv_value
;
6731 struct ldb_message_element
*nuv_el
= NULL
;
6732 struct ldb_message_element
*orf_el
= NULL
;
6733 struct repsFromToBlob nrf
;
6734 struct ldb_val
*nrf_value
= NULL
;
6735 struct ldb_message_element
*nrf_el
= NULL
;
6739 time_t t
= time(NULL
);
6742 uint32_t instanceType
;
6744 ldb
= ldb_module_get_ctx(ar
->module
);
6745 ruv
= ar
->objs
->uptodateness_vector
;
6751 unix_to_nt_time(&now
, t
);
6753 if (ar
->search_msg
== NULL
) {
6754 /* this happens for a REPL_OBJ call where we are
6755 creating the target object by replicating it. The
6756 subdomain join code does this for the partition DN
6758 DEBUG(4,(__location__
": Skipping UDV and repsFrom update as no target DN\n"));
6759 return ldb_module_done(ar
->req
, NULL
, NULL
, LDB_SUCCESS
);
6762 instanceType
= ldb_msg_find_attr_as_uint(ar
->search_msg
, "instanceType", 0);
6763 if (! (instanceType
& INSTANCE_TYPE_IS_NC_HEAD
)) {
6764 DEBUG(4,(__location__
": Skipping UDV and repsFrom update as not NC root: %s\n",
6765 ldb_dn_get_linearized(ar
->search_msg
->dn
)));
6766 return ldb_module_done(ar
->req
, NULL
, NULL
, LDB_SUCCESS
);
6770 * first create the new replUpToDateVector
6772 ouv_value
= ldb_msg_find_ldb_val(ar
->search_msg
, "replUpToDateVector");
6774 ndr_err
= ndr_pull_struct_blob(ouv_value
, ar
, &ouv
,
6775 (ndr_pull_flags_fn_t
)ndr_pull_replUpToDateVectorBlob
);
6776 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err
)) {
6777 NTSTATUS nt_status
= ndr_map_error2ntstatus(ndr_err
);
6778 return replmd_replicated_request_werror(ar
, ntstatus_to_werror(nt_status
));
6781 if (ouv
.version
!= 2) {
6782 return replmd_replicated_request_werror(ar
, WERR_DS_DRA_INTERNAL_ERROR
);
6787 * the new uptodateness vector will at least
6788 * contain 1 entry, one for the source_dsa
6790 * plus optional values from our old vector and the one from the source_dsa
6792 nuv
.ctr
.ctr2
.count
= ouv
.ctr
.ctr2
.count
;
6793 if (ruv
) nuv
.ctr
.ctr2
.count
+= ruv
->count
;
6794 nuv
.ctr
.ctr2
.cursors
= talloc_array(ar
,
6795 struct drsuapi_DsReplicaCursor2
,
6796 nuv
.ctr
.ctr2
.count
);
6797 if (!nuv
.ctr
.ctr2
.cursors
) return replmd_replicated_request_werror(ar
, WERR_NOT_ENOUGH_MEMORY
);
6799 /* first copy the old vector */
6800 for (i
=0; i
< ouv
.ctr
.ctr2
.count
; i
++) {
6801 nuv
.ctr
.ctr2
.cursors
[ni
] = ouv
.ctr
.ctr2
.cursors
[i
];
6805 /* merge in the source_dsa vector is available */
6806 for (i
=0; (ruv
&& i
< ruv
->count
); i
++) {
6809 if (GUID_equal(&ruv
->cursors
[i
].source_dsa_invocation_id
,
6810 &ar
->our_invocation_id
)) {
6814 for (j
=0; j
< ni
; j
++) {
6815 if (!GUID_equal(&ruv
->cursors
[i
].source_dsa_invocation_id
,
6816 &nuv
.ctr
.ctr2
.cursors
[j
].source_dsa_invocation_id
)) {
6822 if (ruv
->cursors
[i
].highest_usn
> nuv
.ctr
.ctr2
.cursors
[j
].highest_usn
) {
6823 nuv
.ctr
.ctr2
.cursors
[j
] = ruv
->cursors
[i
];
6828 if (found
) continue;
6830 /* if it's not there yet, add it */
6831 nuv
.ctr
.ctr2
.cursors
[ni
] = ruv
->cursors
[i
];
6836 * finally correct the size of the cursors array
6838 nuv
.ctr
.ctr2
.count
= ni
;
6843 TYPESAFE_QSORT(nuv
.ctr
.ctr2
.cursors
, nuv
.ctr
.ctr2
.count
, drsuapi_DsReplicaCursor2_compare
);
6846 * create the change ldb_message
6848 msg
= ldb_msg_new(ar
);
6849 if (!msg
) return replmd_replicated_request_werror(ar
, WERR_NOT_ENOUGH_MEMORY
);
6850 msg
->dn
= ar
->search_msg
->dn
;
6852 ndr_err
= ndr_push_struct_blob(&nuv_value
, msg
, &nuv
,
6853 (ndr_push_flags_fn_t
)ndr_push_replUpToDateVectorBlob
);
6854 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err
)) {
6855 NTSTATUS nt_status
= ndr_map_error2ntstatus(ndr_err
);
6856 return replmd_replicated_request_werror(ar
, ntstatus_to_werror(nt_status
));
6858 ret
= ldb_msg_add_value(msg
, "replUpToDateVector", &nuv_value
, &nuv_el
);
6859 if (ret
!= LDB_SUCCESS
) {
6860 return replmd_replicated_request_error(ar
, ret
);
6862 nuv_el
->flags
= LDB_FLAG_MOD_REPLACE
;
6865 * now create the new repsFrom value from the given repsFromTo1 structure
6869 nrf
.ctr
.ctr1
= *ar
->objs
->source_dsa
;
6870 nrf
.ctr
.ctr1
.last_attempt
= now
;
6871 nrf
.ctr
.ctr1
.last_success
= now
;
6872 nrf
.ctr
.ctr1
.result_last_attempt
= WERR_OK
;
6875 * first see if we already have a repsFrom value for the current source dsa
6876 * if so we'll later replace this value
6878 orf_el
= ldb_msg_find_element(ar
->search_msg
, "repsFrom");
6880 for (i
=0; i
< orf_el
->num_values
; i
++) {
6881 struct repsFromToBlob
*trf
;
6883 trf
= talloc(ar
, struct repsFromToBlob
);
6884 if (!trf
) return replmd_replicated_request_werror(ar
, WERR_NOT_ENOUGH_MEMORY
);
6886 ndr_err
= ndr_pull_struct_blob(&orf_el
->values
[i
], trf
, trf
,
6887 (ndr_pull_flags_fn_t
)ndr_pull_repsFromToBlob
);
6888 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err
)) {
6889 NTSTATUS nt_status
= ndr_map_error2ntstatus(ndr_err
);
6890 return replmd_replicated_request_werror(ar
, ntstatus_to_werror(nt_status
));
6893 if (trf
->version
!= 1) {
6894 return replmd_replicated_request_werror(ar
, WERR_DS_DRA_INTERNAL_ERROR
);
6898 * we compare the source dsa objectGUID not the invocation_id
6899 * because we want only one repsFrom value per source dsa
6900 * and when the invocation_id of the source dsa has changed we don't need
6901 * the old repsFrom with the old invocation_id
6903 if (!GUID_equal(&trf
->ctr
.ctr1
.source_dsa_obj_guid
,
6904 &ar
->objs
->source_dsa
->source_dsa_obj_guid
)) {
6910 nrf_value
= &orf_el
->values
[i
];
6915 * copy over all old values to the new ldb_message
6917 ret
= ldb_msg_add_empty(msg
, "repsFrom", 0, &nrf_el
);
6918 if (ret
!= LDB_SUCCESS
) return replmd_replicated_request_error(ar
, ret
);
6923 * if we haven't found an old repsFrom value for the current source dsa
6924 * we'll add a new value
6927 struct ldb_val zero_value
;
6928 ZERO_STRUCT(zero_value
);
6929 ret
= ldb_msg_add_value(msg
, "repsFrom", &zero_value
, &nrf_el
);
6930 if (ret
!= LDB_SUCCESS
) return replmd_replicated_request_error(ar
, ret
);
6932 nrf_value
= &nrf_el
->values
[nrf_el
->num_values
- 1];
6935 /* we now fill the value which is already attached to ldb_message */
6936 ndr_err
= ndr_push_struct_blob(nrf_value
, msg
,
6938 (ndr_push_flags_fn_t
)ndr_push_repsFromToBlob
);
6939 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err
)) {
6940 NTSTATUS nt_status
= ndr_map_error2ntstatus(ndr_err
);
6941 return replmd_replicated_request_werror(ar
, ntstatus_to_werror(nt_status
));
6945 * the ldb_message_element for the attribute, has all the old values and the new one
6946 * so we'll replace the whole attribute with all values
6948 nrf_el
->flags
= LDB_FLAG_MOD_REPLACE
;
6950 if (CHECK_DEBUGLVL(4)) {
6951 char *s
= ldb_ldif_message_redacted_string(ldb
, ar
,
6952 LDB_CHANGETYPE_MODIFY
,
6954 DEBUG(4, ("DRS replication uptodate modify message:\n%s\n", s
));
6958 /* prepare the ldb_modify() request */
6959 ret
= ldb_build_mod_req(&change_req
,
6965 replmd_replicated_uptodate_modify_callback
,
6967 LDB_REQ_SET_LOCATION(change_req
);
6968 if (ret
!= LDB_SUCCESS
) return replmd_replicated_request_error(ar
, ret
);
6970 return ldb_next_request(ar
->module
, change_req
);
6973 static int replmd_replicated_uptodate_search_callback(struct ldb_request
*req
,
6974 struct ldb_reply
*ares
)
6976 struct replmd_replicated_request
*ar
= talloc_get_type(req
->context
,
6977 struct replmd_replicated_request
);
6981 return ldb_module_done(ar
->req
, NULL
, NULL
,
6982 LDB_ERR_OPERATIONS_ERROR
);
6984 if (ares
->error
!= LDB_SUCCESS
&&
6985 ares
->error
!= LDB_ERR_NO_SUCH_OBJECT
) {
6986 return ldb_module_done(ar
->req
, ares
->controls
,
6987 ares
->response
, ares
->error
);
6990 switch (ares
->type
) {
6991 case LDB_REPLY_ENTRY
:
6992 ar
->search_msg
= talloc_steal(ar
, ares
->message
);
6995 case LDB_REPLY_REFERRAL
:
6996 /* we ignore referrals */
6999 case LDB_REPLY_DONE
:
7000 ret
= replmd_replicated_uptodate_modify(ar
);
7001 if (ret
!= LDB_SUCCESS
) {
7002 return ldb_module_done(ar
->req
, NULL
, NULL
, ret
);
7011 static int replmd_replicated_uptodate_vector(struct replmd_replicated_request
*ar
)
7013 struct ldb_context
*ldb
= ldb_module_get_ctx(ar
->module
);
7014 struct replmd_private
*replmd_private
=
7015 talloc_get_type_abort(ldb_module_get_private(ar
->module
),
7016 struct replmd_private
);
7018 static const char *attrs
[] = {
7019 "replUpToDateVector",
7024 struct ldb_request
*search_req
;
7026 ar
->search_msg
= NULL
;
7029 * Let the caller know that we did an originating updates
7031 ar
->objs
->originating_updates
= replmd_private
->originating_updates
;
7033 ret
= ldb_build_search_req(&search_req
,
7036 ar
->objs
->partition_dn
,
7042 replmd_replicated_uptodate_search_callback
,
7044 LDB_REQ_SET_LOCATION(search_req
);
7045 if (ret
!= LDB_SUCCESS
) return replmd_replicated_request_error(ar
, ret
);
7047 return ldb_next_request(ar
->module
, search_req
);
7052 static int replmd_extended_replicated_objects(struct ldb_module
*module
, struct ldb_request
*req
)
7054 struct ldb_context
*ldb
;
7055 struct dsdb_extended_replicated_objects
*objs
;
7056 struct replmd_replicated_request
*ar
;
7057 struct ldb_control
**ctrls
;
7060 ldb
= ldb_module_get_ctx(module
);
7062 ldb_debug(ldb
, LDB_DEBUG_TRACE
, "replmd_extended_replicated_objects\n");
7064 objs
= talloc_get_type(req
->op
.extended
.data
, struct dsdb_extended_replicated_objects
);
7066 ldb_debug(ldb
, LDB_DEBUG_FATAL
, "replmd_extended_replicated_objects: invalid extended data\n");
7067 return LDB_ERR_PROTOCOL_ERROR
;
7070 if (objs
->version
!= DSDB_EXTENDED_REPLICATED_OBJECTS_VERSION
) {
7071 ldb_debug(ldb
, LDB_DEBUG_FATAL
, "replmd_extended_replicated_objects: extended data invalid version [%u != %u]\n",
7072 objs
->version
, DSDB_EXTENDED_REPLICATED_OBJECTS_VERSION
);
7073 return LDB_ERR_PROTOCOL_ERROR
;
7076 ar
= replmd_ctx_init(module
, req
);
7078 return LDB_ERR_OPERATIONS_ERROR
;
7080 /* Set the flags to have the replmd_op_callback run over the full set of objects */
7081 ar
->apply_mode
= true;
7083 ar
->schema
= dsdb_get_schema(ldb
, ar
);
7085 ldb_debug_set(ldb
, LDB_DEBUG_FATAL
, "replmd_ctx_init: no loaded schema found\n");
7087 DEBUG(0,(__location__
": %s\n", ldb_errstring(ldb
)));
7088 return LDB_ERR_CONSTRAINT_VIOLATION
;
7091 ctrls
= req
->controls
;
7093 if (req
->controls
) {
7094 req
->controls
= talloc_memdup(ar
, req
->controls
,
7095 talloc_get_size(req
->controls
));
7096 if (!req
->controls
) return replmd_replicated_request_werror(ar
, WERR_NOT_ENOUGH_MEMORY
);
7099 ret
= ldb_request_add_control(req
, DSDB_CONTROL_REPLICATED_UPDATE_OID
, false, NULL
);
7100 if (ret
!= LDB_SUCCESS
) {
7104 /* If this change contained linked attributes in the body
7105 * (rather than in the links section) we need to update
7106 * backlinks in linked_attributes */
7107 ret
= ldb_request_add_control(req
, DSDB_CONTROL_APPLY_LINKS
, false, NULL
);
7108 if (ret
!= LDB_SUCCESS
) {
7112 ar
->controls
= req
->controls
;
7113 req
->controls
= ctrls
;
7115 return replmd_replicated_apply_next(ar
);
7119 * Checks how to handle an missing target - either we need to fail the
7120 * replication and retry with GET_TGT, ignore the link and continue, or try to
7121 * add a partial link to an unknown target.
7123 static int replmd_allow_missing_target(struct ldb_module
*module
,
7124 TALLOC_CTX
*mem_ctx
,
7125 struct ldb_dn
*target_dn
,
7126 struct ldb_dn
*source_dn
,
7129 uint32_t dsdb_repl_flags
,
7131 const char * missing_str
)
7133 struct ldb_context
*ldb
= ldb_module_get_ctx(module
);
7137 * we may not be able to resolve link targets properly when
7138 * dealing with subsets of objects, e.g. the source is a
7139 * critical object and the target isn't
7142 * When we implement Trusted Domains we need to consider
7143 * whether they get treated as an incomplete replica here or not
7145 if (dsdb_repl_flags
& DSDB_REPL_FLAG_OBJECT_SUBSET
) {
7148 * Ignore the link. We don't increase the highwater-mark in
7149 * the object subset cases, so subsequent replications should
7150 * resolve any missing links
7152 DEBUG(2, ("%s target %s linked from %s\n", missing_str
,
7153 ldb_dn_get_linearized(target_dn
),
7154 ldb_dn_get_linearized(source_dn
)));
7155 *ignore_link
= true;
7159 if (dsdb_repl_flags
& DSDB_REPL_FLAG_TARGETS_UPTODATE
) {
7162 * target should already be up-to-date so there's no point in
7163 * retrying. This could be due to bad timing, or if a target
7164 * on a one-way link was deleted. We ignore the link rather
7165 * than failing the replication cycle completely
7167 *ignore_link
= true;
7168 DBG_WARNING("%s is %s but up to date. Ignoring link from %s\n",
7169 ldb_dn_get_linearized(target_dn
), missing_str
,
7170 ldb_dn_get_linearized(source_dn
));
7174 is_in_same_nc
= dsdb_objects_have_same_nc(ldb
,
7178 if (is_in_same_nc
) {
7179 /* fail the replication and retry with GET_TGT */
7180 ldb_asprintf_errstring(ldb
, "%s target %s GUID %s linked from %s\n",
7182 ldb_dn_get_linearized(target_dn
),
7183 GUID_string(mem_ctx
, guid
),
7184 ldb_dn_get_linearized(source_dn
));
7185 return LDB_ERR_NO_SUCH_OBJECT
;
7189 * The target of the cross-partition link is missing. Continue
7190 * and try to at least add the forward-link. This isn't great,
7191 * but a partial link can be fixed by dbcheck, so it's better
7192 * than dropping the link completely.
7194 *ignore_link
= false;
7196 if (is_obj_commit
) {
7199 * Only log this when we're actually committing the objects.
7200 * This avoids spurious logs, i.e. if we're just verifying the
7201 * received link during a join.
7203 DBG_WARNING("%s cross-partition target %s linked from %s\n",
7204 missing_str
, ldb_dn_get_linearized(target_dn
),
7205 ldb_dn_get_linearized(source_dn
));
7212 * Checks that the target object for a linked attribute exists.
7213 * @param guid returns the target object's GUID (is returned)if it exists)
7214 * @param ignore_link set to true if the linked attribute should be ignored
7215 * (i.e. the target doesn't exist, but that it's OK to skip the link)
7217 static int replmd_check_target_exists(struct ldb_module
*module
,
7218 struct dsdb_dn
*dsdb_dn
,
7219 struct la_entry
*la_entry
,
7220 struct ldb_dn
*source_dn
,
7225 struct drsuapi_DsReplicaLinkedAttribute
*la
= la_entry
->la
;
7226 struct ldb_context
*ldb
= ldb_module_get_ctx(module
);
7227 struct ldb_result
*target_res
;
7228 TALLOC_CTX
*tmp_ctx
= talloc_new(la_entry
);
7229 const char *attrs
[] = { "isDeleted", "isRecycled", NULL
};
7232 enum deletion_state target_deletion_state
= OBJECT_REMOVED
;
7233 bool active
= (la
->flags
& DRSUAPI_DS_LINKED_ATTRIBUTE_FLAG_ACTIVE
) ? true : false;
7235 *ignore_link
= false;
7236 ntstatus
= dsdb_get_extended_dn_guid(dsdb_dn
->dn
, guid
, "GUID");
7238 if (!NT_STATUS_IS_OK(ntstatus
) && !active
) {
7241 * This strange behaviour (allowing a NULL/missing
7242 * GUID) originally comes from:
7244 * commit e3054ce0fe0f8f62d2f5b2a77893e7a1479128bd
7245 * Author: Andrew Tridgell <tridge@samba.org>
7246 * Date: Mon Dec 21 21:21:55 2009 +1100
7248 * s4-drs: cope better with NULL GUIDS from DRS
7250 * It is valid to get a NULL GUID over DRS for a deleted forward link. We
7251 * need to match by DN if possible when seeing if we should update an
7254 * Pair-Programmed-With: Andrew Bartlett <abartlet@samba.org>
7256 ret
= dsdb_module_search_dn(module
, tmp_ctx
, &target_res
,
7258 DSDB_FLAG_NEXT_MODULE
|
7259 DSDB_SEARCH_SHOW_RECYCLED
|
7260 DSDB_SEARCH_SEARCH_ALL_PARTITIONS
|
7261 DSDB_SEARCH_SHOW_DN_IN_STORAGE_FORMAT
,
7263 } else if (!NT_STATUS_IS_OK(ntstatus
)) {
7264 ldb_asprintf_errstring(ldb
, "Failed to find GUID in linked attribute 0x%x blob for %s from %s",
7266 ldb_dn_get_linearized(dsdb_dn
->dn
),
7267 ldb_dn_get_linearized(source_dn
));
7268 talloc_free(tmp_ctx
);
7269 return LDB_ERR_OPERATIONS_ERROR
;
7271 ret
= dsdb_module_search(module
, tmp_ctx
, &target_res
,
7272 NULL
, LDB_SCOPE_SUBTREE
,
7274 DSDB_FLAG_NEXT_MODULE
|
7275 DSDB_SEARCH_SHOW_RECYCLED
|
7276 DSDB_SEARCH_SEARCH_ALL_PARTITIONS
|
7277 DSDB_SEARCH_SHOW_DN_IN_STORAGE_FORMAT
,
7280 GUID_string(tmp_ctx
, guid
));
7283 if (ret
!= LDB_SUCCESS
) {
7284 ldb_asprintf_errstring(ldb
, "Failed to re-resolve GUID %s: %s\n",
7285 GUID_string(tmp_ctx
, guid
),
7286 ldb_errstring(ldb
));
7287 talloc_free(tmp_ctx
);
7291 if (target_res
->count
== 0) {
7294 * target object is unknown. Check whether to ignore the link,
7295 * fail the replication, or add a partial link
7297 ret
= replmd_allow_missing_target(module
, tmp_ctx
, dsdb_dn
->dn
,
7298 source_dn
, is_obj_commit
, guid
,
7299 la_entry
->dsdb_repl_flags
,
7300 ignore_link
, "Unknown");
7302 } else if (target_res
->count
!= 1) {
7303 ldb_asprintf_errstring(ldb
, "More than one object found matching objectGUID %s\n",
7304 GUID_string(tmp_ctx
, guid
));
7305 ret
= LDB_ERR_OPERATIONS_ERROR
;
7307 struct ldb_message
*target_msg
= target_res
->msgs
[0];
7309 dsdb_dn
->dn
= talloc_steal(dsdb_dn
, target_msg
->dn
);
7311 /* Get the object's state (i.e. Not Deleted, Tombstone, etc) */
7312 replmd_deletion_state(module
, target_msg
,
7313 &target_deletion_state
, NULL
);
7316 * Check for deleted objects as per MS-DRSR 4.1.10.6.14
7317 * ProcessLinkValue(). Link updates should not be sent for
7318 * recycled and tombstone objects (deleting the links should
7319 * happen when we delete the object). This probably means our
7320 * copy of the target object isn't up to date.
7322 if (target_deletion_state
>= OBJECT_RECYCLED
) {
7325 * target object is deleted. Check whether to ignore the
7326 * link, fail the replication, or add a partial link
7328 ret
= replmd_allow_missing_target(module
, tmp_ctx
,
7329 dsdb_dn
->dn
, source_dn
,
7330 is_obj_commit
, guid
,
7331 la_entry
->dsdb_repl_flags
,
7332 ignore_link
, "Deleted");
7336 talloc_free(tmp_ctx
);
7341 * Extracts the key details about the source/target object for a
7342 * linked-attribute entry.
7343 * This returns the following details:
7344 * @param ret_attr the schema details for the linked attribute
7345 * @param source_msg the search result for the source object
7346 * @param target_dsdb_dn the unpacked DN info for the target object
7348 static int replmd_extract_la_entry_details(struct ldb_module
*module
,
7349 struct la_entry
*la_entry
,
7350 TALLOC_CTX
*mem_ctx
,
7351 const struct dsdb_attribute
**ret_attr
,
7352 struct ldb_message
**source_msg
,
7353 struct dsdb_dn
**target_dsdb_dn
)
7355 struct drsuapi_DsReplicaLinkedAttribute
*la
= la_entry
->la
;
7356 struct ldb_context
*ldb
= ldb_module_get_ctx(module
);
7357 const struct dsdb_schema
*schema
= dsdb_get_schema(ldb
, mem_ctx
);
7359 const struct dsdb_attribute
*attr
;
7361 struct ldb_result
*res
;
7362 const char *attrs
[4];
7365 linked_attributes[0]:
7366 &objs->linked_attributes[i]: struct drsuapi_DsReplicaLinkedAttribute
7368 identifier: struct drsuapi_DsReplicaObjectIdentifier
7369 __ndr_size : 0x0000003a (58)
7370 __ndr_size_sid : 0x00000000 (0)
7371 guid : 8e95b6a9-13dd-4158-89db-3220a5be5cc7
7373 __ndr_size_dn : 0x00000000 (0)
7375 attid : DRSUAPI_ATTID_member (0x1F)
7376 value: struct drsuapi_DsAttributeValue
7377 __ndr_size : 0x0000007e (126)
7379 blob : DATA_BLOB length=126
7380 flags : 0x00000001 (1)
7381 1: DRSUAPI_DS_LINKED_ATTRIBUTE_FLAG_ACTIVE
7382 originating_add_time : Wed Sep 2 22:20:01 2009 EST
7383 meta_data: struct drsuapi_DsReplicaMetaData
7384 version : 0x00000015 (21)
7385 originating_change_time : Wed Sep 2 23:39:07 2009 EST
7386 originating_invocation_id: 794640f3-18cf-40ee-a211-a93992b67a64
7387 originating_usn : 0x000000000001e19c (123292)
7389 (for cases where the link is to a normal DN)
7390 &target: struct drsuapi_DsReplicaObjectIdentifier3
7391 __ndr_size : 0x0000007e (126)
7392 __ndr_size_sid : 0x0000001c (28)
7393 guid : 7639e594-db75-4086-b0d4-67890ae46031
7394 sid : S-1-5-21-2848215498-2472035911-1947525656-19924
7395 __ndr_size_dn : 0x00000022 (34)
7396 dn : 'CN=UOne,OU=TestOU,DC=vsofs8,DC=com'
7399 /* find the attribute being modified */
7400 attr
= dsdb_attribute_by_attributeID_id(schema
, la
->attid
);
7402 struct GUID_txt_buf guid_str
;
7403 ldb_asprintf_errstring(ldb
, "Unable to find attributeID 0x%x for link on <GUID=%s>",
7405 GUID_buf_string(&la
->identifier
->guid
,
7407 return LDB_ERR_OPERATIONS_ERROR
;
7410 attrs
[0] = attr
->lDAPDisplayName
;
7411 attrs
[1] = "isDeleted";
7412 attrs
[2] = "isRecycled";
7416 * get the existing message from the db for the object with
7417 * this GUID, returning attribute being modified. We will then
7418 * use this msg as the basis for a modify call
7420 ret
= dsdb_module_search(module
, mem_ctx
, &res
, NULL
, LDB_SCOPE_SUBTREE
, attrs
,
7421 DSDB_FLAG_NEXT_MODULE
|
7422 DSDB_SEARCH_SEARCH_ALL_PARTITIONS
|
7423 DSDB_SEARCH_SHOW_RECYCLED
|
7424 DSDB_SEARCH_SHOW_DN_IN_STORAGE_FORMAT
|
7425 DSDB_SEARCH_REVEAL_INTERNALS
,
7427 "objectGUID=%s", GUID_string(mem_ctx
, &la
->identifier
->guid
));
7428 if (ret
!= LDB_SUCCESS
) {
7431 if (res
->count
!= 1) {
7432 ldb_asprintf_errstring(ldb
, "DRS linked attribute for GUID %s - DN not found",
7433 GUID_string(mem_ctx
, &la
->identifier
->guid
));
7434 return LDB_ERR_NO_SUCH_OBJECT
;
7437 *source_msg
= res
->msgs
[0];
7439 /* the value blob for the attribute holds the target object DN */
7440 status
= dsdb_dn_la_from_blob(ldb
, attr
, schema
, mem_ctx
, la
->value
.blob
, target_dsdb_dn
);
7441 if (!W_ERROR_IS_OK(status
)) {
7442 ldb_asprintf_errstring(ldb
, "Failed to parsed linked attribute blob for %s on %s - %s\n",
7443 attr
->lDAPDisplayName
,
7444 ldb_dn_get_linearized(res
->msgs
[0]->dn
),
7445 win_errstr(status
));
7446 return LDB_ERR_OPERATIONS_ERROR
;
7455 * Verifies the source and target objects are known for a linked attribute
7457 static int replmd_verify_linked_attribute(struct replmd_replicated_request
*ar
,
7458 struct la_entry
*la
)
7460 int ret
= LDB_SUCCESS
;
7461 TALLOC_CTX
*tmp_ctx
= talloc_new(la
);
7462 struct ldb_module
*module
= ar
->module
;
7463 struct ldb_message
*src_msg
;
7464 const struct dsdb_attribute
*attr
;
7465 struct dsdb_dn
*tgt_dsdb_dn
;
7466 struct GUID guid
= GUID_zero();
7469 ret
= replmd_extract_la_entry_details(module
, la
, tmp_ctx
, &attr
,
7470 &src_msg
, &tgt_dsdb_dn
);
7473 * When we fail to find the source object, the error code we pass
7474 * back here is really important. It flags back to the callers to
7475 * retry this request with DRSUAPI_DRS_GET_ANC. This case should
7476 * never happen if we're replicating from a Samba DC, but it is
7477 * needed to talk to a Windows DC
7479 if (ret
== LDB_ERR_NO_SUCH_OBJECT
) {
7480 ret
= replmd_replicated_request_werror(ar
, WERR_DS_DRA_MISSING_PARENT
);
7483 if (ret
!= LDB_SUCCESS
) {
7484 talloc_free(tmp_ctx
);
7489 * We can skip the target object checks if we're only syncing critical
7490 * objects, or we know the target is up-to-date. If either case, we
7491 * still continue even if the target doesn't exist
7493 if ((la
->dsdb_repl_flags
& (DSDB_REPL_FLAG_OBJECT_SUBSET
|
7494 DSDB_REPL_FLAG_TARGETS_UPTODATE
)) == 0) {
7496 ret
= replmd_check_target_exists(module
, tgt_dsdb_dn
, la
,
7497 src_msg
->dn
, false, &guid
,
7502 * When we fail to find the target object, the error code we pass
7503 * back here is really important. It flags back to the callers to
7504 * retry this request with DRSUAPI_DRS_GET_TGT
7506 if (ret
== LDB_ERR_NO_SUCH_OBJECT
) {
7507 ret
= replmd_replicated_request_werror(ar
, WERR_DS_DRA_RECYCLED_TARGET
);
7510 talloc_free(tmp_ctx
);
7515 * Finds the current active Parsed-DN value for a single-valued linked
7516 * attribute, if one exists.
7517 * @param ret_pdn assigned the active Parsed-DN, or NULL if none was found
7518 * @returns LDB_SUCCESS (regardless of whether a match was found), unless
7521 static int replmd_get_active_singleval_link(struct ldb_module
*module
,
7522 TALLOC_CTX
*mem_ctx
,
7523 struct parsed_dn pdn_list
[],
7525 const struct dsdb_attribute
*attr
,
7526 struct parsed_dn
**ret_pdn
)
7532 if (!(attr
->ldb_schema_attribute
->flags
& LDB_ATTR_FLAG_SINGLE_VALUE
)) {
7534 /* nothing to do for multi-valued linked attributes */
7538 for (i
= 0; i
< count
; i
++) {
7539 int ret
= LDB_SUCCESS
;
7540 struct parsed_dn
*pdn
= &pdn_list
[i
];
7542 /* skip any inactive links */
7543 if (dsdb_dn_is_deleted_val(pdn
->v
)) {
7547 /* we've found an active value for this attribute */
7550 if (pdn
->dsdb_dn
== NULL
) {
7551 struct ldb_context
*ldb
= ldb_module_get_ctx(module
);
7553 ret
= really_parse_trusted_dn(mem_ctx
, ldb
, pdn
,
7554 attr
->syntax
->ldap_oid
);
7560 /* no active link found */
7565 * @returns true if the replication linked attribute info is newer than we
7566 * already have in our DB
7567 * @param pdn the existing linked attribute info in our DB
7568 * @param la the new linked attribute info received during replication
7570 static bool replmd_link_update_is_newer(struct parsed_dn
*pdn
,
7571 struct drsuapi_DsReplicaLinkedAttribute
*la
)
7573 /* see if this update is newer than what we have already */
7574 struct GUID invocation_id
= GUID_zero();
7575 uint32_t version
= 0;
7576 NTTIME change_time
= 0;
7580 /* no existing info so update is newer */
7584 dsdb_get_extended_dn_guid(pdn
->dsdb_dn
->dn
, &invocation_id
, "RMD_INVOCID");
7585 dsdb_get_extended_dn_uint32(pdn
->dsdb_dn
->dn
, &version
, "RMD_VERSION");
7586 dsdb_get_extended_dn_nttime(pdn
->dsdb_dn
->dn
, &change_time
, "RMD_CHANGETIME");
7588 return replmd_update_is_newer(&invocation_id
,
7589 &la
->meta_data
.originating_invocation_id
,
7591 la
->meta_data
.version
,
7593 la
->meta_data
.originating_change_time
);
7597 * Marks an existing linked attribute value as deleted in the DB
7598 * @param pdn the parsed-DN of the target-value to delete
7600 static int replmd_delete_link_value(struct ldb_module
*module
,
7601 struct replmd_private
*replmd_private
,
7602 TALLOC_CTX
*mem_ctx
,
7603 struct ldb_dn
*src_obj_dn
,
7604 const struct dsdb_schema
*schema
,
7605 const struct dsdb_attribute
*attr
,
7608 struct GUID
*target_guid
,
7609 struct dsdb_dn
*target_dsdb_dn
,
7610 struct ldb_val
*output_val
)
7612 struct ldb_context
*ldb
= ldb_module_get_ctx(module
);
7615 const struct GUID
*invocation_id
= NULL
;
7619 unix_to_nt_time(&now
, t
);
7621 invocation_id
= samdb_ntds_invocation_id(ldb
);
7622 if (invocation_id
== NULL
) {
7623 return LDB_ERR_OPERATIONS_ERROR
;
7626 /* if the existing link is active, remove its backlink */
7629 ret
= replmd_add_backlink(module
, replmd_private
, schema
,
7630 src_obj_dn
, target_guid
, false,
7632 if (ret
!= LDB_SUCCESS
) {
7637 /* mark the existing value as deleted */
7638 ret
= replmd_update_la_val(mem_ctx
, output_val
, target_dsdb_dn
,
7639 target_dsdb_dn
, invocation_id
, seq_num
,
7640 seq_num
, now
, true);
7645 * Checks for a conflict in single-valued link attributes, and tries to
7646 * resolve the problem if possible.
7648 * Single-valued links should only ever have one active value. If we already
7649 * have an active link value, and during replication we receive an active link
7650 * value for a different target DN, then we need to resolve this inconsistency
7651 * and determine which value should be active. If the received info is better/
7652 * newer than the existing link attribute, then we need to set our existing
7653 * link as deleted. If the received info is worse/older, then we should continue
7654 * to add it, but set it as an inactive link.
7656 * Note that this is a corner-case that is unlikely to happen (but if it does
7657 * happen, we don't want it to break replication completely).
7659 * @param pdn_being_modified the parsed DN corresponding to the received link
7660 * target (note this is NULL if the link does not already exist in our DB)
7661 * @param pdn_list all the source object's Parsed-DNs for this attribute, i.e.
7662 * any existing active or inactive values for the attribute in our DB.
7663 * @param dsdb_dn the target DN for the received link attribute
7664 * @param add_as_inactive gets set to true if the received link is worse than
7665 * the existing link - it should still be added, but as an inactive link.
7667 static int replmd_check_singleval_la_conflict(struct ldb_module
*module
,
7668 struct replmd_private
*replmd_private
,
7669 TALLOC_CTX
*mem_ctx
,
7670 struct ldb_dn
*src_obj_dn
,
7671 struct drsuapi_DsReplicaLinkedAttribute
*la
,
7672 struct dsdb_dn
*dsdb_dn
,
7673 struct parsed_dn
*pdn_being_modified
,
7674 struct parsed_dn
*pdn_list
,
7675 struct ldb_message_element
*old_el
,
7676 const struct dsdb_schema
*schema
,
7677 const struct dsdb_attribute
*attr
,
7679 bool *add_as_inactive
)
7681 struct parsed_dn
*active_pdn
= NULL
;
7682 bool update_is_newer
= false;
7686 * check if there's a conflict for single-valued links, i.e. an active
7687 * linked attribute already exists, but it has a different target value
7689 ret
= replmd_get_active_singleval_link(module
, mem_ctx
, pdn_list
,
7690 old_el
->num_values
, attr
,
7693 if (ret
!= LDB_SUCCESS
) {
7698 * If no active value exists (or the received info is for the currently
7699 * active value), then no conflict exists
7701 if (active_pdn
== NULL
|| active_pdn
== pdn_being_modified
) {
7705 DBG_WARNING("Link conflict for %s attribute on %s\n",
7706 attr
->lDAPDisplayName
, ldb_dn_get_linearized(src_obj_dn
));
7708 /* Work out how to resolve the conflict based on which info is better */
7709 update_is_newer
= replmd_link_update_is_newer(active_pdn
, la
);
7711 if (update_is_newer
) {
7712 DBG_WARNING("Using received value %s, over existing target %s\n",
7713 ldb_dn_get_linearized(dsdb_dn
->dn
),
7714 ldb_dn_get_linearized(active_pdn
->dsdb_dn
->dn
));
7717 * Delete our existing active link. The received info will then
7718 * be added (through normal link processing) as the active value
7720 ret
= replmd_delete_link_value(module
, replmd_private
, old_el
,
7721 src_obj_dn
, schema
, attr
,
7722 seq_num
, true, &active_pdn
->guid
,
7723 active_pdn
->dsdb_dn
,
7726 if (ret
!= LDB_SUCCESS
) {
7730 DBG_WARNING("Using existing target %s, over received value %s\n",
7731 ldb_dn_get_linearized(active_pdn
->dsdb_dn
->dn
),
7732 ldb_dn_get_linearized(dsdb_dn
->dn
));
7735 * we want to keep our existing active link and add the
7736 * received link as inactive
7738 *add_as_inactive
= true;
7745 process one linked attribute structure
7747 static int replmd_process_linked_attribute(struct ldb_module
*module
,
7748 struct replmd_private
*replmd_private
,
7749 struct la_entry
*la_entry
,
7750 struct ldb_request
*parent
)
7752 struct drsuapi_DsReplicaLinkedAttribute
*la
= la_entry
->la
;
7753 struct ldb_context
*ldb
= ldb_module_get_ctx(module
);
7754 struct ldb_message
*msg
;
7755 TALLOC_CTX
*tmp_ctx
= talloc_new(la_entry
);
7756 const struct dsdb_schema
*schema
= dsdb_get_schema(ldb
, tmp_ctx
);
7758 const struct dsdb_attribute
*attr
;
7759 struct dsdb_dn
*dsdb_dn
;
7760 uint64_t seq_num
= 0;
7761 struct ldb_message_element
*old_el
;
7762 time_t t
= time(NULL
);
7763 struct parsed_dn
*pdn_list
, *pdn
, *next
;
7764 struct GUID guid
= GUID_zero();
7765 bool active
= (la
->flags
& DRSUAPI_DS_LINKED_ATTRIBUTE_FLAG_ACTIVE
)?true:false;
7767 enum deletion_state deletion_state
= OBJECT_NOT_DELETED
;
7768 struct dsdb_dn
*old_dsdb_dn
= NULL
;
7769 struct ldb_val
*val_to_update
= NULL
;
7770 bool add_as_inactive
= false;
7773 * get the attribute being modified, the search result for the source object,
7774 * and the target object's DN details
7776 ret
= replmd_extract_la_entry_details(module
, la_entry
, tmp_ctx
, &attr
,
7779 if (ret
!= LDB_SUCCESS
) {
7780 talloc_free(tmp_ctx
);
7785 * Check for deleted objects per MS-DRSR 4.1.10.6.14
7786 * ProcessLinkValue, because link updates are not applied to
7787 * recycled and tombstone objects. We don't have to delete
7788 * any existing link, that should have happened when the
7789 * object deletion was replicated or initiated.
7791 replmd_deletion_state(module
, msg
, &deletion_state
, NULL
);
7793 if (deletion_state
>= OBJECT_RECYCLED
) {
7794 talloc_free(tmp_ctx
);
7798 old_el
= ldb_msg_find_element(msg
, attr
->lDAPDisplayName
);
7799 if (old_el
== NULL
) {
7800 ret
= ldb_msg_add_empty(msg
, attr
->lDAPDisplayName
, LDB_FLAG_MOD_REPLACE
, &old_el
);
7801 if (ret
!= LDB_SUCCESS
) {
7802 ldb_module_oom(module
);
7803 talloc_free(tmp_ctx
);
7804 return LDB_ERR_OPERATIONS_ERROR
;
7807 old_el
->flags
= LDB_FLAG_MOD_REPLACE
;
7810 /* parse the existing links */
7811 ret
= get_parsed_dns_trusted(module
, replmd_private
, tmp_ctx
, old_el
, &pdn_list
,
7812 attr
->syntax
->ldap_oid
, parent
);
7814 if (ret
!= LDB_SUCCESS
) {
7815 talloc_free(tmp_ctx
);
7819 ret
= replmd_check_target_exists(module
, dsdb_dn
, la_entry
, msg
->dn
,
7820 true, &guid
, &ignore_link
);
7822 if (ret
!= LDB_SUCCESS
) {
7823 talloc_free(tmp_ctx
);
7828 * there are some cases where the target object doesn't exist, but it's
7829 * OK to ignore the linked attribute
7832 talloc_free(tmp_ctx
);
7836 /* see if this link already exists */
7837 ret
= parsed_dn_find(ldb
, pdn_list
, old_el
->num_values
,
7840 dsdb_dn
->extra_part
, 0,
7842 attr
->syntax
->ldap_oid
,
7844 if (ret
!= LDB_SUCCESS
) {
7845 talloc_free(tmp_ctx
);
7849 if (!replmd_link_update_is_newer(pdn
, la
)) {
7850 DEBUG(3,("Discarding older DRS linked attribute update to %s on %s from %s\n",
7851 old_el
->name
, ldb_dn_get_linearized(msg
->dn
),
7852 GUID_string(tmp_ctx
, &la
->meta_data
.originating_invocation_id
)));
7853 talloc_free(tmp_ctx
);
7857 /* get a seq_num for this change */
7858 ret
= ldb_sequence_number(ldb
, LDB_SEQ_NEXT
, &seq_num
);
7859 if (ret
!= LDB_SUCCESS
) {
7860 talloc_free(tmp_ctx
);
7865 * check for single-valued link conflicts, i.e. an active linked
7866 * attribute already exists, but it has a different target value
7869 ret
= replmd_check_singleval_la_conflict(module
, replmd_private
,
7870 tmp_ctx
, msg
->dn
, la
,
7871 dsdb_dn
, pdn
, pdn_list
,
7872 old_el
, schema
, attr
,
7875 if (ret
!= LDB_SUCCESS
) {
7876 talloc_free(tmp_ctx
);
7882 uint32_t rmd_flags
= dsdb_dn_rmd_flags(pdn
->dsdb_dn
->dn
);
7884 if (!(rmd_flags
& DSDB_RMD_FLAG_DELETED
)) {
7885 /* remove the existing backlink */
7886 ret
= replmd_add_backlink(module
, replmd_private
,
7889 &pdn
->guid
, false, attr
,
7891 if (ret
!= LDB_SUCCESS
) {
7892 talloc_free(tmp_ctx
);
7897 val_to_update
= pdn
->v
;
7898 old_dsdb_dn
= pdn
->dsdb_dn
;
7904 * We know where the new one needs to be, from the *next
7905 * pointer into pdn_list.
7908 offset
= old_el
->num_values
;
7910 if (next
->dsdb_dn
== NULL
) {
7911 ret
= really_parse_trusted_dn(tmp_ctx
, ldb
, next
,
7912 attr
->syntax
->ldap_oid
);
7913 if (ret
!= LDB_SUCCESS
) {
7917 offset
= next
- pdn_list
;
7918 if (offset
> old_el
->num_values
) {
7919 talloc_free(tmp_ctx
);
7920 return LDB_ERR_OPERATIONS_ERROR
;
7924 old_el
->values
= talloc_realloc(msg
->elements
, old_el
->values
,
7925 struct ldb_val
, old_el
->num_values
+1);
7926 if (!old_el
->values
) {
7927 ldb_module_oom(module
);
7928 return LDB_ERR_OPERATIONS_ERROR
;
7931 if (offset
!= old_el
->num_values
) {
7932 memmove(&old_el
->values
[offset
+ 1], &old_el
->values
[offset
],
7933 (old_el
->num_values
- offset
) * sizeof(old_el
->values
[0]));
7936 old_el
->num_values
++;
7938 val_to_update
= &old_el
->values
[offset
];
7942 /* set the link attribute's value to the info that was received */
7943 ret
= replmd_set_la_val(tmp_ctx
, val_to_update
, dsdb_dn
, old_dsdb_dn
,
7944 &la
->meta_data
.originating_invocation_id
,
7945 la
->meta_data
.originating_usn
, seq_num
,
7946 la
->meta_data
.originating_change_time
,
7947 la
->meta_data
.version
,
7949 if (ret
!= LDB_SUCCESS
) {
7950 talloc_free(tmp_ctx
);
7954 if (add_as_inactive
) {
7956 /* Set the new link as inactive/deleted to avoid conflicts */
7957 ret
= replmd_delete_link_value(module
, replmd_private
, old_el
,
7958 msg
->dn
, schema
, attr
, seq_num
,
7959 false, &guid
, dsdb_dn
,
7962 if (ret
!= LDB_SUCCESS
) {
7963 talloc_free(tmp_ctx
);
7967 } else if (active
) {
7969 /* if the new link is active, then add the new backlink */
7970 ret
= replmd_add_backlink(module
, replmd_private
,
7975 if (ret
!= LDB_SUCCESS
) {
7976 talloc_free(tmp_ctx
);
7981 /* we only change whenChanged and uSNChanged if the seq_num
7983 ret
= add_time_element(msg
, "whenChanged", t
);
7984 if (ret
!= LDB_SUCCESS
) {
7985 talloc_free(tmp_ctx
);
7990 ret
= add_uint64_element(ldb
, msg
, "uSNChanged", seq_num
);
7991 if (ret
!= LDB_SUCCESS
) {
7992 talloc_free(tmp_ctx
);
7997 old_el
= ldb_msg_find_element(msg
, attr
->lDAPDisplayName
);
7998 if (old_el
== NULL
) {
7999 talloc_free(tmp_ctx
);
8000 return ldb_operr(ldb
);
8003 ret
= dsdb_check_single_valued_link(attr
, old_el
);
8004 if (ret
!= LDB_SUCCESS
) {
8005 talloc_free(tmp_ctx
);
8009 old_el
->flags
|= LDB_FLAG_INTERNAL_DISABLE_SINGLE_VALUE_CHECK
;
8011 ret
= linked_attr_modify(module
, msg
, parent
);
8012 if (ret
!= LDB_SUCCESS
) {
8013 ldb_debug(ldb
, LDB_DEBUG_WARNING
, "Failed to apply linked attribute change '%s'\n%s\n",
8015 ldb_ldif_message_redacted_string(ldb
,
8017 LDB_CHANGETYPE_MODIFY
,
8019 talloc_free(tmp_ctx
);
8023 talloc_free(tmp_ctx
);
8028 static int replmd_extended(struct ldb_module
*module
, struct ldb_request
*req
)
8030 if (strcmp(req
->op
.extended
.oid
, DSDB_EXTENDED_REPLICATED_OBJECTS_OID
) == 0) {
8031 return replmd_extended_replicated_objects(module
, req
);
8034 return ldb_next_request(module
, req
);
8039 we hook into the transaction operations to allow us to
8040 perform the linked attribute updates at the end of the whole
8041 transaction. This allows a forward linked attribute to be created
8042 before the object is created. During a vampire, w2k8 sends us linked
8043 attributes before the objects they are part of.
8045 static int replmd_start_transaction(struct ldb_module
*module
)
8047 /* create our private structure for this transaction */
8048 struct replmd_private
*replmd_private
= talloc_get_type(ldb_module_get_private(module
),
8049 struct replmd_private
);
8050 replmd_txn_cleanup(replmd_private
);
8052 /* free any leftover mod_usn records from cancelled
8054 while (replmd_private
->ncs
) {
8055 struct nc_entry
*e
= replmd_private
->ncs
;
8056 DLIST_REMOVE(replmd_private
->ncs
, e
);
8060 replmd_private
->originating_updates
= false;
8062 return ldb_next_start_trans(module
);
8066 on prepare commit we loop over our queued la_context structures and
8069 static int replmd_prepare_commit(struct ldb_module
*module
)
8071 struct replmd_private
*replmd_private
=
8072 talloc_get_type(ldb_module_get_private(module
), struct replmd_private
);
8073 struct la_entry
*la
, *prev
;
8077 * Walk the list of linked attributes from DRS replication.
8079 * We walk backwards, to do the first entry first, as we
8080 * added the entries with DLIST_ADD() which puts them at the
8083 for (la
= DLIST_TAIL(replmd_private
->la_list
); la
; la
=prev
) {
8084 prev
= DLIST_PREV(la
);
8085 DLIST_REMOVE(replmd_private
->la_list
, la
);
8086 ret
= replmd_process_linked_attribute(module
, replmd_private
,
8088 if (ret
!= LDB_SUCCESS
) {
8089 replmd_txn_cleanup(replmd_private
);
8094 replmd_txn_cleanup(replmd_private
);
8096 /* possibly change @REPLCHANGED */
8097 ret
= replmd_notify_store(module
, NULL
);
8098 if (ret
!= LDB_SUCCESS
) {
8102 return ldb_next_prepare_commit(module
);
8105 static int replmd_del_transaction(struct ldb_module
*module
)
8107 struct replmd_private
*replmd_private
=
8108 talloc_get_type(ldb_module_get_private(module
), struct replmd_private
);
8109 replmd_txn_cleanup(replmd_private
);
8111 return ldb_next_del_trans(module
);
8115 static const struct ldb_module_ops ldb_repl_meta_data_module_ops
= {
8116 .name
= "repl_meta_data",
8117 .init_context
= replmd_init
,
8119 .modify
= replmd_modify
,
8120 .rename
= replmd_rename
,
8121 .del
= replmd_delete
,
8122 .extended
= replmd_extended
,
8123 .start_transaction
= replmd_start_transaction
,
8124 .prepare_commit
= replmd_prepare_commit
,
8125 .del_transaction
= replmd_del_transaction
,
8128 int ldb_repl_meta_data_module_init(const char *version
)
8130 LDB_MODULE_CHECK_VERSION(version
);
8131 return ldb_register_module(&ldb_repl_meta_data_module_ops
);