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"
53 #include "lib/util/binsearch.h"
58 #define DBGC_CLASS DBGC_DRS_REPL
60 /* the RMD_VERSION for linked attributes starts from 1 */
61 #define RMD_VERSION_INITIAL 1
64 * It's 29/12/9999 at 23:59:59 UTC as specified in MS-ADTS 7.1.1.4.2
65 * Deleted Objects Container
67 static const NTTIME DELETED_OBJECT_CONTAINER_CHANGE_TIME
= 2650466015990000000ULL;
69 struct replmd_private
{
71 struct la_group
*la_list
;
73 struct nc_entry
*prev
, *next
;
76 uint64_t mod_usn_urgent
;
78 struct ldb_dn
*schema_dn
;
79 bool originating_updates
;
82 uint32_t num_processed
;
83 bool recyclebin_enabled
;
84 bool recyclebin_state_known
;
88 * groups link attributes together by source-object and attribute-ID,
89 * to improve processing efficiency (i.e. for 'member' attribute, which
90 * could have 100s or 1000s of links).
91 * Note this grouping is best effort - the same source object could still
92 * correspond to several la_groups (a lot depends on the order DRS sends
93 * the links in). The groups currently don't span replication chunks (which
94 * caps the size to ~1500 links by default).
97 struct la_group
*next
, *prev
;
98 struct la_entry
*la_entries
;
102 struct la_entry
*next
, *prev
;
103 struct drsuapi_DsReplicaLinkedAttribute
*la
;
104 uint32_t dsdb_repl_flags
;
107 struct replmd_replicated_request
{
108 struct ldb_module
*module
;
109 struct ldb_request
*req
;
111 const struct dsdb_schema
*schema
;
112 struct GUID our_invocation_id
;
114 /* the controls we pass down */
115 struct ldb_control
**controls
;
118 * Backlinks for the replmd_add() case (we want to create
119 * backlinks after creating the user, but before the end of
122 struct la_backlink
*la_backlinks
;
124 /* details for the mode where we apply a bunch of inbound replication meessages */
126 uint32_t index_current
;
127 struct dsdb_extended_replicated_objects
*objs
;
129 struct ldb_message
*search_msg
;
130 struct GUID local_parent_guid
;
141 * the result of replmd_process_linked_attribute(): either there was no change
142 * (update was ignored), a new link was added (either inactive or active), or
143 * an existing link was modified (active/inactive status may have changed).
148 LINK_CHANGE_MODIFIED
,
149 } replmd_link_changed
;
151 static int replmd_replicated_apply_merge(struct replmd_replicated_request
*ar
);
152 static int replmd_delete_internals(struct ldb_module
*module
, struct ldb_request
*req
, bool re_delete
);
153 static int replmd_check_upgrade_links(struct ldb_context
*ldb
,
154 struct parsed_dn
*dns
, uint32_t count
,
155 struct ldb_message_element
*el
,
156 const char *ldap_oid
);
157 static int replmd_verify_link_target(struct replmd_replicated_request
*ar
,
159 struct la_entry
*la_entry
,
160 struct ldb_dn
*src_dn
,
161 const struct dsdb_attribute
*attr
);
162 static int replmd_get_la_entry_source(struct ldb_module
*module
,
163 struct la_entry
*la_entry
,
165 const struct dsdb_attribute
**ret_attr
,
166 struct ldb_message
**source_msg
);
167 static int replmd_set_la_val(TALLOC_CTX
*mem_ctx
, struct ldb_val
*v
, struct dsdb_dn
*dsdb_dn
,
168 struct dsdb_dn
*old_dsdb_dn
, const struct GUID
*invocation_id
,
169 uint64_t usn
, uint64_t local_usn
, NTTIME nttime
,
170 uint32_t version
, bool deleted
);
172 static int replmd_make_deleted_child_dn(TALLOC_CTX
*tmp_ctx
,
173 struct ldb_context
*ldb
,
175 const char *rdn_name
,
176 const struct ldb_val
*rdn_value
,
179 enum urgent_situation
{
180 REPL_URGENT_ON_CREATE
= 1,
181 REPL_URGENT_ON_UPDATE
= 2,
182 REPL_URGENT_ON_DELETE
= 4
185 enum deletion_state
{
186 OBJECT_NOT_DELETED
=1,
193 static bool replmd_recyclebin_enabled(struct ldb_module
*module
)
195 bool enabled
= false;
196 struct replmd_private
*replmd_private
=
197 talloc_get_type_abort(ldb_module_get_private(module
),
198 struct replmd_private
);
201 * only lookup the recycle-bin state once per replication, then cache
202 * the result. This can save us 1000s of DB searches
204 if (!replmd_private
->recyclebin_state_known
) {
205 int ret
= dsdb_recyclebin_enabled(module
, &enabled
);
206 if (ret
!= LDB_SUCCESS
) {
210 replmd_private
->recyclebin_enabled
= enabled
;
211 replmd_private
->recyclebin_state_known
= true;
214 return replmd_private
->recyclebin_enabled
;
217 static void replmd_deletion_state(struct ldb_module
*module
,
218 const struct ldb_message
*msg
,
219 enum deletion_state
*current_state
,
220 enum deletion_state
*next_state
)
222 bool enabled
= false;
225 *current_state
= OBJECT_REMOVED
;
226 if (next_state
!= NULL
) {
227 *next_state
= OBJECT_REMOVED
;
232 enabled
= replmd_recyclebin_enabled(module
);
234 if (ldb_msg_check_string_attribute(msg
, "isDeleted", "TRUE")) {
236 *current_state
= OBJECT_TOMBSTONE
;
237 if (next_state
!= NULL
) {
238 *next_state
= OBJECT_REMOVED
;
243 if (ldb_msg_check_string_attribute(msg
, "isRecycled", "TRUE")) {
244 *current_state
= OBJECT_RECYCLED
;
245 if (next_state
!= NULL
) {
246 *next_state
= OBJECT_REMOVED
;
251 *current_state
= OBJECT_DELETED
;
252 if (next_state
!= NULL
) {
253 *next_state
= OBJECT_RECYCLED
;
258 *current_state
= OBJECT_NOT_DELETED
;
259 if (next_state
== NULL
) {
264 *next_state
= OBJECT_DELETED
;
266 *next_state
= OBJECT_TOMBSTONE
;
270 static const struct {
271 const char *update_name
;
272 enum urgent_situation repl_situation
;
273 } urgent_objects
[] = {
274 {"nTDSDSA", (REPL_URGENT_ON_CREATE
| REPL_URGENT_ON_DELETE
)},
275 {"crossRef", (REPL_URGENT_ON_CREATE
| REPL_URGENT_ON_DELETE
)},
276 {"attributeSchema", (REPL_URGENT_ON_CREATE
| REPL_URGENT_ON_UPDATE
)},
277 {"classSchema", (REPL_URGENT_ON_CREATE
| REPL_URGENT_ON_UPDATE
)},
278 {"secret", (REPL_URGENT_ON_CREATE
| REPL_URGENT_ON_UPDATE
)},
279 {"rIDManager", (REPL_URGENT_ON_CREATE
| REPL_URGENT_ON_UPDATE
)},
283 /* Attributes looked for when updating or deleting, to check for a urgent replication needed */
284 static const char *urgent_attrs
[] = {
287 "userAccountControl",
292 static bool replmd_check_urgent_objectclass(const struct ldb_message_element
*objectclass_el
,
293 enum urgent_situation situation
)
296 for (i
=0; urgent_objects
[i
].update_name
; i
++) {
298 if ((situation
& urgent_objects
[i
].repl_situation
) == 0) {
302 for (j
=0; j
<objectclass_el
->num_values
; j
++) {
303 const struct ldb_val
*v
= &objectclass_el
->values
[j
];
304 if (ldb_attr_cmp((const char *)v
->data
, urgent_objects
[i
].update_name
) == 0) {
312 static bool replmd_check_urgent_attribute(const struct ldb_message_element
*el
)
314 if (ldb_attr_in_list(urgent_attrs
, el
->name
)) {
320 static int replmd_replicated_apply_isDeleted(struct replmd_replicated_request
*ar
);
323 initialise the module
324 allocate the private structure and build the list
325 of partition DNs for use by replmd_notify()
327 static int replmd_init(struct ldb_module
*module
)
329 struct replmd_private
*replmd_private
;
330 struct ldb_context
*ldb
= ldb_module_get_ctx(module
);
333 replmd_private
= talloc_zero(module
, struct replmd_private
);
334 if (replmd_private
== NULL
) {
336 return LDB_ERR_OPERATIONS_ERROR
;
339 ret
= dsdb_check_samba_compatible_feature(module
,
340 SAMBA_SORTED_LINKS_FEATURE
,
341 &replmd_private
->sorted_links
);
342 if (ret
!= LDB_SUCCESS
) {
343 talloc_free(replmd_private
);
347 replmd_private
->schema_dn
= ldb_get_schema_basedn(ldb
);
348 ldb_module_set_private(module
, replmd_private
);
349 return ldb_next_init(module
);
353 cleanup our per-transaction contexts
355 static void replmd_txn_cleanup(struct replmd_private
*replmd_private
)
357 talloc_free(replmd_private
->la_ctx
);
358 replmd_private
->la_list
= NULL
;
359 replmd_private
->la_ctx
= NULL
;
360 replmd_private
->recyclebin_state_known
= false;
365 struct la_backlink
*next
, *prev
;
366 const char *attr_name
;
367 struct ldb_dn
*forward_dn
;
368 struct GUID target_guid
;
370 bool bl_maybe_invisible
;
375 a ldb_modify request operating on modules below the
378 static int linked_attr_modify(struct ldb_module
*module
,
379 const struct ldb_message
*message
,
380 struct ldb_request
*parent
)
382 struct ldb_request
*mod_req
;
384 struct ldb_context
*ldb
= ldb_module_get_ctx(module
);
385 TALLOC_CTX
*tmp_ctx
= talloc_new(module
);
386 struct ldb_result
*res
;
388 res
= talloc_zero(tmp_ctx
, struct ldb_result
);
390 talloc_free(tmp_ctx
);
391 return ldb_oom(ldb_module_get_ctx(module
));
394 ret
= ldb_build_mod_req(&mod_req
, ldb
, tmp_ctx
,
398 ldb_modify_default_callback
,
400 LDB_REQ_SET_LOCATION(mod_req
);
401 if (ret
!= LDB_SUCCESS
) {
402 talloc_free(tmp_ctx
);
406 ret
= ldb_request_add_control(mod_req
, DSDB_CONTROL_REPLICATED_UPDATE_OID
,
408 if (ret
!= LDB_SUCCESS
) {
412 /* Run the new request */
413 ret
= ldb_next_request(module
, mod_req
);
415 if (ret
== LDB_SUCCESS
) {
416 ret
= ldb_wait(mod_req
->handle
, LDB_WAIT_ALL
);
419 talloc_free(tmp_ctx
);
423 static int replmd_backlink_invisible(struct ldb_module
*module
,
424 struct ldb_message
*msg
,
425 struct la_backlink
*bl
)
427 struct ldb_context
*ldb
= ldb_module_get_ctx(module
);
428 const struct dsdb_schema
*schema
= NULL
;
429 TALLOC_CTX
*frame
= NULL
;
430 struct ldb_message_element
*oc_element
= NULL
;
431 const char **allowed_attrs
= NULL
;
434 if (!bl
->active
|| !bl
->bl_maybe_invisible
|| bl
->bl_invisible
) {
438 schema
= dsdb_get_schema(ldb
, NULL
);
439 if (schema
== NULL
) {
440 return ldb_module_operr(module
);
443 oc_element
= ldb_msg_find_element(msg
, "objectClass");
444 if (oc_element
== NULL
) {
445 return ldb_module_operr(module
);
448 frame
= talloc_stackframe();
450 allowed_attrs
= dsdb_full_attribute_list(frame
,
454 if (allowed_attrs
== NULL
) {
456 return ldb_module_oom(module
);
459 bl_allowed
= str_list_check(allowed_attrs
, bl
->attr_name
);
461 bl
->bl_maybe_invisible
= false;
462 bl
->bl_invisible
= true;
470 process a backlinks we accumulated during a transaction, adding and
471 deleting the backlinks from the target objects
473 static int replmd_process_backlink(struct ldb_module
*module
, struct la_backlink
*bl
, struct ldb_request
*parent
)
475 struct ldb_dn
*target_dn
, *source_dn
;
476 struct ldb_message
*old_msg
= NULL
;
477 const char * const empty_attrs
[] = { NULL
};
478 const char * const oc_attrs
[] = { "objectClass", NULL
};
479 const char * const *attrs
= NULL
;
480 uint32_t rmd_flags
= 0;
482 struct ldb_context
*ldb
= ldb_module_get_ctx(module
);
483 struct ldb_message
*msg
;
484 TALLOC_CTX
*frame
= talloc_stackframe();
487 if (bl
->active
&& bl
->bl_maybe_invisible
) {
496 - construct ldb_message
497 - either an add or a delete
499 ret
= dsdb_module_obj_by_guid(module
,
505 if (ret
!= LDB_SUCCESS
) {
506 struct GUID_txt_buf guid_str
;
507 DBG_WARNING("Failed to find target DN for linked attribute with GUID %s\n",
508 GUID_buf_string(&bl
->target_guid
, &guid_str
));
509 DBG_WARNING("Please run 'samba-tool dbcheck' to resolve any missing backlinks.\n");
513 target_dn
= old_msg
->dn
;
515 ret
= replmd_backlink_invisible(module
, old_msg
, bl
);
516 if (ret
!= LDB_SUCCESS
) {
521 if (bl
->active
&& bl
->bl_invisible
) {
522 rmd_flags
|= DSDB_RMD_FLAG_HIDDEN_BL
;
525 msg
= ldb_msg_new(frame
);
527 ldb_module_oom(module
);
529 return LDB_ERR_OPERATIONS_ERROR
;
532 source_dn
= ldb_dn_copy(frame
, bl
->forward_dn
);
534 ldb_module_oom(module
);
536 return LDB_ERR_OPERATIONS_ERROR
;
538 /* Filter down to the attributes we want in the backlink */
539 const char *accept
[] = { "GUID", "SID", NULL
};
540 ldb_dn_extended_filter(source_dn
, accept
);
543 if (rmd_flags
!= 0) {
544 const char *flags_string
= NULL
;
545 struct ldb_val flagsv
;
547 flags_string
= talloc_asprintf(frame
, "%u", rmd_flags
);
548 if (flags_string
== NULL
) {
550 return ldb_module_oom(module
);
553 flagsv
= data_blob_string_const(flags_string
);
555 ret
= ldb_dn_set_extended_component(source_dn
, "RMD_FLAGS", &flagsv
);
556 if (ret
!= LDB_SUCCESS
) {
562 /* construct a ldb_message for adding/deleting the backlink */
564 dn_string
= ldb_dn_get_extended_linearized(frame
, source_dn
, 1);
566 ldb_module_oom(module
);
568 return LDB_ERR_OPERATIONS_ERROR
;
570 ret
= ldb_msg_add_steal_string(msg
, bl
->attr_name
, dn_string
);
571 if (ret
!= LDB_SUCCESS
) {
575 msg
->elements
[0].flags
= bl
->active
?LDB_FLAG_MOD_ADD
:LDB_FLAG_MOD_DELETE
;
577 /* a backlink should never be single valued. Unfortunately the
578 exchange schema has a attribute
579 msExchBridgeheadedLocalConnectorsDNBL which is single
580 valued and a backlink. We need to cope with that by
581 ignoring the single value flag */
582 msg
->elements
[0].flags
|= LDB_FLAG_INTERNAL_DISABLE_SINGLE_VALUE_CHECK
;
584 ret
= dsdb_module_modify(module
, msg
, DSDB_FLAG_NEXT_MODULE
, parent
);
585 if (ret
== LDB_ERR_NO_SUCH_ATTRIBUTE
&& !bl
->active
) {
586 /* we allow LDB_ERR_NO_SUCH_ATTRIBUTE as success to
587 cope with possible corruption where the backlink has
588 already been removed */
589 DEBUG(3,("WARNING: backlink from %s already removed from %s - %s\n",
590 ldb_dn_get_linearized(target_dn
),
591 ldb_dn_get_linearized(source_dn
),
592 ldb_errstring(ldb
)));
594 } else if (ret
!= LDB_SUCCESS
) {
595 ldb_asprintf_errstring(ldb
, "Failed to %s backlink from %s to %s - %s",
596 bl
->active
?"add":"remove",
597 ldb_dn_get_linearized(source_dn
),
598 ldb_dn_get_linearized(target_dn
),
608 add a backlink to the list of backlinks to add/delete in the prepare
611 forward_dn is stolen onto the defereed context
613 static int replmd_defer_add_backlink(struct ldb_module
*module
,
614 struct replmd_private
*replmd_private
,
615 const struct dsdb_schema
*schema
,
616 struct replmd_replicated_request
*ac
,
617 struct ldb_dn
*forward_dn
,
618 struct GUID
*target_guid
, bool active
,
619 const struct dsdb_attribute
*schema_attr
,
620 struct ldb_request
*parent
)
622 const struct dsdb_attribute
*target_attr
;
623 struct la_backlink
*bl
;
625 bl
= talloc(ac
, struct la_backlink
);
627 ldb_module_oom(module
);
628 return LDB_ERR_OPERATIONS_ERROR
;
631 target_attr
= dsdb_attribute_by_linkID(schema
, schema_attr
->linkID
^ 1);
634 * windows 2003 has a broken schema where the
635 * definition of msDS-IsDomainFor is missing (which is
636 * supposed to be the backlink of the
637 * msDS-HasDomainNCs attribute
642 bl
->attr_name
= target_attr
->lDAPDisplayName
;
643 bl
->forward_dn
= talloc_steal(bl
, forward_dn
);
644 bl
->target_guid
= *target_guid
;
646 bl
->bl_maybe_invisible
= target_attr
->bl_maybe_invisible
;
647 bl
->bl_invisible
= false;
649 DLIST_ADD(ac
->la_backlinks
, bl
);
655 add a backlink to the list of backlinks to add/delete in the prepare
658 static int replmd_add_backlink(struct ldb_module
*module
,
659 struct replmd_private
*replmd_private
,
660 const struct dsdb_schema
*schema
,
661 struct ldb_dn
*forward_dn
,
662 struct GUID
*target_guid
, bool active
,
663 const struct dsdb_attribute
*schema_attr
,
664 struct ldb_request
*parent
)
666 const struct dsdb_attribute
*target_attr
;
667 struct la_backlink bl
;
670 target_attr
= dsdb_attribute_by_linkID(schema
, schema_attr
->linkID
^ 1);
673 * windows 2003 has a broken schema where the
674 * definition of msDS-IsDomainFor is missing (which is
675 * supposed to be the backlink of the
676 * msDS-HasDomainNCs attribute
681 bl
.attr_name
= target_attr
->lDAPDisplayName
;
682 bl
.forward_dn
= forward_dn
;
683 bl
.target_guid
= *target_guid
;
685 bl
.bl_maybe_invisible
= target_attr
->bl_maybe_invisible
;
686 bl
.bl_invisible
= false;
688 ret
= replmd_process_backlink(module
, &bl
, parent
);
694 * Callback for most write operations in this module:
696 * notify the repl task that a object has changed. The notifies are
697 * gathered up in the replmd_private structure then written to the
698 * @REPLCHANGED object in each partition during the prepare_commit
700 static int replmd_op_callback(struct ldb_request
*req
, struct ldb_reply
*ares
)
703 struct replmd_replicated_request
*ac
=
704 talloc_get_type_abort(req
->context
, struct replmd_replicated_request
);
705 struct replmd_private
*replmd_private
=
706 talloc_get_type_abort(ldb_module_get_private(ac
->module
), struct replmd_private
);
707 struct nc_entry
*modified_partition
;
708 struct ldb_control
*partition_ctrl
;
709 const struct dsdb_control_current_partition
*partition
;
711 struct ldb_control
**controls
;
713 partition_ctrl
= ldb_reply_get_control(ares
, DSDB_CONTROL_CURRENT_PARTITION_OID
);
715 controls
= ares
->controls
;
716 if (ldb_request_get_control(ac
->req
,
717 DSDB_CONTROL_CURRENT_PARTITION_OID
) == NULL
) {
719 * Remove the current partition control from what we pass up
720 * the chain if it hasn't been requested manually.
722 controls
= ldb_controls_except_specified(ares
->controls
, ares
,
726 if (ares
->error
!= LDB_SUCCESS
) {
727 struct GUID_txt_buf guid_txt
;
728 struct ldb_message
*msg
= NULL
;
731 if (ac
->apply_mode
== false) {
732 DBG_NOTICE("Originating update failure. Error is: %s\n",
733 ldb_strerror(ares
->error
));
734 return ldb_module_done(ac
->req
, controls
,
735 ares
->response
, ares
->error
);
738 msg
= ac
->objs
->objects
[ac
->index_current
].msg
;
740 * Set at DBG_NOTICE as once these start to happe, they
741 * will happen a lot until resolved, due to repeated
742 * replication. The caller will probably print the
743 * ldb error string anyway.
745 DBG_NOTICE("DRS replication apply failure for %s. Error is: %s\n",
746 ldb_dn_get_linearized(msg
->dn
),
747 ldb_strerror(ares
->error
));
749 s
= ldb_ldif_message_redacted_string(ldb_module_get_ctx(ac
->module
),
754 DBG_INFO("Failing DRS %s replication message was %s:\n%s\n",
755 ac
->search_msg
== NULL
? "ADD" : "MODIFY",
756 GUID_buf_string(&ac
->objs
->objects
[ac
->index_current
].object_guid
,
760 return ldb_module_done(ac
->req
, controls
,
761 ares
->response
, ares
->error
);
764 if (ares
->type
!= LDB_REPLY_DONE
) {
765 ldb_set_errstring(ldb_module_get_ctx(ac
->module
), "Invalid reply type for notify\n!");
766 return ldb_module_done(ac
->req
, NULL
,
767 NULL
, LDB_ERR_OPERATIONS_ERROR
);
770 if (ac
->apply_mode
== false) {
771 struct la_backlink
*bl
;
773 * process our backlink list after an replmd_add(),
774 * creating and deleting backlinks as necessary (this
775 * code is sync). The other cases are handled inline
778 for (bl
=ac
->la_backlinks
; bl
; bl
=bl
->next
) {
779 ret
= replmd_process_backlink(ac
->module
, bl
, ac
->req
);
780 if (ret
!= LDB_SUCCESS
) {
781 return ldb_module_done(ac
->req
, NULL
,
787 if (!partition_ctrl
) {
788 ldb_set_errstring(ldb_module_get_ctx(ac
->module
),"No partition control on reply");
789 return ldb_module_done(ac
->req
, NULL
,
790 NULL
, LDB_ERR_OPERATIONS_ERROR
);
793 partition
= talloc_get_type_abort(partition_ctrl
->data
,
794 struct dsdb_control_current_partition
);
796 if (ac
->seq_num
> 0) {
797 for (modified_partition
= replmd_private
->ncs
; modified_partition
;
798 modified_partition
= modified_partition
->next
) {
799 if (ldb_dn_compare(modified_partition
->dn
, partition
->dn
) == 0) {
804 if (modified_partition
== NULL
) {
805 modified_partition
= talloc_zero(replmd_private
, struct nc_entry
);
806 if (!modified_partition
) {
807 ldb_oom(ldb_module_get_ctx(ac
->module
));
808 return ldb_module_done(ac
->req
, NULL
,
809 NULL
, LDB_ERR_OPERATIONS_ERROR
);
811 modified_partition
->dn
= ldb_dn_copy(modified_partition
, partition
->dn
);
812 if (!modified_partition
->dn
) {
813 ldb_oom(ldb_module_get_ctx(ac
->module
));
814 return ldb_module_done(ac
->req
, NULL
,
815 NULL
, LDB_ERR_OPERATIONS_ERROR
);
817 DLIST_ADD(replmd_private
->ncs
, modified_partition
);
820 if (ac
->seq_num
> modified_partition
->mod_usn
) {
821 modified_partition
->mod_usn
= ac
->seq_num
;
823 modified_partition
->mod_usn_urgent
= ac
->seq_num
;
826 if (!ac
->apply_mode
) {
827 replmd_private
->originating_updates
= true;
831 if (ac
->apply_mode
) {
832 ret
= replmd_replicated_apply_isDeleted(ac
);
833 if (ret
!= LDB_SUCCESS
) {
834 return ldb_module_done(ac
->req
, NULL
, NULL
, ret
);
838 /* free the partition control container here, for the
839 * common path. Other cases will have it cleaned up
840 * eventually with the ares */
841 talloc_free(partition_ctrl
);
842 return ldb_module_done(ac
->req
, controls
,
843 ares
->response
, LDB_SUCCESS
);
849 * update a @REPLCHANGED record in each partition if there have been
850 * any writes of replicated data in the partition
852 static int replmd_notify_store(struct ldb_module
*module
, struct ldb_request
*parent
)
854 struct replmd_private
*replmd_private
=
855 talloc_get_type(ldb_module_get_private(module
), struct replmd_private
);
857 while (replmd_private
->ncs
) {
859 struct nc_entry
*modified_partition
= replmd_private
->ncs
;
861 ret
= dsdb_module_save_partition_usn(module
, modified_partition
->dn
,
862 modified_partition
->mod_usn
,
863 modified_partition
->mod_usn_urgent
, parent
);
864 if (ret
!= LDB_SUCCESS
) {
865 DEBUG(0,(__location__
": Failed to save partition uSN for %s\n",
866 ldb_dn_get_linearized(modified_partition
->dn
)));
870 if (ldb_dn_compare(modified_partition
->dn
,
871 replmd_private
->schema_dn
) == 0) {
872 struct ldb_result
*ext_res
;
873 ret
= dsdb_module_extended(module
,
874 replmd_private
->schema_dn
,
876 DSDB_EXTENDED_SCHEMA_UPDATE_NOW_OID
,
878 DSDB_FLAG_NEXT_MODULE
,
880 if (ret
!= LDB_SUCCESS
) {
883 talloc_free(ext_res
);
886 DLIST_REMOVE(replmd_private
->ncs
, modified_partition
);
887 talloc_free(modified_partition
);
895 created a replmd_replicated_request context
897 static struct replmd_replicated_request
*replmd_ctx_init(struct ldb_module
*module
,
898 struct ldb_request
*req
)
900 struct ldb_context
*ldb
;
901 struct replmd_replicated_request
*ac
;
902 const struct GUID
*our_invocation_id
;
904 ldb
= ldb_module_get_ctx(module
);
906 ac
= talloc_zero(req
, struct replmd_replicated_request
);
915 ac
->schema
= dsdb_get_schema(ldb
, ac
);
917 ldb_debug_set(ldb
, LDB_DEBUG_FATAL
,
918 "replmd_modify: no dsdb_schema loaded");
919 DEBUG(0,(__location__
": %s\n", ldb_errstring(ldb
)));
924 /* get our invocationId */
925 our_invocation_id
= samdb_ntds_invocation_id(ldb
);
926 if (!our_invocation_id
) {
927 ldb_debug_set(ldb
, LDB_DEBUG_FATAL
,
928 "replmd_add: unable to find invocationId\n");
932 ac
->our_invocation_id
= *our_invocation_id
;
938 add a time element to a record
940 static int add_time_element(struct ldb_message
*msg
, const char *attr
, time_t t
)
942 struct ldb_message_element
*el
;
946 if (ldb_msg_find_element(msg
, attr
) != NULL
) {
950 s
= ldb_timestring(msg
, t
);
952 return LDB_ERR_OPERATIONS_ERROR
;
955 ret
= ldb_msg_add_string(msg
, attr
, s
);
956 if (ret
!= LDB_SUCCESS
) {
960 el
= ldb_msg_find_element(msg
, attr
);
961 /* always set as replace. This works because on add ops, the flag
963 el
->flags
= LDB_FLAG_MOD_REPLACE
;
969 add a uint64_t element to a record
971 static int add_uint64_element(struct ldb_context
*ldb
, struct ldb_message
*msg
,
972 const char *attr
, uint64_t v
)
974 struct ldb_message_element
*el
;
977 if (ldb_msg_find_element(msg
, attr
) != NULL
) {
981 ret
= samdb_msg_add_uint64(ldb
, msg
, msg
, attr
, v
);
982 if (ret
!= LDB_SUCCESS
) {
986 el
= ldb_msg_find_element(msg
, attr
);
987 /* always set as replace. This works because on add ops, the flag
989 el
->flags
= LDB_FLAG_MOD_REPLACE
;
994 static int replmd_replPropertyMetaData1_attid_sort(const struct replPropertyMetaData1
*m1
,
995 const struct replPropertyMetaData1
*m2
)
998 * This assignment seems inoccous, but it is critical for the
999 * system, as we need to do the comparisons as a unsigned
1000 * quantity, not signed (enums are signed integers)
1002 uint32_t attid_1
= m1
->attid
;
1003 uint32_t attid_2
= m2
->attid
;
1005 if (attid_1
== attid_2
) {
1010 * See above regarding this being an unsigned comparison.
1011 * Otherwise when the high bit is set on non-standard
1012 * attributes, they would end up first, before objectClass
1015 return attid_1
> attid_2
? 1 : -1;
1018 static int replmd_replPropertyMetaDataCtr1_verify(struct ldb_context
*ldb
,
1019 struct replPropertyMetaDataCtr1
*ctr1
,
1022 if (ctr1
->count
== 0) {
1023 ldb_debug_set(ldb
, LDB_DEBUG_FATAL
,
1024 "No elements found in replPropertyMetaData for %s!\n",
1025 ldb_dn_get_linearized(dn
));
1026 return LDB_ERR_CONSTRAINT_VIOLATION
;
1029 /* the objectClass attribute is value 0x00000000, so must be first */
1030 if (ctr1
->array
[0].attid
!= DRSUAPI_ATTID_objectClass
) {
1031 ldb_debug_set(ldb
, LDB_DEBUG_FATAL
,
1032 "No objectClass found in replPropertyMetaData for %s!\n",
1033 ldb_dn_get_linearized(dn
));
1034 return LDB_ERR_OBJECT_CLASS_VIOLATION
;
1040 static int replmd_replPropertyMetaDataCtr1_sort_and_verify(struct ldb_context
*ldb
,
1041 struct replPropertyMetaDataCtr1
*ctr1
,
1044 /* Note this is O(n^2) for the almost-sorted case, which this is */
1045 TYPESAFE_QSORT(ctr1
->array
, ctr1
->count
,
1046 replmd_replPropertyMetaData1_attid_sort
);
1047 return replmd_replPropertyMetaDataCtr1_verify(ldb
, ctr1
, dn
);
1050 static int replmd_ldb_message_element_attid_sort(const struct ldb_message_element
*e1
,
1051 const struct ldb_message_element
*e2
,
1052 const struct dsdb_schema
*schema
)
1054 const struct dsdb_attribute
*a1
;
1055 const struct dsdb_attribute
*a2
;
1058 * TODO: make this faster by caching the dsdb_attribute pointer
1059 * on the ldb_messag_element
1062 a1
= dsdb_attribute_by_lDAPDisplayName(schema
, e1
->name
);
1063 a2
= dsdb_attribute_by_lDAPDisplayName(schema
, e2
->name
);
1066 * If the elements do not have valid attribute names in the schema
1067 * (which we would prefer to think can't happen), we need to sort them
1068 * somehow. The current strategy is to put them at the end, sorted by
1071 if (a1
== NULL
&& a2
== NULL
) {
1072 return strcasecmp(e1
->name
, e2
->name
);
1080 if (a1
->attributeID_id
== a2
->attributeID_id
) {
1083 return a1
->attributeID_id
> a2
->attributeID_id
? 1 : -1;
1086 static void replmd_ldb_message_sort(struct ldb_message
*msg
,
1087 const struct dsdb_schema
*schema
)
1089 LDB_TYPESAFE_QSORT(msg
->elements
, msg
->num_elements
, schema
, replmd_ldb_message_element_attid_sort
);
1092 static int replmd_build_la_val(TALLOC_CTX
*mem_ctx
, struct ldb_val
*v
, struct dsdb_dn
*dsdb_dn
,
1093 const struct GUID
*invocation_id
,
1094 uint64_t local_usn
, NTTIME nttime
);
1096 static int parsed_dn_compare(struct parsed_dn
*pdn1
, struct parsed_dn
*pdn2
);
1098 static int get_parsed_dns(struct ldb_module
*module
, TALLOC_CTX
*mem_ctx
,
1099 struct ldb_message_element
*el
, struct parsed_dn
**pdn
,
1100 const char *ldap_oid
, struct ldb_request
*parent
);
1102 static int check_parsed_dn_duplicates(struct ldb_module
*module
,
1103 struct ldb_message_element
*el
,
1104 struct parsed_dn
*pdn
);
1107 fix up linked attributes in replmd_add.
1108 This involves setting up the right meta-data in extended DN
1109 components, and creating backlinks to the object
1111 static int replmd_add_fix_la(struct ldb_module
*module
, TALLOC_CTX
*mem_ctx
,
1112 struct replmd_private
*replmd_private
,
1113 struct ldb_message_element
*el
,
1114 struct replmd_replicated_request
*ac
,
1116 struct ldb_dn
*forward_dn
,
1117 const struct dsdb_attribute
*sa
,
1118 struct ldb_request
*parent
)
1121 TALLOC_CTX
*tmp_ctx
= talloc_new(mem_ctx
);
1122 struct ldb_context
*ldb
= ldb_module_get_ctx(module
);
1123 struct parsed_dn
*pdn
;
1124 /* We will take a reference to the schema in replmd_add_backlink */
1125 const struct dsdb_schema
*schema
= dsdb_get_schema(ldb
, NULL
);
1126 struct ldb_val
*new_values
= NULL
;
1129 if (dsdb_check_single_valued_link(sa
, el
) == LDB_SUCCESS
) {
1130 el
->flags
|= LDB_FLAG_INTERNAL_DISABLE_SINGLE_VALUE_CHECK
;
1132 ldb_asprintf_errstring(ldb
,
1133 "Attribute %s is single valued but "
1134 "more than one value has been supplied",
1136 talloc_free(tmp_ctx
);
1137 return LDB_ERR_CONSTRAINT_VIOLATION
;
1141 * At the successful end of these functions el->values is
1142 * overwritten with new_values. However get_parsed_dns()
1143 * points p->v at the supplied el and it effectively gets used
1144 * as a working area by replmd_build_la_val(). So we must
1145 * duplicate it because our caller only called
1146 * ldb_msg_copy_shallow().
1149 el
->values
= talloc_memdup(tmp_ctx
,
1151 sizeof(el
->values
[0]) * el
->num_values
);
1152 if (el
->values
== NULL
) {
1153 ldb_module_oom(module
);
1154 talloc_free(tmp_ctx
);
1155 return LDB_ERR_OPERATIONS_ERROR
;
1158 ret
= get_parsed_dns(module
, tmp_ctx
, el
, &pdn
,
1159 sa
->syntax
->ldap_oid
, parent
);
1160 if (ret
!= LDB_SUCCESS
) {
1161 talloc_free(tmp_ctx
);
1165 ret
= check_parsed_dn_duplicates(module
, el
, pdn
);
1166 if (ret
!= LDB_SUCCESS
) {
1167 talloc_free(tmp_ctx
);
1171 new_values
= talloc_array(tmp_ctx
, struct ldb_val
, el
->num_values
);
1172 if (new_values
== NULL
) {
1173 ldb_module_oom(module
);
1174 talloc_free(tmp_ctx
);
1175 return LDB_ERR_OPERATIONS_ERROR
;
1178 for (i
= 0; i
< el
->num_values
; i
++) {
1179 struct parsed_dn
*p
= &pdn
[i
];
1180 ret
= replmd_build_la_val(new_values
, p
->v
, p
->dsdb_dn
,
1181 &ac
->our_invocation_id
,
1183 if (ret
!= LDB_SUCCESS
) {
1184 talloc_free(tmp_ctx
);
1188 ret
= replmd_defer_add_backlink(module
, replmd_private
,
1190 forward_dn
, &p
->guid
, true, sa
,
1192 if (ret
!= LDB_SUCCESS
) {
1193 talloc_free(tmp_ctx
);
1197 new_values
[i
] = *p
->v
;
1199 el
->values
= talloc_steal(mem_ctx
, new_values
);
1201 talloc_free(tmp_ctx
);
1205 static int replmd_add_make_extended_dn(struct ldb_request
*req
,
1206 const DATA_BLOB
*guid_blob
,
1207 struct ldb_dn
**_extended_dn
)
1210 const DATA_BLOB
*sid_blob
;
1211 /* Calculate an extended DN for any linked attributes */
1212 struct ldb_dn
*extended_dn
= ldb_dn_copy(req
, req
->op
.add
.message
->dn
);
1214 return LDB_ERR_OPERATIONS_ERROR
;
1216 ret
= ldb_dn_set_extended_component(extended_dn
, "GUID", guid_blob
);
1217 if (ret
!= LDB_SUCCESS
) {
1221 sid_blob
= ldb_msg_find_ldb_val(req
->op
.add
.message
, "objectSID");
1222 if (sid_blob
!= NULL
) {
1223 ret
= ldb_dn_set_extended_component(extended_dn
, "SID", sid_blob
);
1224 if (ret
!= LDB_SUCCESS
) {
1228 *_extended_dn
= extended_dn
;
1233 intercept add requests
1235 static int replmd_add(struct ldb_module
*module
, struct ldb_request
*req
)
1237 struct ldb_context
*ldb
;
1238 struct ldb_control
*control
;
1239 struct replmd_replicated_request
*ac
;
1240 enum ndr_err_code ndr_err
;
1241 struct ldb_request
*down_req
;
1242 struct ldb_message
*msg
;
1243 const DATA_BLOB
*guid_blob
;
1244 DATA_BLOB guid_blob_stack
;
1246 uint8_t guid_data
[16];
1247 struct replPropertyMetaDataBlob nmd
;
1248 struct ldb_val nmd_value
;
1249 struct ldb_dn
*extended_dn
= NULL
;
1252 * The use of a time_t here seems odd, but as the NTTIME
1253 * elements are actually declared as NTTIME_1sec in the IDL,
1254 * getting a higher resolution timestamp is not required.
1256 time_t t
= time(NULL
);
1261 unsigned int functional_level
;
1263 bool allow_add_guid
= false;
1264 bool remove_current_guid
= false;
1265 bool is_urgent
= false;
1266 bool is_schema_nc
= false;
1267 struct ldb_message_element
*objectclass_el
;
1268 struct replmd_private
*replmd_private
=
1269 talloc_get_type_abort(ldb_module_get_private(module
), struct replmd_private
);
1271 /* check if there's a show relax control (used by provision to say 'I know what I'm doing') */
1272 control
= ldb_request_get_control(req
, LDB_CONTROL_RELAX_OID
);
1274 allow_add_guid
= true;
1277 /* do not manipulate our control entries */
1278 if (ldb_dn_is_special(req
->op
.add
.message
->dn
)) {
1279 return ldb_next_request(module
, req
);
1282 ldb
= ldb_module_get_ctx(module
);
1284 ldb_debug(ldb
, LDB_DEBUG_TRACE
, "replmd_add\n");
1286 guid_blob
= ldb_msg_find_ldb_val(req
->op
.add
.message
, "objectGUID");
1287 if (guid_blob
!= NULL
) {
1288 if (!allow_add_guid
) {
1289 ldb_set_errstring(ldb
,
1290 "replmd_add: it's not allowed to add an object with objectGUID!");
1291 return LDB_ERR_UNWILLING_TO_PERFORM
;
1293 NTSTATUS status
= GUID_from_data_blob(guid_blob
,&guid
);
1294 if (!NT_STATUS_IS_OK(status
)) {
1295 ldb_set_errstring(ldb
,
1296 "replmd_add: Unable to parse the 'objectGUID' as a GUID!");
1297 return LDB_ERR_UNWILLING_TO_PERFORM
;
1299 /* we remove this attribute as it can be a string and
1300 * will not be treated correctly and then we will re-add
1301 * it later on in the good format */
1302 remove_current_guid
= true;
1306 guid
= GUID_random();
1308 guid_blob_stack
= data_blob_const(guid_data
, sizeof(guid_data
));
1310 /* This can't fail */
1311 ndr_push_struct_into_fixed_blob(&guid_blob_stack
, &guid
,
1312 (ndr_push_flags_fn_t
)ndr_push_GUID
);
1313 guid_blob
= &guid_blob_stack
;
1316 ac
= replmd_ctx_init(module
, req
);
1318 return ldb_module_oom(module
);
1321 functional_level
= dsdb_functional_level(ldb
);
1323 /* Get a sequence number from the backend */
1324 ret
= ldb_sequence_number(ldb
, LDB_SEQ_NEXT
, &ac
->seq_num
);
1325 if (ret
!= LDB_SUCCESS
) {
1330 /* we have to copy the message as the caller might have it as a const */
1331 msg
= ldb_msg_copy_shallow(ac
, req
->op
.add
.message
);
1335 return LDB_ERR_OPERATIONS_ERROR
;
1338 /* generated times */
1339 unix_to_nt_time(&now
, t
);
1340 time_str
= ldb_timestring(msg
, t
);
1344 return LDB_ERR_OPERATIONS_ERROR
;
1346 if (remove_current_guid
) {
1347 ldb_msg_remove_attr(msg
,"objectGUID");
1351 * remove autogenerated attributes
1353 ldb_msg_remove_attr(msg
, "whenCreated");
1354 ldb_msg_remove_attr(msg
, "whenChanged");
1355 ldb_msg_remove_attr(msg
, "uSNCreated");
1356 ldb_msg_remove_attr(msg
, "uSNChanged");
1357 ldb_msg_remove_attr(msg
, "replPropertyMetaData");
1360 * readd replicated attributes
1362 ret
= ldb_msg_add_string(msg
, "whenCreated", time_str
);
1363 if (ret
!= LDB_SUCCESS
) {
1369 /* build the replication meta_data */
1372 nmd
.ctr
.ctr1
.count
= msg
->num_elements
;
1373 nmd
.ctr
.ctr1
.array
= talloc_array(msg
,
1374 struct replPropertyMetaData1
,
1375 nmd
.ctr
.ctr1
.count
);
1376 if (!nmd
.ctr
.ctr1
.array
) {
1379 return LDB_ERR_OPERATIONS_ERROR
;
1382 is_schema_nc
= ldb_dn_compare_base(replmd_private
->schema_dn
, msg
->dn
) == 0;
1384 for (i
=0; i
< msg
->num_elements
;) {
1385 struct ldb_message_element
*e
= &msg
->elements
[i
];
1386 struct replPropertyMetaData1
*m
= &nmd
.ctr
.ctr1
.array
[ni
];
1387 const struct dsdb_attribute
*sa
;
1389 if (e
->name
[0] == '@') {
1394 sa
= dsdb_attribute_by_lDAPDisplayName(ac
->schema
, e
->name
);
1396 ldb_debug_set(ldb
, LDB_DEBUG_ERROR
,
1397 "replmd_add: attribute '%s' not defined in schema\n",
1400 return LDB_ERR_NO_SUCH_ATTRIBUTE
;
1403 if ((sa
->systemFlags
& DS_FLAG_ATTR_NOT_REPLICATED
) || (sa
->systemFlags
& DS_FLAG_ATTR_IS_CONSTRUCTED
)) {
1404 /* if the attribute is not replicated (0x00000001)
1405 * or constructed (0x00000004) it has no metadata
1411 if (sa
->linkID
!= 0 && functional_level
> DS_DOMAIN_FUNCTION_2000
) {
1412 if (extended_dn
== NULL
) {
1413 ret
= replmd_add_make_extended_dn(req
,
1416 if (ret
!= LDB_SUCCESS
) {
1423 * Prepare the context for the backlinks and
1424 * create metadata for the forward links. The
1425 * backlinks are created in
1426 * replmd_op_callback() after the successful
1427 * ADD of the object.
1429 ret
= replmd_add_fix_la(module
, msg
->elements
,
1434 if (ret
!= LDB_SUCCESS
) {
1438 /* linked attributes are not stored in
1439 replPropertyMetaData in FL above w2k */
1444 m
->attid
= dsdb_attribute_get_attid(sa
, is_schema_nc
);
1446 if (m
->attid
== DRSUAPI_ATTID_isDeleted
) {
1447 const struct ldb_val
*rdn_val
= ldb_dn_get_rdn_val(msg
->dn
);
1450 if (rdn_val
== NULL
) {
1453 return LDB_ERR_OPERATIONS_ERROR
;
1456 rdn
= (const char*)rdn_val
->data
;
1457 if (strcmp(rdn
, "Deleted Objects") == 0) {
1459 * Set the originating_change_time to 29/12/9999 at 23:59:59
1460 * as specified in MS-ADTS 7.1.1.4.2 Deleted Objects Container
1462 m
->originating_change_time
= DELETED_OBJECT_CONTAINER_CHANGE_TIME
;
1464 m
->originating_change_time
= now
;
1467 m
->originating_change_time
= now
;
1469 m
->originating_invocation_id
= ac
->our_invocation_id
;
1470 m
->originating_usn
= ac
->seq_num
;
1471 m
->local_usn
= ac
->seq_num
;
1474 if (!(e
->flags
& DSDB_FLAG_INTERNAL_FORCE_META_DATA
)) {
1479 e
->flags
&= ~DSDB_FLAG_INTERNAL_FORCE_META_DATA
;
1481 if (e
->num_values
!= 0) {
1486 ldb_msg_remove_element(msg
, e
);
1489 /* fix meta data count */
1490 nmd
.ctr
.ctr1
.count
= ni
;
1493 * sort meta data array
1495 ret
= replmd_replPropertyMetaDataCtr1_sort_and_verify(ldb
, &nmd
.ctr
.ctr1
, msg
->dn
);
1496 if (ret
!= LDB_SUCCESS
) {
1497 ldb_asprintf_errstring(ldb
, "%s: error during direct ADD: %s", __func__
, ldb_errstring(ldb
));
1502 /* generated NDR encoded values */
1503 ndr_err
= ndr_push_struct_blob(&nmd_value
, msg
,
1505 (ndr_push_flags_fn_t
)ndr_push_replPropertyMetaDataBlob
);
1506 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err
)) {
1509 return LDB_ERR_OPERATIONS_ERROR
;
1513 * add the autogenerated values
1515 ret
= dsdb_msg_add_guid(msg
, &guid
, "objectGUID");
1516 if (ret
!= LDB_SUCCESS
) {
1521 ret
= ldb_msg_add_string(msg
, "whenChanged", time_str
);
1522 if (ret
!= LDB_SUCCESS
) {
1527 ret
= samdb_msg_add_uint64(ldb
, msg
, msg
, "uSNCreated", ac
->seq_num
);
1528 if (ret
!= LDB_SUCCESS
) {
1533 ret
= samdb_msg_add_uint64(ldb
, msg
, msg
, "uSNChanged", ac
->seq_num
);
1534 if (ret
!= LDB_SUCCESS
) {
1539 ret
= ldb_msg_add_value(msg
, "replPropertyMetaData", &nmd_value
, NULL
);
1540 if (ret
!= LDB_SUCCESS
) {
1547 * sort the attributes by attid before storing the object
1549 replmd_ldb_message_sort(msg
, ac
->schema
);
1552 * Assert that we do have an objectClass
1554 objectclass_el
= ldb_msg_find_element(msg
, "objectClass");
1555 if (objectclass_el
== NULL
) {
1556 ldb_asprintf_errstring(ldb
, __location__
1557 ": objectClass missing on %s\n",
1558 ldb_dn_get_linearized(msg
->dn
));
1560 return LDB_ERR_OBJECT_CLASS_VIOLATION
;
1562 is_urgent
= replmd_check_urgent_objectclass(objectclass_el
,
1563 REPL_URGENT_ON_CREATE
);
1565 ac
->is_urgent
= is_urgent
;
1566 ret
= ldb_build_add_req(&down_req
, ldb
, ac
,
1569 ac
, replmd_op_callback
,
1572 LDB_REQ_SET_LOCATION(down_req
);
1573 if (ret
!= LDB_SUCCESS
) {
1578 /* current partition control is needed by "replmd_op_callback" */
1579 if (ldb_request_get_control(req
, DSDB_CONTROL_CURRENT_PARTITION_OID
) == NULL
) {
1580 ret
= ldb_request_add_control(down_req
,
1581 DSDB_CONTROL_CURRENT_PARTITION_OID
,
1583 if (ret
!= LDB_SUCCESS
) {
1589 if (functional_level
== DS_DOMAIN_FUNCTION_2000
) {
1590 ret
= ldb_request_add_control(down_req
, DSDB_CONTROL_APPLY_LINKS
, false, NULL
);
1591 if (ret
!= LDB_SUCCESS
) {
1597 /* mark the relax control done */
1599 control
->critical
= 0;
1601 /* go on with the call chain */
1602 return ldb_next_request(module
, down_req
);
1607 * update the replPropertyMetaData for one element
1609 static int replmd_update_rpmd_element(struct ldb_context
*ldb
,
1610 struct ldb_message
*msg
,
1611 struct ldb_message_element
*el
,
1612 struct ldb_message_element
*old_el
,
1613 struct replPropertyMetaDataBlob
*omd
,
1614 const struct dsdb_schema
*schema
,
1616 const struct GUID
*our_invocation_id
,
1619 bool is_forced_rodc
,
1620 struct ldb_request
*req
)
1623 const struct dsdb_attribute
*a
;
1624 struct replPropertyMetaData1
*md1
;
1625 bool may_skip
= false;
1628 a
= dsdb_attribute_by_lDAPDisplayName(schema
, el
->name
);
1630 if (ldb_request_get_control(req
, LDB_CONTROL_RELAX_OID
)) {
1631 /* allow this to make it possible for dbcheck
1632 to remove bad attributes */
1636 DEBUG(0,(__location__
": Unable to find attribute %s in schema\n",
1638 return LDB_ERR_OPERATIONS_ERROR
;
1641 attid
= dsdb_attribute_get_attid(a
, is_schema_nc
);
1643 if ((a
->systemFlags
& DS_FLAG_ATTR_NOT_REPLICATED
) || (a
->systemFlags
& DS_FLAG_ATTR_IS_CONSTRUCTED
)) {
1648 * if the attribute's value haven't changed, and this isn't
1649 * just a delete of everything then return LDB_SUCCESS Unless
1650 * we have the provision control or if the attribute is
1651 * interSiteTopologyGenerator as this page explain:
1652 * http://support.microsoft.com/kb/224815 this attribute is
1653 * periodically written by the DC responsible for the intersite
1654 * generation in a given site
1656 * Unchanged could be deleting or replacing an already-gone
1657 * thing with an unconstrained delete/empty replace or a
1658 * replace with the same value, but not an add with the same
1659 * value because that could be about adding a duplicate (which
1660 * is for someone else to error out on).
1662 if (old_el
!= NULL
&& ldb_msg_element_equal_ordered(el
, old_el
)) {
1663 if (LDB_FLAG_MOD_TYPE(el
->flags
) == LDB_FLAG_MOD_REPLACE
) {
1666 } else if (old_el
== NULL
&& el
->num_values
== 0) {
1667 if (LDB_FLAG_MOD_TYPE(el
->flags
) == LDB_FLAG_MOD_REPLACE
) {
1669 } else if (LDB_FLAG_MOD_TYPE(el
->flags
) == LDB_FLAG_MOD_DELETE
) {
1672 } else if (a
->linkID
!= 0 && LDB_FLAG_MOD_TYPE(el
->flags
) == LDB_FLAG_MOD_DELETE
&&
1673 ldb_request_get_control(req
, DSDB_CONTROL_REPLMD_VANISH_LINKS
) != NULL
) {
1675 * We intentionally skip the version bump when attempting to
1678 * The control is set by dbcheck and expunge-tombstones which
1679 * both attempt to be non-replicating. Otherwise, making an
1680 * alteration to the replication state would trigger a
1681 * broadcast of all expunged objects.
1686 if (el
->flags
& DSDB_FLAG_INTERNAL_FORCE_META_DATA
) {
1688 el
->flags
&= ~DSDB_FLAG_INTERNAL_FORCE_META_DATA
;
1692 if (strcmp(el
->name
, "interSiteTopologyGenerator") != 0 &&
1693 !ldb_request_get_control(req
, LDB_CONTROL_PROVISION_OID
)) {
1695 * allow this to make it possible for dbcheck
1696 * to rebuild broken metadata
1702 for (i
=0; i
<omd
->ctr
.ctr1
.count
; i
++) {
1704 * First check if we find it under the msDS-IntID,
1705 * then check if we find it under the OID and
1708 * This allows the administrator to simply re-write
1709 * the attributes and so restore replication, which is
1710 * likely what they will try to do.
1712 if (attid
== omd
->ctr
.ctr1
.array
[i
].attid
) {
1716 if (a
->attributeID_id
== omd
->ctr
.ctr1
.array
[i
].attid
) {
1721 if (a
->linkID
!= 0 && dsdb_functional_level(ldb
) > DS_DOMAIN_FUNCTION_2000
) {
1722 /* linked attributes are not stored in
1723 replPropertyMetaData in FL above w2k, but we do
1724 raise the seqnum for the object */
1725 if (*seq_num
== 0 &&
1726 ldb_sequence_number(ldb
, LDB_SEQ_NEXT
, seq_num
) != LDB_SUCCESS
) {
1727 return LDB_ERR_OPERATIONS_ERROR
;
1732 if (i
== omd
->ctr
.ctr1
.count
) {
1733 /* we need to add a new one */
1734 omd
->ctr
.ctr1
.array
= talloc_realloc(msg
, omd
->ctr
.ctr1
.array
,
1735 struct replPropertyMetaData1
, omd
->ctr
.ctr1
.count
+1);
1736 if (omd
->ctr
.ctr1
.array
== NULL
) {
1738 return LDB_ERR_OPERATIONS_ERROR
;
1740 omd
->ctr
.ctr1
.count
++;
1741 ZERO_STRUCT(omd
->ctr
.ctr1
.array
[i
]);
1744 /* Get a new sequence number from the backend. We only do this
1745 * if we have a change that requires a new
1746 * replPropertyMetaData element
1748 if (*seq_num
== 0) {
1749 int ret
= ldb_sequence_number(ldb
, LDB_SEQ_NEXT
, seq_num
);
1750 if (ret
!= LDB_SUCCESS
) {
1751 return LDB_ERR_OPERATIONS_ERROR
;
1755 md1
= &omd
->ctr
.ctr1
.array
[i
];
1759 if (md1
->attid
== DRSUAPI_ATTID_isDeleted
) {
1760 const struct ldb_val
*rdn_val
= ldb_dn_get_rdn_val(msg
->dn
);
1763 if (rdn_val
== NULL
) {
1765 return LDB_ERR_OPERATIONS_ERROR
;
1768 rdn
= (const char*)rdn_val
->data
;
1769 if (strcmp(rdn
, "Deleted Objects") == 0) {
1771 * Set the originating_change_time to 29/12/9999 at 23:59:59
1772 * as specified in MS-ADTS 7.1.1.4.2 Deleted Objects Container
1774 md1
->originating_change_time
= DELETED_OBJECT_CONTAINER_CHANGE_TIME
;
1776 md1
->originating_change_time
= now
;
1779 md1
->originating_change_time
= now
;
1781 md1
->originating_invocation_id
= *our_invocation_id
;
1782 md1
->originating_usn
= *seq_num
;
1783 md1
->local_usn
= *seq_num
;
1785 if (is_forced_rodc
) {
1786 /* Force version to 0 to be overridden later via replication */
1794 * Bump the replPropertyMetaData version on an attribute, and if it
1795 * has changed (or forced by leaving rdn_old NULL), update the value
1798 * This is important, as calling a modify operation may not change the
1799 * version number if the values appear unchanged, but a rename between
1800 * parents bumps this value.
1803 static int replmd_update_rpmd_rdn_attr(struct ldb_context
*ldb
,
1804 struct ldb_message
*msg
,
1805 const struct ldb_val
*rdn_new
,
1806 const struct ldb_val
*rdn_old
,
1807 struct replPropertyMetaDataBlob
*omd
,
1808 struct replmd_replicated_request
*ar
,
1811 bool is_forced_rodc
)
1813 const char *rdn_name
= ldb_dn_get_rdn_name(msg
->dn
);
1814 const struct dsdb_attribute
*rdn_attr
=
1815 dsdb_attribute_by_lDAPDisplayName(ar
->schema
, rdn_name
);
1816 const char *attr_name
= rdn_attr
!= NULL
?
1817 rdn_attr
->lDAPDisplayName
:
1819 struct ldb_message_element new_el
= {
1820 .flags
= LDB_FLAG_MOD_REPLACE
,
1823 .values
= discard_const_p(struct ldb_val
, rdn_new
)
1825 struct ldb_message_element old_el
= {
1826 .flags
= LDB_FLAG_MOD_REPLACE
,
1828 .num_values
= rdn_old
? 1 : 0,
1829 .values
= discard_const_p(struct ldb_val
, rdn_old
)
1832 if (ldb_msg_element_equal_ordered(&new_el
, &old_el
) == false) {
1833 int ret
= ldb_msg_add(msg
, &new_el
, LDB_FLAG_MOD_REPLACE
);
1834 if (ret
!= LDB_SUCCESS
) {
1835 return ldb_oom(ldb
);
1839 return replmd_update_rpmd_element(ldb
, msg
, &new_el
, NULL
,
1840 omd
, ar
->schema
, &ar
->seq_num
,
1841 &ar
->our_invocation_id
,
1842 now
, is_schema_nc
, is_forced_rodc
,
1847 static uint64_t find_max_local_usn(struct replPropertyMetaDataBlob omd
)
1849 uint32_t count
= omd
.ctr
.ctr1
.count
;
1852 for (i
=0; i
< count
; i
++) {
1853 struct replPropertyMetaData1 m
= omd
.ctr
.ctr1
.array
[i
];
1854 if (max
< m
.local_usn
) {
1862 * update the replPropertyMetaData object each time we modify an
1863 * object. This is needed for DRS replication, as the merge on the
1864 * client is based on this object
1866 static int replmd_update_rpmd(struct ldb_module
*module
,
1867 const struct dsdb_schema
*schema
,
1868 struct ldb_request
*req
,
1869 const char * const *rename_attrs
,
1870 struct ldb_message
*msg
, uint64_t *seq_num
,
1871 time_t t
, bool is_schema_nc
,
1872 bool *is_urgent
, bool *rodc
)
1874 const struct ldb_val
*omd_value
;
1875 enum ndr_err_code ndr_err
;
1876 struct replPropertyMetaDataBlob omd
;
1879 const struct GUID
*our_invocation_id
;
1881 const char * const *attrs
= NULL
;
1882 const char * const attrs2
[] = { "uSNChanged", "objectClass", "instanceType", NULL
};
1883 struct ldb_result
*res
;
1884 struct ldb_context
*ldb
;
1885 struct ldb_message_element
*objectclass_el
;
1886 enum urgent_situation situation
;
1887 bool rmd_is_provided
;
1888 bool rmd_is_just_resorted
= false;
1889 const char *not_rename_attrs
[4 + msg
->num_elements
];
1890 bool is_forced_rodc
= false;
1893 attrs
= rename_attrs
;
1895 for (i
= 0; i
< msg
->num_elements
; i
++) {
1896 not_rename_attrs
[i
] = msg
->elements
[i
].name
;
1898 not_rename_attrs
[i
] = "replPropertyMetaData";
1899 not_rename_attrs
[i
+1] = "objectClass";
1900 not_rename_attrs
[i
+2] = "instanceType";
1901 not_rename_attrs
[i
+3] = NULL
;
1902 attrs
= not_rename_attrs
;
1905 ldb
= ldb_module_get_ctx(module
);
1907 ret
= samdb_rodc(ldb
, rodc
);
1908 if (ret
!= LDB_SUCCESS
) {
1909 DEBUG(4, (__location__
": unable to tell if we are an RODC\n"));
1914 ldb_request_get_control(req
, DSDB_CONTROL_FORCE_RODC_LOCAL_CHANGE
)) {
1915 is_forced_rodc
= true;
1918 our_invocation_id
= samdb_ntds_invocation_id(ldb
);
1919 if (!our_invocation_id
) {
1920 /* this happens during an initial vampire while
1921 updating the schema */
1922 DEBUG(5,("No invocationID - skipping replPropertyMetaData update\n"));
1926 unix_to_nt_time(&now
, t
);
1928 if (ldb_request_get_control(req
, DSDB_CONTROL_CHANGEREPLMETADATA_OID
)) {
1929 rmd_is_provided
= true;
1930 if (ldb_request_get_control(req
, DSDB_CONTROL_CHANGEREPLMETADATA_RESORT_OID
)) {
1931 rmd_is_just_resorted
= true;
1934 rmd_is_provided
= false;
1937 /* if isDeleted is present and is TRUE, then we consider we are deleting,
1938 * otherwise we consider we are updating */
1939 if (ldb_msg_check_string_attribute(msg
, "isDeleted", "TRUE")) {
1940 situation
= REPL_URGENT_ON_DELETE
;
1941 } else if (rename_attrs
) {
1942 situation
= REPL_URGENT_ON_CREATE
| REPL_URGENT_ON_DELETE
;
1944 situation
= REPL_URGENT_ON_UPDATE
;
1947 if (rmd_is_provided
) {
1948 /* In this case the change_replmetadata control was supplied */
1949 /* We check that it's the only attribute that is provided
1950 * (it's a rare case so it's better to keep the code simpler)
1951 * We also check that the highest local_usn is bigger or the same as
1954 if( msg
->num_elements
!= 1 ||
1955 strncmp(msg
->elements
[0].name
,
1956 "replPropertyMetaData", 20) ) {
1957 DEBUG(0,(__location__
": changereplmetada control called without "\
1958 "a specified replPropertyMetaData attribute or with others\n"));
1959 return LDB_ERR_OPERATIONS_ERROR
;
1961 if (situation
!= REPL_URGENT_ON_UPDATE
) {
1962 DEBUG(0,(__location__
": changereplmetada control can't be called when deleting an object\n"));
1963 return LDB_ERR_OPERATIONS_ERROR
;
1965 omd_value
= ldb_msg_find_ldb_val(msg
, "replPropertyMetaData");
1967 DEBUG(0,(__location__
": replPropertyMetaData was not specified for Object %s\n",
1968 ldb_dn_get_linearized(msg
->dn
)));
1969 return LDB_ERR_OPERATIONS_ERROR
;
1971 ndr_err
= ndr_pull_struct_blob(omd_value
, msg
, &omd
,
1972 (ndr_pull_flags_fn_t
)ndr_pull_replPropertyMetaDataBlob
);
1973 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err
)) {
1974 DEBUG(0,(__location__
": Failed to parse replPropertyMetaData for %s\n",
1975 ldb_dn_get_linearized(msg
->dn
)));
1976 return LDB_ERR_OPERATIONS_ERROR
;
1979 ret
= dsdb_module_search_dn(module
, msg
, &res
, msg
->dn
, attrs2
,
1980 DSDB_FLAG_NEXT_MODULE
|
1981 DSDB_SEARCH_SHOW_RECYCLED
|
1982 DSDB_SEARCH_SHOW_EXTENDED_DN
|
1983 DSDB_SEARCH_SHOW_DN_IN_STORAGE_FORMAT
|
1984 DSDB_SEARCH_REVEAL_INTERNALS
, req
);
1986 if (ret
!= LDB_SUCCESS
) {
1990 if (rmd_is_just_resorted
== false) {
1991 *seq_num
= find_max_local_usn(omd
);
1993 db_seq
= ldb_msg_find_attr_as_uint64(res
->msgs
[0], "uSNChanged", 0);
1996 * The test here now allows for a new
1997 * replPropertyMetaData with no change, if was
1998 * just dbcheck re-sorting the values.
2000 if (*seq_num
<= db_seq
) {
2001 DEBUG(0,(__location__
": changereplmetada control provided but max(local_usn)" \
2002 " is less than uSNChanged (max = %lld uSNChanged = %lld)\n",
2003 (long long)*seq_num
, (long long)db_seq
));
2004 return LDB_ERR_OPERATIONS_ERROR
;
2009 /* search for the existing replPropertyMetaDataBlob. We need
2010 * to use REVEAL and ask for DNs in storage format to support
2011 * the check for values being the same in
2012 * replmd_update_rpmd_element()
2014 ret
= dsdb_module_search_dn(module
, msg
, &res
, msg
->dn
, attrs
,
2015 DSDB_FLAG_NEXT_MODULE
|
2016 DSDB_SEARCH_SHOW_RECYCLED
|
2017 DSDB_SEARCH_SHOW_EXTENDED_DN
|
2018 DSDB_SEARCH_SHOW_DN_IN_STORAGE_FORMAT
|
2019 DSDB_SEARCH_REVEAL_INTERNALS
, req
);
2020 if (ret
!= LDB_SUCCESS
) {
2024 omd_value
= ldb_msg_find_ldb_val(res
->msgs
[0], "replPropertyMetaData");
2026 DEBUG(0,(__location__
": Object %s does not have a replPropertyMetaData attribute\n",
2027 ldb_dn_get_linearized(msg
->dn
)));
2028 return LDB_ERR_OPERATIONS_ERROR
;
2031 ndr_err
= ndr_pull_struct_blob(omd_value
, msg
, &omd
,
2032 (ndr_pull_flags_fn_t
)ndr_pull_replPropertyMetaDataBlob
);
2033 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err
)) {
2034 DEBUG(0,(__location__
": Failed to parse replPropertyMetaData for %s\n",
2035 ldb_dn_get_linearized(msg
->dn
)));
2036 return LDB_ERR_OPERATIONS_ERROR
;
2039 if (omd
.version
!= 1) {
2040 DEBUG(0,(__location__
": bad version %u in replPropertyMetaData for %s\n",
2041 omd
.version
, ldb_dn_get_linearized(msg
->dn
)));
2042 return LDB_ERR_OPERATIONS_ERROR
;
2045 for (i
=0; i
<msg
->num_elements
;) {
2046 struct ldb_message_element
*el
= &msg
->elements
[i
];
2047 struct ldb_message_element
*old_el
;
2049 old_el
= ldb_msg_find_element(res
->msgs
[0], el
->name
);
2050 ret
= replmd_update_rpmd_element(ldb
, msg
, el
, old_el
,
2051 &omd
, schema
, seq_num
,
2056 if (ret
!= LDB_SUCCESS
) {
2060 if (!*is_urgent
&& (situation
== REPL_URGENT_ON_UPDATE
)) {
2061 *is_urgent
= replmd_check_urgent_attribute(el
);
2064 if (!(el
->flags
& DSDB_FLAG_INTERNAL_FORCE_META_DATA
)) {
2069 el
->flags
&= ~DSDB_FLAG_INTERNAL_FORCE_META_DATA
;
2071 if (el
->num_values
!= 0) {
2076 ldb_msg_remove_element(msg
, el
);
2081 * Assert that we have an objectClass attribute - this is major
2082 * corruption if we don't have this!
2084 objectclass_el
= ldb_msg_find_element(res
->msgs
[0], "objectClass");
2085 if (objectclass_el
!= NULL
) {
2087 * Now check if this objectClass means we need to do urgent replication
2089 if (!*is_urgent
&& replmd_check_urgent_objectclass(objectclass_el
,
2093 } else if (!ldb_request_get_control(req
, DSDB_CONTROL_DBCHECK
)) {
2094 ldb_asprintf_errstring(ldb
, __location__
2095 ": objectClass missing on %s\n",
2096 ldb_dn_get_linearized(msg
->dn
));
2097 return LDB_ERR_OBJECT_CLASS_VIOLATION
;
2101 * replmd_update_rpmd_element has done an update if the
2104 if (*seq_num
!= 0 || rmd_is_just_resorted
== true) {
2105 struct ldb_val
*md_value
;
2106 struct ldb_message_element
*el
;
2108 /*if we are RODC and this is a DRSR update then its ok*/
2109 if (!ldb_request_get_control(req
, DSDB_CONTROL_REPLICATED_UPDATE_OID
)
2110 && !ldb_request_get_control(req
, DSDB_CONTROL_DBCHECK_MODIFY_RO_REPLICA
)
2111 && !is_forced_rodc
) {
2112 unsigned instanceType
;
2115 ldb_set_errstring(ldb
, "RODC modify is forbidden!");
2116 return LDB_ERR_REFERRAL
;
2119 instanceType
= ldb_msg_find_attr_as_uint(res
->msgs
[0], "instanceType", INSTANCE_TYPE_WRITE
);
2120 if (!(instanceType
& INSTANCE_TYPE_WRITE
)) {
2121 return ldb_error(ldb
, LDB_ERR_UNWILLING_TO_PERFORM
,
2122 "cannot change replicated attribute on partial replica");
2126 md_value
= talloc(msg
, struct ldb_val
);
2127 if (md_value
== NULL
) {
2129 return LDB_ERR_OPERATIONS_ERROR
;
2132 ret
= replmd_replPropertyMetaDataCtr1_sort_and_verify(ldb
, &omd
.ctr
.ctr1
, msg
->dn
);
2133 if (ret
!= LDB_SUCCESS
) {
2134 ldb_asprintf_errstring(ldb
, "%s: %s", __func__
, ldb_errstring(ldb
));
2138 ndr_err
= ndr_push_struct_blob(md_value
, msg
, &omd
,
2139 (ndr_push_flags_fn_t
)ndr_push_replPropertyMetaDataBlob
);
2140 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err
)) {
2141 DEBUG(0,(__location__
": Failed to marshall replPropertyMetaData for %s\n",
2142 ldb_dn_get_linearized(msg
->dn
)));
2143 return LDB_ERR_OPERATIONS_ERROR
;
2146 ret
= ldb_msg_add_empty(msg
, "replPropertyMetaData", LDB_FLAG_MOD_REPLACE
, &el
);
2147 if (ret
!= LDB_SUCCESS
) {
2148 DEBUG(0,(__location__
": Failed to add updated replPropertyMetaData %s\n",
2149 ldb_dn_get_linearized(msg
->dn
)));
2154 el
->values
= md_value
;
2160 static int parsed_dn_compare(struct parsed_dn
*pdn1
, struct parsed_dn
*pdn2
)
2162 int ret
= ndr_guid_compare(&pdn1
->guid
, &pdn2
->guid
);
2164 return data_blob_cmp(&pdn1
->dsdb_dn
->extra_part
,
2165 &pdn2
->dsdb_dn
->extra_part
);
2171 get a series of message element values as an array of DNs and GUIDs
2172 the result is sorted by GUID
2174 static int get_parsed_dns(struct ldb_module
*module
, TALLOC_CTX
*mem_ctx
,
2175 struct ldb_message_element
*el
, struct parsed_dn
**pdn
,
2176 const char *ldap_oid
, struct ldb_request
*parent
)
2179 bool values_are_sorted
= true;
2180 struct ldb_context
*ldb
= ldb_module_get_ctx(module
);
2187 (*pdn
) = talloc_array(mem_ctx
, struct parsed_dn
, el
->num_values
);
2189 ldb_module_oom(module
);
2190 return LDB_ERR_OPERATIONS_ERROR
;
2193 for (i
=0; i
<el
->num_values
; i
++) {
2194 struct ldb_val
*v
= &el
->values
[i
];
2197 struct parsed_dn
*p
;
2201 p
->dsdb_dn
= dsdb_dn_parse(*pdn
, ldb
, v
, ldap_oid
);
2202 if (p
->dsdb_dn
== NULL
) {
2203 return LDB_ERR_INVALID_DN_SYNTAX
;
2206 dn
= p
->dsdb_dn
->dn
;
2208 status
= dsdb_get_extended_dn_guid(dn
, &p
->guid
, "GUID");
2209 if (NT_STATUS_EQUAL(status
, NT_STATUS_OBJECT_NAME_NOT_FOUND
) ||
2210 unlikely(GUID_all_zero(&p
->guid
))) {
2211 /* we got a DN without a GUID - go find the GUID */
2212 int ret
= dsdb_module_guid_by_dn(module
, dn
, &p
->guid
, parent
);
2213 if (ret
!= LDB_SUCCESS
) {
2214 char *dn_str
= NULL
;
2215 dn_str
= ldb_dn_get_extended_linearized(mem_ctx
,
2217 ldb_asprintf_errstring(ldb
,
2218 "Unable to find GUID for DN %s\n",
2220 if (ret
== LDB_ERR_NO_SUCH_OBJECT
&&
2221 LDB_FLAG_MOD_TYPE(el
->flags
) == LDB_FLAG_MOD_DELETE
&&
2222 ldb_attr_cmp(el
->name
, "member") == 0) {
2223 return LDB_ERR_UNWILLING_TO_PERFORM
;
2227 ret
= dsdb_set_extended_dn_guid(dn
, &p
->guid
, "GUID");
2228 if (ret
!= LDB_SUCCESS
) {
2231 } else if (!NT_STATUS_IS_OK(status
)) {
2232 return LDB_ERR_OPERATIONS_ERROR
;
2234 if (i
> 0 && values_are_sorted
) {
2235 int cmp
= parsed_dn_compare(p
, &(*pdn
)[i
- 1]);
2237 values_are_sorted
= false;
2240 /* keep a pointer to the original ldb_val */
2243 if (! values_are_sorted
) {
2244 TYPESAFE_QSORT(*pdn
, el
->num_values
, parsed_dn_compare
);
2250 * Get a series of trusted message element values. The result is sorted by
2251 * GUID, even though the GUIDs might not be known. That works because we trust
2252 * the database to give us the elements like that if the
2253 * replmd_private->sorted_links flag is set.
2255 * We also ensure that the links are in the Functional Level 2003
2256 * linked attributes format.
2258 static int get_parsed_dns_trusted_fallback(struct ldb_module
*module
,
2259 struct replmd_private
*replmd_private
,
2260 TALLOC_CTX
*mem_ctx
,
2261 struct ldb_message_element
*el
,
2262 struct parsed_dn
**pdn
,
2263 const char *ldap_oid
,
2264 struct ldb_request
*parent
)
2272 if (!replmd_private
->sorted_links
) {
2273 /* We need to sort the list. This is the slow old path we want
2276 ret
= get_parsed_dns(module
, mem_ctx
, el
, pdn
, ldap_oid
,
2278 if (ret
!= LDB_SUCCESS
) {
2282 ret
= get_parsed_dns_trusted(mem_ctx
, el
, pdn
);
2283 if (ret
!= LDB_SUCCESS
) {
2284 ldb_module_oom(module
);
2285 return LDB_ERR_OPERATIONS_ERROR
;
2290 * This upgrades links to FL2003 style, and sorts the result
2291 * if that was needed.
2293 * TODO: Add a database feature that asserts we have no FL2000
2294 * style links to avoid this check or add a feature that
2295 * uses a similar check to find sorted/unsorted links
2296 * for an on-the-fly upgrade.
2299 ret
= replmd_check_upgrade_links(ldb_module_get_ctx(module
),
2300 *pdn
, el
->num_values
,
2303 if (ret
!= LDB_SUCCESS
) {
2311 Return LDB_SUCCESS if a parsed_dn list contains no duplicate values,
2312 otherwise an error code. For compatibility the error code differs depending
2313 on whether or not the attribute is "member".
2315 As always, the parsed_dn list is assumed to be sorted.
2317 static int check_parsed_dn_duplicates(struct ldb_module
*module
,
2318 struct ldb_message_element
*el
,
2319 struct parsed_dn
*pdn
)
2322 struct ldb_context
*ldb
= ldb_module_get_ctx(module
);
2324 for (i
= 1; i
< el
->num_values
; i
++) {
2325 struct parsed_dn
*p
= &pdn
[i
];
2326 if (parsed_dn_compare(p
, &pdn
[i
- 1]) == 0) {
2327 ldb_asprintf_errstring(ldb
,
2328 "Linked attribute %s has "
2329 "multiple identical values",
2331 if (ldb_attr_cmp(el
->name
, "member") == 0) {
2332 return LDB_ERR_ENTRY_ALREADY_EXISTS
;
2334 return LDB_ERR_ATTRIBUTE_OR_VALUE_EXISTS
;
2342 build a new extended DN, including all meta data fields
2344 RMD_FLAGS = DSDB_RMD_FLAG_* bits
2345 RMD_ADDTIME = originating_add_time
2346 RMD_INVOCID = originating_invocation_id
2347 RMD_CHANGETIME = originating_change_time
2348 RMD_ORIGINATING_USN = originating_usn
2349 RMD_LOCAL_USN = local_usn
2350 RMD_VERSION = version
2352 static int replmd_build_la_val(TALLOC_CTX
*mem_ctx
, struct ldb_val
*v
,
2353 struct dsdb_dn
*dsdb_dn
,
2354 const struct GUID
*invocation_id
,
2355 uint64_t local_usn
, NTTIME nttime
)
2357 return replmd_set_la_val(mem_ctx
, v
, dsdb_dn
, NULL
, invocation_id
,
2358 local_usn
, local_usn
, nttime
,
2359 RMD_VERSION_INITIAL
, false);
2362 static int replmd_update_la_val(TALLOC_CTX
*mem_ctx
, struct ldb_val
*v
, struct dsdb_dn
*dsdb_dn
,
2363 struct dsdb_dn
*old_dsdb_dn
, const struct GUID
*invocation_id
,
2364 uint64_t seq_num
, uint64_t local_usn
, NTTIME nttime
,
2368 check if any links need upgrading from w2k format
2370 static int replmd_check_upgrade_links(struct ldb_context
*ldb
,
2371 struct parsed_dn
*dns
, uint32_t count
,
2372 struct ldb_message_element
*el
,
2373 const char *ldap_oid
)
2376 const struct GUID
*invocation_id
= NULL
;
2377 for (i
=0; i
<count
; i
++) {
2381 if (dns
[i
].dsdb_dn
== NULL
) {
2382 ret
= really_parse_trusted_dn(dns
, ldb
, &dns
[i
],
2384 if (ret
!= LDB_SUCCESS
) {
2385 return LDB_ERR_INVALID_DN_SYNTAX
;
2389 status
= dsdb_get_extended_dn_uint32(dns
[i
].dsdb_dn
->dn
,
2390 &version
, "RMD_VERSION");
2391 if (!NT_STATUS_EQUAL(status
, NT_STATUS_OBJECT_NAME_NOT_FOUND
)) {
2393 * We optimistically assume they are all the same; if
2394 * the first one is fixed, they are all fixed.
2396 * If the first one was *not* fixed and we find a
2397 * later one that is, that is an occasion to shout
2403 DEBUG(0, ("Mixed w2k and fixed format "
2404 "linked attributes\n"));
2408 if (invocation_id
== NULL
) {
2409 invocation_id
= samdb_ntds_invocation_id(ldb
);
2410 if (invocation_id
== NULL
) {
2411 return LDB_ERR_OPERATIONS_ERROR
;
2416 /* it's an old one that needs upgrading */
2417 ret
= replmd_update_la_val(el
->values
, dns
[i
].v
,
2418 dns
[i
].dsdb_dn
, dns
[i
].dsdb_dn
,
2419 invocation_id
, 1, 1, 0, false);
2420 if (ret
!= LDB_SUCCESS
) {
2426 * This sort() is critical for the operation of
2427 * get_parsed_dns_trusted_fallback() because callers of this function
2428 * expect a sorted list, and FL2000 style links are not
2429 * sorted. In particular, as well as the upgrade case,
2430 * get_parsed_dns_trusted_fallback() is called from
2431 * replmd_delete_remove_link() even in FL2000 mode
2433 * We do not normally pay the cost of the qsort() due to the
2434 * early return in the RMD_VERSION found case.
2436 TYPESAFE_QSORT(dns
, count
, parsed_dn_compare
);
2441 Sets the value for a linked attribute, including all meta data fields
2443 see replmd_build_la_val for value names
2445 static int replmd_set_la_val(TALLOC_CTX
*mem_ctx
, struct ldb_val
*v
, struct dsdb_dn
*dsdb_dn
,
2446 struct dsdb_dn
*old_dsdb_dn
, const struct GUID
*invocation_id
,
2447 uint64_t usn
, uint64_t local_usn
, NTTIME nttime
,
2448 uint32_t version
, bool deleted
)
2450 struct ldb_dn
*dn
= dsdb_dn
->dn
;
2451 const char *tstring
, *usn_string
, *flags_string
;
2452 struct ldb_val tval
;
2454 struct ldb_val usnv
, local_usnv
;
2455 struct ldb_val vers
, flagsv
;
2456 const struct ldb_val
*old_addtime
= NULL
;
2459 const char *dnstring
;
2461 uint32_t rmd_flags
= deleted
?DSDB_RMD_FLAG_DELETED
:0;
2463 tstring
= talloc_asprintf(mem_ctx
, "%llu", (unsigned long long)nttime
);
2465 return LDB_ERR_OPERATIONS_ERROR
;
2467 tval
= data_blob_string_const(tstring
);
2469 usn_string
= talloc_asprintf(mem_ctx
, "%llu", (unsigned long long)usn
);
2471 return LDB_ERR_OPERATIONS_ERROR
;
2473 usnv
= data_blob_string_const(usn_string
);
2475 usn_string
= talloc_asprintf(mem_ctx
, "%llu", (unsigned long long)local_usn
);
2477 return LDB_ERR_OPERATIONS_ERROR
;
2479 local_usnv
= data_blob_string_const(usn_string
);
2481 status
= GUID_to_ndr_blob(invocation_id
, dn
, &iid
);
2482 if (!NT_STATUS_IS_OK(status
)) {
2483 return LDB_ERR_OPERATIONS_ERROR
;
2486 flags_string
= talloc_asprintf(mem_ctx
, "%u", rmd_flags
);
2487 if (!flags_string
) {
2488 return LDB_ERR_OPERATIONS_ERROR
;
2490 flagsv
= data_blob_string_const(flags_string
);
2492 ret
= ldb_dn_set_extended_component(dn
, "RMD_FLAGS", &flagsv
);
2493 if (ret
!= LDB_SUCCESS
) return ret
;
2495 /* get the ADDTIME from the original */
2496 if (old_dsdb_dn
!= NULL
) {
2497 old_addtime
= ldb_dn_get_extended_component(old_dsdb_dn
->dn
,
2500 if (old_addtime
== NULL
) {
2501 old_addtime
= &tval
;
2503 if (dsdb_dn
!= old_dsdb_dn
||
2504 ldb_dn_get_extended_component(dn
, "RMD_ADDTIME") == NULL
) {
2505 ret
= ldb_dn_set_extended_component(dn
, "RMD_ADDTIME", old_addtime
);
2506 if (ret
!= LDB_SUCCESS
) return ret
;
2509 /* use our invocation id */
2510 ret
= ldb_dn_set_extended_component(dn
, "RMD_INVOCID", &iid
);
2511 if (ret
!= LDB_SUCCESS
) return ret
;
2513 /* changetime is the current time */
2514 ret
= ldb_dn_set_extended_component(dn
, "RMD_CHANGETIME", &tval
);
2515 if (ret
!= LDB_SUCCESS
) return ret
;
2517 /* update the USN */
2518 ret
= ldb_dn_set_extended_component(dn
, "RMD_ORIGINATING_USN", &usnv
);
2519 if (ret
!= LDB_SUCCESS
) return ret
;
2521 ret
= ldb_dn_set_extended_component(dn
, "RMD_LOCAL_USN", &local_usnv
);
2522 if (ret
!= LDB_SUCCESS
) return ret
;
2524 vstring
= talloc_asprintf(mem_ctx
, "%lu", (unsigned long)version
);
2525 vers
= data_blob_string_const(vstring
);
2526 ret
= ldb_dn_set_extended_component(dn
, "RMD_VERSION", &vers
);
2527 if (ret
!= LDB_SUCCESS
) return ret
;
2529 dnstring
= dsdb_dn_get_extended_linearized(mem_ctx
, dsdb_dn
, 1);
2530 if (dnstring
== NULL
) {
2531 return LDB_ERR_OPERATIONS_ERROR
;
2533 *v
= data_blob_string_const(dnstring
);
2539 * Updates the value for a linked attribute, including all meta data fields
2541 static int replmd_update_la_val(TALLOC_CTX
*mem_ctx
, struct ldb_val
*v
, struct dsdb_dn
*dsdb_dn
,
2542 struct dsdb_dn
*old_dsdb_dn
, const struct GUID
*invocation_id
,
2543 uint64_t usn
, uint64_t local_usn
, NTTIME nttime
,
2546 uint32_t old_version
;
2547 uint32_t version
= RMD_VERSION_INITIAL
;
2551 * We're updating the linked attribute locally, so increase the version
2552 * by 1 so that other DCs will see the change when it gets replicated out
2554 status
= dsdb_get_extended_dn_uint32(old_dsdb_dn
->dn
, &old_version
,
2557 if (NT_STATUS_IS_OK(status
)) {
2558 version
= old_version
+ 1;
2561 return replmd_set_la_val(mem_ctx
, v
, dsdb_dn
, old_dsdb_dn
, invocation_id
,
2562 usn
, local_usn
, nttime
, version
, deleted
);
2566 handle adding a linked attribute
2568 static int replmd_modify_la_add(struct ldb_module
*module
,
2569 struct replmd_private
*replmd_private
,
2570 struct replmd_replicated_request
*ac
,
2571 struct ldb_message
*msg
,
2572 struct ldb_message_element
*el
,
2573 struct ldb_message_element
*old_el
,
2574 const struct dsdb_attribute
*schema_attr
,
2576 struct ldb_dn
*msg_dn
,
2577 struct ldb_request
*parent
)
2580 struct parsed_dn
*dns
, *old_dns
;
2581 TALLOC_CTX
*tmp_ctx
= talloc_new(msg
);
2583 struct ldb_val
*new_values
= NULL
;
2584 unsigned old_num_values
= old_el
? old_el
->num_values
: 0;
2585 unsigned num_values
= 0;
2586 unsigned max_num_values
;
2587 struct ldb_context
*ldb
= ldb_module_get_ctx(module
);
2589 unix_to_nt_time(&now
, t
);
2591 /* get the DNs to be added, fully parsed.
2593 * We need full parsing because they came off the wire and we don't
2594 * trust them, besides which we need their details to know where to put
2597 ret
= get_parsed_dns(module
, tmp_ctx
, el
, &dns
,
2598 schema_attr
->syntax
->ldap_oid
, parent
);
2599 if (ret
!= LDB_SUCCESS
) {
2600 talloc_free(tmp_ctx
);
2604 /* get the existing DNs, lazily parsed */
2605 ret
= get_parsed_dns_trusted_fallback(module
, replmd_private
,
2606 tmp_ctx
, old_el
, &old_dns
,
2607 schema_attr
->syntax
->ldap_oid
,
2610 if (ret
!= LDB_SUCCESS
) {
2611 talloc_free(tmp_ctx
);
2615 max_num_values
= old_num_values
+ el
->num_values
;
2616 if (max_num_values
< old_num_values
) {
2617 DEBUG(0, ("we seem to have overflow in replmd_modify_la_add. "
2618 "old values: %u, new values: %u, sum: %u\n",
2619 old_num_values
, el
->num_values
, max_num_values
));
2620 talloc_free(tmp_ctx
);
2621 return LDB_ERR_OPERATIONS_ERROR
;
2624 new_values
= talloc_zero_array(tmp_ctx
, struct ldb_val
, max_num_values
);
2626 if (new_values
== NULL
) {
2627 ldb_module_oom(module
);
2628 talloc_free(tmp_ctx
);
2629 return LDB_ERR_OPERATIONS_ERROR
;
2633 * For each new value, find where it would go in the list. If there is
2634 * a matching GUID there, we update the existing value; otherwise we
2638 for (i
= 0; i
< el
->num_values
; i
++) {
2639 struct parsed_dn
*exact
;
2640 struct parsed_dn
*next
;
2642 int err
= parsed_dn_find(ldb
, old_dns
, old_num_values
,
2645 dns
[i
].dsdb_dn
->extra_part
, 0,
2647 schema_attr
->syntax
->ldap_oid
,
2649 if (err
!= LDB_SUCCESS
) {
2650 talloc_free(tmp_ctx
);
2654 if (ac
->fix_link_sid
) {
2655 char *fixed_dnstring
= NULL
;
2656 struct dom_sid tmp_sid
= { 0, };
2657 DATA_BLOB sid_blob
= data_blob_null
;
2658 enum ndr_err_code ndr_err
;
2662 if (exact
== NULL
) {
2663 talloc_free(tmp_ctx
);
2664 return ldb_operr(ldb
);
2667 if (dns
[i
].dsdb_dn
->dn_format
!= DSDB_NORMAL_DN
) {
2668 talloc_free(tmp_ctx
);
2669 return ldb_operr(ldb
);
2673 * Only "<GUID=...><SID=...>" is allowed.
2675 * We get the GUID to just to find the old
2676 * value and the SID in order to add it
2677 * to the found value.
2680 num
= ldb_dn_get_comp_num(dns
[i
].dsdb_dn
->dn
);
2682 talloc_free(tmp_ctx
);
2683 return ldb_operr(ldb
);
2686 num
= ldb_dn_get_extended_comp_num(dns
[i
].dsdb_dn
->dn
);
2688 talloc_free(tmp_ctx
);
2689 return ldb_operr(ldb
);
2692 status
= dsdb_get_extended_dn_sid(exact
->dsdb_dn
->dn
,
2694 if (NT_STATUS_EQUAL(status
, NT_STATUS_OBJECT_NAME_NOT_FOUND
)) {
2695 /* this is what we expect */
2696 } else if (NT_STATUS_IS_OK(status
)) {
2697 struct GUID_txt_buf guid_str
;
2698 ldb_debug_set(ldb
, LDB_DEBUG_FATAL
,
2699 "i[%u] SID NOT MISSING... Attribute %s already "
2700 "exists for target GUID %s, SID %s, DN: %s",
2702 GUID_buf_string(&exact
->guid
,
2704 dom_sid_string(tmp_ctx
, &tmp_sid
),
2705 dsdb_dn_get_extended_linearized(tmp_ctx
,
2706 exact
->dsdb_dn
, 1));
2707 talloc_free(tmp_ctx
);
2708 return LDB_ERR_ATTRIBUTE_OR_VALUE_EXISTS
;
2710 talloc_free(tmp_ctx
);
2711 return ldb_operr(ldb
);
2714 status
= dsdb_get_extended_dn_sid(dns
[i
].dsdb_dn
->dn
,
2716 if (!NT_STATUS_IS_OK(status
)) {
2717 struct GUID_txt_buf guid_str
;
2718 ldb_asprintf_errstring(ldb
,
2719 "NO SID PROVIDED... Attribute %s already "
2720 "exists for target GUID %s",
2722 GUID_buf_string(&exact
->guid
,
2724 talloc_free(tmp_ctx
);
2725 return LDB_ERR_ATTRIBUTE_OR_VALUE_EXISTS
;
2728 ndr_err
= ndr_push_struct_blob(&sid_blob
, tmp_ctx
, &tmp_sid
,
2729 (ndr_push_flags_fn_t
)ndr_push_dom_sid
);
2730 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err
)) {
2731 talloc_free(tmp_ctx
);
2732 return ldb_operr(ldb
);
2735 ret
= ldb_dn_set_extended_component(exact
->dsdb_dn
->dn
, "SID", &sid_blob
);
2736 data_blob_free(&sid_blob
);
2737 if (ret
!= LDB_SUCCESS
) {
2738 talloc_free(tmp_ctx
);
2742 fixed_dnstring
= dsdb_dn_get_extended_linearized(
2743 new_values
, exact
->dsdb_dn
, 1);
2744 if (fixed_dnstring
== NULL
) {
2745 talloc_free(tmp_ctx
);
2746 return ldb_operr(ldb
);
2750 * We just replace the existing value...
2752 *exact
->v
= data_blob_string_const(fixed_dnstring
);
2757 if (exact
!= NULL
) {
2759 * We are trying to add one that exists, which is only
2760 * allowed if it was previously deleted.
2762 * When we do undelete a link we change it in place.
2763 * It will be copied across into the right spot in due
2767 rmd_flags
= dsdb_dn_rmd_flags(exact
->dsdb_dn
->dn
);
2769 if (!(rmd_flags
& DSDB_RMD_FLAG_DELETED
)) {
2770 struct GUID_txt_buf guid_str
;
2771 ldb_asprintf_errstring(ldb
,
2772 "Attribute %s already "
2773 "exists for target GUID %s",
2775 GUID_buf_string(&exact
->guid
,
2777 talloc_free(tmp_ctx
);
2778 /* error codes for 'member' need to be
2780 if (ldb_attr_cmp(el
->name
, "member") == 0) {
2781 return LDB_ERR_ENTRY_ALREADY_EXISTS
;
2783 return LDB_ERR_ATTRIBUTE_OR_VALUE_EXISTS
;
2787 ret
= replmd_update_la_val(new_values
, exact
->v
,
2790 &ac
->our_invocation_id
,
2791 ac
->seq_num
, ac
->seq_num
,
2793 if (ret
!= LDB_SUCCESS
) {
2794 talloc_free(tmp_ctx
);
2798 ret
= replmd_add_backlink(module
, replmd_private
,
2805 if (ret
!= LDB_SUCCESS
) {
2806 talloc_free(tmp_ctx
);
2812 * Here we don't have an exact match.
2814 * If next is NULL, this one goes beyond the end of the
2815 * existing list, so we need to add all of those ones first.
2817 * If next is not NULL, we need to add all the ones before
2821 offset
= old_num_values
;
2823 /* next should have been parsed, but let's make sure */
2824 if (next
->dsdb_dn
== NULL
) {
2825 ret
= really_parse_trusted_dn(tmp_ctx
, ldb
, next
,
2826 schema_attr
->syntax
->ldap_oid
);
2827 if (ret
!= LDB_SUCCESS
) {
2828 talloc_free(tmp_ctx
);
2832 offset
= MIN(next
- old_dns
, old_num_values
);
2835 /* put all the old ones before next on the list */
2836 for (; j
< offset
; j
++) {
2837 new_values
[num_values
] = *old_dns
[j
].v
;
2841 ret
= replmd_add_backlink(module
, replmd_private
,
2846 if (ret
!= LDB_SUCCESS
) {
2847 talloc_free(tmp_ctx
);
2850 /* Make the new linked attribute ldb_val. */
2851 ret
= replmd_build_la_val(new_values
, &new_values
[num_values
],
2852 dns
[i
].dsdb_dn
, &ac
->our_invocation_id
,
2854 if (ret
!= LDB_SUCCESS
) {
2855 talloc_free(tmp_ctx
);
2859 if (ret
!= LDB_SUCCESS
) {
2860 talloc_free(tmp_ctx
);
2864 /* copy the rest of the old ones (if any) */
2865 for (; j
< old_num_values
; j
++) {
2866 new_values
[num_values
] = *old_dns
[j
].v
;
2870 talloc_steal(msg
->elements
, new_values
);
2871 if (old_el
!= NULL
) {
2872 talloc_steal(msg
->elements
, old_el
->values
);
2874 el
->values
= new_values
;
2875 el
->num_values
= num_values
;
2877 talloc_free(tmp_ctx
);
2879 /* we now tell the backend to replace all existing values
2880 with the one we have constructed */
2881 el
->flags
= LDB_FLAG_MOD_REPLACE
;
2888 handle deleting all active linked attributes
2890 static int replmd_modify_la_delete(struct ldb_module
*module
,
2891 struct replmd_private
*replmd_private
,
2892 struct replmd_replicated_request
*ac
,
2893 struct ldb_message
*msg
,
2894 struct ldb_message_element
*el
,
2895 struct ldb_message_element
*old_el
,
2896 const struct dsdb_attribute
*schema_attr
,
2898 struct ldb_dn
*msg_dn
,
2899 struct ldb_request
*parent
)
2902 struct parsed_dn
*dns
, *old_dns
;
2903 TALLOC_CTX
*tmp_ctx
= NULL
;
2905 struct ldb_context
*ldb
= ldb_module_get_ctx(module
);
2906 struct ldb_control
*vanish_links_ctrl
= NULL
;
2907 bool vanish_links
= false;
2908 unsigned int num_to_delete
= el
->num_values
;
2912 unix_to_nt_time(&now
, t
);
2914 if (old_el
== NULL
|| old_el
->num_values
== 0) {
2915 /* there is nothing to delete... */
2916 if (num_to_delete
== 0) {
2917 /* and we're deleting nothing, so that's OK */
2920 return LDB_ERR_NO_SUCH_ATTRIBUTE
;
2923 tmp_ctx
= talloc_new(msg
);
2924 if (tmp_ctx
== NULL
) {
2925 return LDB_ERR_OPERATIONS_ERROR
;
2928 ret
= get_parsed_dns(module
, tmp_ctx
, el
, &dns
,
2929 schema_attr
->syntax
->ldap_oid
, parent
);
2930 if (ret
!= LDB_SUCCESS
) {
2931 talloc_free(tmp_ctx
);
2935 ret
= get_parsed_dns_trusted_fallback(module
, replmd_private
,
2936 tmp_ctx
, old_el
, &old_dns
,
2937 schema_attr
->syntax
->ldap_oid
,
2940 if (ret
!= LDB_SUCCESS
) {
2941 talloc_free(tmp_ctx
);
2945 vanish_links_ctrl
= ldb_request_get_control(parent
, DSDB_CONTROL_REPLMD_VANISH_LINKS
);
2946 if (vanish_links_ctrl
) {
2947 vanish_links
= true;
2948 vanish_links_ctrl
->critical
= false;
2951 /* we empty out el->values here to avoid damage if we return early. */
2956 * If vanish links is set, we are actually removing members of
2957 * old_el->values; otherwise we are just marking them deleted.
2959 * There is a special case when no values are given: we remove them
2960 * all. When we have the vanish_links control we just have to remove
2961 * the backlinks and change our element to replace the existing values
2962 * with the empty list.
2965 if (num_to_delete
== 0) {
2966 for (i
= 0; i
< old_el
->num_values
; i
++) {
2967 struct parsed_dn
*p
= &old_dns
[i
];
2968 if (p
->dsdb_dn
== NULL
) {
2969 ret
= really_parse_trusted_dn(tmp_ctx
, ldb
, p
,
2970 schema_attr
->syntax
->ldap_oid
);
2971 if (ret
!= LDB_SUCCESS
) {
2975 ret
= replmd_add_backlink(module
, replmd_private
,
2976 ac
->schema
, msg_dn
, &p
->guid
,
2979 if (ret
!= LDB_SUCCESS
) {
2980 talloc_free(tmp_ctx
);
2987 rmd_flags
= dsdb_dn_rmd_flags(p
->dsdb_dn
->dn
);
2988 if (rmd_flags
& DSDB_RMD_FLAG_DELETED
) {
2992 ret
= replmd_update_la_val(old_el
->values
, p
->v
,
2993 p
->dsdb_dn
, p
->dsdb_dn
,
2994 &ac
->our_invocation_id
,
2995 ac
->seq_num
, ac
->seq_num
,
2997 if (ret
!= LDB_SUCCESS
) {
2998 talloc_free(tmp_ctx
);
3004 el
->flags
= LDB_FLAG_MOD_REPLACE
;
3005 talloc_free(tmp_ctx
);
3011 for (i
= 0; i
< num_to_delete
; i
++) {
3012 struct parsed_dn
*p
= &dns
[i
];
3013 struct parsed_dn
*exact
= NULL
;
3014 struct parsed_dn
*next
= NULL
;
3015 ret
= parsed_dn_find(ldb
, old_dns
, old_el
->num_values
,
3018 p
->dsdb_dn
->extra_part
, 0,
3020 schema_attr
->syntax
->ldap_oid
,
3022 if (ret
!= LDB_SUCCESS
) {
3023 talloc_free(tmp_ctx
);
3026 if (exact
== NULL
) {
3027 struct GUID_txt_buf buf
;
3028 ldb_asprintf_errstring(ldb
, "Attribute %s doesn't "
3029 "exist for target GUID %s",
3031 GUID_buf_string(&p
->guid
, &buf
));
3032 if (ldb_attr_cmp(el
->name
, "member") == 0) {
3033 talloc_free(tmp_ctx
);
3034 return LDB_ERR_UNWILLING_TO_PERFORM
;
3036 talloc_free(tmp_ctx
);
3037 return LDB_ERR_NO_SUCH_ATTRIBUTE
;
3042 if (CHECK_DEBUGLVL(5)) {
3043 rmd_flags
= dsdb_dn_rmd_flags(exact
->dsdb_dn
->dn
);
3044 if ((rmd_flags
& DSDB_RMD_FLAG_DELETED
)) {
3045 struct GUID_txt_buf buf
;
3046 const char *guid_str
= \
3047 GUID_buf_string(&p
->guid
, &buf
);
3048 DEBUG(5, ("Deleting deleted linked "
3049 "attribute %s to %s, because "
3050 "vanish_links control is set\n",
3051 el
->name
, guid_str
));
3055 /* remove the backlink */
3056 ret
= replmd_add_backlink(module
,
3063 if (ret
!= LDB_SUCCESS
) {
3064 talloc_free(tmp_ctx
);
3068 /* We flag the deletion and tidy it up later. */
3073 rmd_flags
= dsdb_dn_rmd_flags(exact
->dsdb_dn
->dn
);
3075 if (rmd_flags
& DSDB_RMD_FLAG_DELETED
) {
3076 struct GUID_txt_buf buf
;
3077 const char *guid_str
= GUID_buf_string(&p
->guid
, &buf
);
3078 ldb_asprintf_errstring(ldb
, "Attribute %s already "
3079 "deleted for target GUID %s",
3080 el
->name
, guid_str
);
3081 if (ldb_attr_cmp(el
->name
, "member") == 0) {
3082 talloc_free(tmp_ctx
);
3083 return LDB_ERR_UNWILLING_TO_PERFORM
;
3085 talloc_free(tmp_ctx
);
3086 return LDB_ERR_NO_SUCH_ATTRIBUTE
;
3090 ret
= replmd_update_la_val(old_el
->values
, exact
->v
,
3091 exact
->dsdb_dn
, exact
->dsdb_dn
,
3092 &ac
->our_invocation_id
,
3093 ac
->seq_num
, ac
->seq_num
,
3095 if (ret
!= LDB_SUCCESS
) {
3096 talloc_free(tmp_ctx
);
3099 ret
= replmd_add_backlink(module
, replmd_private
,
3104 if (ret
!= LDB_SUCCESS
) {
3105 talloc_free(tmp_ctx
);
3112 struct ldb_val
*tmp_vals
= NULL
;
3114 tmp_vals
= talloc_array(tmp_ctx
, struct ldb_val
,
3115 old_el
->num_values
);
3116 if (tmp_vals
== NULL
) {
3117 talloc_free(tmp_ctx
);
3118 return ldb_module_oom(module
);
3120 for (i
= 0; i
< old_el
->num_values
; i
++) {
3121 if (old_dns
[i
].v
== NULL
) {
3124 tmp_vals
[j
] = *old_dns
[i
].v
;
3127 for (i
= 0; i
< j
; i
++) {
3128 old_el
->values
[i
] = tmp_vals
[i
];
3130 old_el
->num_values
= j
;
3133 el
->values
= talloc_steal(msg
->elements
, old_el
->values
);
3134 el
->num_values
= old_el
->num_values
;
3136 talloc_free(tmp_ctx
);
3138 /* we now tell the backend to replace all existing values
3139 with the one we have constructed */
3140 el
->flags
= LDB_FLAG_MOD_REPLACE
;
3146 handle replacing a linked attribute
3148 static int replmd_modify_la_replace(struct ldb_module
*module
,
3149 struct replmd_private
*replmd_private
,
3150 struct replmd_replicated_request
*ac
,
3151 struct ldb_message
*msg
,
3152 struct ldb_message_element
*el
,
3153 struct ldb_message_element
*old_el
,
3154 const struct dsdb_attribute
*schema_attr
,
3156 struct ldb_dn
*msg_dn
,
3157 struct ldb_request
*parent
)
3159 unsigned int i
, old_i
, new_i
;
3160 struct parsed_dn
*dns
, *old_dns
;
3161 TALLOC_CTX
*tmp_ctx
= talloc_new(msg
);
3163 struct ldb_context
*ldb
= ldb_module_get_ctx(module
);
3164 struct ldb_val
*new_values
= NULL
;
3165 const char *ldap_oid
= schema_attr
->syntax
->ldap_oid
;
3166 unsigned int old_num_values
;
3167 unsigned int repl_num_values
;
3168 unsigned int max_num_values
;
3171 unix_to_nt_time(&now
, t
);
3174 * The replace operation is unlike the replace and delete cases in that
3175 * we need to look at every existing link to see whether it is being
3176 * retained or deleted. In other words, we can't avoid parsing the GUIDs.
3178 * As we are trying to combine two sorted lists, the algorithm we use
3179 * is akin to the merge phase of a merge sort. We interleave the two
3180 * lists, doing different things depending on which side the current
3183 * There are three main cases, with some sub-cases.
3185 * - a DN is in the old list but not the new one. It needs to be
3186 * marked as deleted (but left in the list).
3187 * - maybe it is already deleted, and we have less to do.
3189 * - a DN is in both lists. The old data gets replaced by the new,
3190 * and the list doesn't grow. The old link may have been marked as
3191 * deleted, in which case we undelete it.
3193 * - a DN is in the new list only. We add it in the right place.
3196 old_num_values
= old_el
? old_el
->num_values
: 0;
3197 repl_num_values
= el
->num_values
;
3198 max_num_values
= old_num_values
+ repl_num_values
;
3200 if (max_num_values
== 0) {
3201 /* There is nothing to do! */
3206 * At the successful end of these functions el->values is
3207 * overwritten with new_values. However get_parsed_dns()
3208 * points p->v at the supplied el and it effectively gets used
3209 * as a working area by replmd_build_la_val(). So we must
3210 * duplicate it because our caller only called
3211 * ldb_msg_copy_shallow().
3214 el
->values
= talloc_memdup(tmp_ctx
,
3216 sizeof(el
->values
[0]) * el
->num_values
);
3217 if (el
->values
== NULL
) {
3218 ldb_module_oom(module
);
3219 talloc_free(tmp_ctx
);
3220 return LDB_ERR_OPERATIONS_ERROR
;
3223 ret
= get_parsed_dns(module
, tmp_ctx
, el
, &dns
, ldap_oid
, parent
);
3224 if (ret
!= LDB_SUCCESS
) {
3225 talloc_free(tmp_ctx
);
3229 ret
= check_parsed_dn_duplicates(module
, el
, dns
);
3230 if (ret
!= LDB_SUCCESS
) {
3231 talloc_free(tmp_ctx
);
3235 ret
= get_parsed_dns(module
, tmp_ctx
, old_el
, &old_dns
,
3237 if (ret
!= LDB_SUCCESS
) {
3238 talloc_free(tmp_ctx
);
3242 ret
= replmd_check_upgrade_links(ldb
, old_dns
, old_num_values
,
3244 if (ret
!= LDB_SUCCESS
) {
3245 talloc_free(tmp_ctx
);
3249 new_values
= talloc_array(tmp_ctx
, struct ldb_val
, max_num_values
);
3250 if (new_values
== NULL
) {
3251 ldb_module_oom(module
);
3252 talloc_free(tmp_ctx
);
3253 return LDB_ERR_OPERATIONS_ERROR
;
3258 for (i
= 0; i
< max_num_values
; i
++) {
3260 struct parsed_dn
*old_p
, *new_p
;
3261 if (old_i
< old_num_values
&& new_i
< repl_num_values
) {
3262 old_p
= &old_dns
[old_i
];
3263 new_p
= &dns
[new_i
];
3264 cmp
= parsed_dn_compare(old_p
, new_p
);
3265 } else if (old_i
< old_num_values
) {
3266 /* the new list is empty, read the old list */
3267 old_p
= &old_dns
[old_i
];
3270 } else if (new_i
< repl_num_values
) {
3271 /* the old list is empty, read new list */
3273 new_p
= &dns
[new_i
];
3281 * An old ones that come before the next replacement
3282 * (if any). We mark it as deleted and add it to the
3285 uint32_t rmd_flags
= dsdb_dn_rmd_flags(old_p
->dsdb_dn
->dn
);
3286 if ((rmd_flags
& DSDB_RMD_FLAG_DELETED
) == 0) {
3287 ret
= replmd_update_la_val(new_values
, old_p
->v
,
3290 &ac
->our_invocation_id
,
3291 ac
->seq_num
, ac
->seq_num
,
3293 if (ret
!= LDB_SUCCESS
) {
3294 talloc_free(tmp_ctx
);
3298 ret
= replmd_add_backlink(module
, replmd_private
,
3301 &old_p
->guid
, false,
3304 if (ret
!= LDB_SUCCESS
) {
3305 talloc_free(tmp_ctx
);
3309 new_values
[i
] = *old_p
->v
;
3311 } else if (cmp
== 0) {
3313 * We are overwriting one. If it was previously
3314 * deleted, we need to add a backlink.
3316 * Note that if any RMD_FLAGs in an extended new DN
3321 ret
= replmd_update_la_val(new_values
, old_p
->v
,
3324 &ac
->our_invocation_id
,
3325 ac
->seq_num
, ac
->seq_num
,
3327 if (ret
!= LDB_SUCCESS
) {
3328 talloc_free(tmp_ctx
);
3332 rmd_flags
= dsdb_dn_rmd_flags(old_p
->dsdb_dn
->dn
);
3333 if ((rmd_flags
& DSDB_RMD_FLAG_DELETED
) != 0) {
3334 ret
= replmd_add_backlink(module
, replmd_private
,
3340 if (ret
!= LDB_SUCCESS
) {
3341 talloc_free(tmp_ctx
);
3346 new_values
[i
] = *old_p
->v
;
3351 * Replacements that don't match an existing one. We
3352 * just add them to the final list.
3354 ret
= replmd_build_la_val(new_values
,
3357 &ac
->our_invocation_id
,
3359 if (ret
!= LDB_SUCCESS
) {
3360 talloc_free(tmp_ctx
);
3363 ret
= replmd_add_backlink(module
, replmd_private
,
3369 if (ret
!= LDB_SUCCESS
) {
3370 talloc_free(tmp_ctx
);
3373 new_values
[i
] = *new_p
->v
;
3377 if (old_el
!= NULL
) {
3378 talloc_steal(msg
->elements
, old_el
->values
);
3380 el
->values
= talloc_steal(msg
->elements
, new_values
);
3382 talloc_free(tmp_ctx
);
3384 el
->flags
= LDB_FLAG_MOD_REPLACE
;
3391 handle linked attributes in modify requests
3393 static int replmd_modify_handle_linked_attribs(struct ldb_module
*module
,
3394 struct replmd_private
*replmd_private
,
3395 struct replmd_replicated_request
*ac
,
3396 struct ldb_message
*msg
,
3398 struct ldb_request
*parent
)
3400 struct ldb_result
*res
;
3403 struct ldb_context
*ldb
= ldb_module_get_ctx(module
);
3404 struct ldb_message
*old_msg
;
3406 if (dsdb_functional_level(ldb
) == DS_DOMAIN_FUNCTION_2000
) {
3408 * Nothing special is required for modifying or vanishing links
3409 * in fl2000 since they are just strings in a multi-valued
3412 struct ldb_control
*ctrl
= ldb_request_get_control(parent
,
3413 DSDB_CONTROL_REPLMD_VANISH_LINKS
);
3415 ctrl
->critical
= false;
3423 * We should restrict this to the intersection of the list of
3424 * linked attributes in the schema and the list of attributes
3427 * This will help performance a little, as otherwise we have
3428 * to allocate the entire object value-by-value.
3430 ret
= dsdb_module_search_dn(module
, msg
, &res
, msg
->dn
, NULL
,
3431 DSDB_FLAG_NEXT_MODULE
|
3432 DSDB_SEARCH_SHOW_RECYCLED
|
3433 DSDB_SEARCH_REVEAL_INTERNALS
|
3434 DSDB_SEARCH_SHOW_DN_IN_STORAGE_FORMAT
,
3436 if (ret
!= LDB_SUCCESS
) {
3440 old_msg
= res
->msgs
[0];
3442 for (i
=0; i
<msg
->num_elements
; i
++) {
3443 struct ldb_message_element
*el
= &msg
->elements
[i
];
3444 struct ldb_message_element
*old_el
, *new_el
;
3445 unsigned int mod_type
= LDB_FLAG_MOD_TYPE(el
->flags
);
3446 const struct dsdb_attribute
*schema_attr
3447 = dsdb_attribute_by_lDAPDisplayName(ac
->schema
, el
->name
);
3449 ldb_asprintf_errstring(ldb
,
3450 "%s: attribute %s is not a valid attribute in schema",
3451 __FUNCTION__
, el
->name
);
3452 return LDB_ERR_OBJECT_CLASS_VIOLATION
;
3454 if (schema_attr
->linkID
== 0) {
3457 if ((schema_attr
->linkID
& 1) == 1) {
3458 struct ldb_control
*ctrl
;
3460 ctrl
= ldb_request_get_control(parent
,
3461 DSDB_CONTROL_REPLMD_VANISH_LINKS
);
3463 ctrl
->critical
= false;
3466 ctrl
= ldb_request_get_control(parent
,
3467 DSDB_CONTROL_DBCHECK
);
3472 /* Odd is for the target. Illegal to modify */
3473 ldb_asprintf_errstring(ldb
,
3474 "attribute %s must not be modified directly, it is a linked attribute", el
->name
);
3475 return LDB_ERR_UNWILLING_TO_PERFORM
;
3477 old_el
= ldb_msg_find_element(old_msg
, el
->name
);
3479 case LDB_FLAG_MOD_REPLACE
:
3480 ret
= replmd_modify_la_replace(module
, replmd_private
,
3481 ac
, msg
, el
, old_el
,
3486 case LDB_FLAG_MOD_DELETE
:
3487 ret
= replmd_modify_la_delete(module
, replmd_private
,
3488 ac
, msg
, el
, old_el
,
3493 case LDB_FLAG_MOD_ADD
:
3494 ret
= replmd_modify_la_add(module
, replmd_private
,
3495 ac
, msg
, el
, old_el
,
3501 ldb_asprintf_errstring(ldb
,
3502 "invalid flags 0x%x for %s linked attribute",
3503 el
->flags
, el
->name
);
3504 return LDB_ERR_UNWILLING_TO_PERFORM
;
3506 if (ret
!= LDB_SUCCESS
) {
3509 ret
= dsdb_check_single_valued_link(schema_attr
, el
);
3510 if (ret
!= LDB_SUCCESS
) {
3511 ldb_asprintf_errstring(ldb
,
3512 "Attribute %s is single valued but more than one value has been supplied",
3514 /* Return codes as found on Windows 2012r2 */
3515 if (mod_type
== LDB_FLAG_MOD_REPLACE
) {
3516 return LDB_ERR_CONSTRAINT_VIOLATION
;
3518 return LDB_ERR_ATTRIBUTE_OR_VALUE_EXISTS
;
3521 el
->flags
|= LDB_FLAG_INTERNAL_DISABLE_SINGLE_VALUE_CHECK
;
3525 ldb_msg_remove_attr(old_msg
, el
->name
);
3527 ret
= ldb_msg_add_empty(old_msg
, el
->name
, 0, &new_el
);
3528 if (ret
!= LDB_SUCCESS
) {
3531 new_el
->num_values
= el
->num_values
;
3532 new_el
->values
= talloc_steal(msg
->elements
, el
->values
);
3534 /* TODO: this relies a bit too heavily on the exact
3535 behaviour of ldb_msg_find_element and
3536 ldb_msg_remove_element */
3537 old_el
= ldb_msg_find_element(msg
, el
->name
);
3539 ldb_msg_remove_element(msg
, old_el
);
3549 static int send_rodc_referral(struct ldb_request
*req
,
3550 struct ldb_context
*ldb
,
3553 char *referral
= NULL
;
3554 struct loadparm_context
*lp_ctx
= NULL
;
3555 struct ldb_dn
*fsmo_role_dn
= NULL
;
3556 struct ldb_dn
*role_owner_dn
= NULL
;
3557 const char *domain
= NULL
;
3560 lp_ctx
= talloc_get_type(ldb_get_opaque(ldb
, "loadparm"),
3561 struct loadparm_context
);
3563 werr
= dsdb_get_fsmo_role_info(req
, ldb
, DREPL_PDC_MASTER
,
3564 &fsmo_role_dn
, &role_owner_dn
);
3566 if (W_ERROR_IS_OK(werr
)) {
3567 struct ldb_dn
*server_dn
= ldb_dn_copy(req
, role_owner_dn
);
3568 if (server_dn
!= NULL
) {
3569 ldb_dn_remove_child_components(server_dn
, 1);
3570 domain
= samdb_dn_to_dnshostname(ldb
, req
,
3575 if (domain
== NULL
) {
3576 domain
= lpcfg_dnsdomain(lp_ctx
);
3579 referral
= talloc_asprintf(req
, "ldap://%s/%s",
3581 ldb_dn_get_linearized(dn
));
3582 if (referral
== NULL
) {
3584 return LDB_ERR_OPERATIONS_ERROR
;
3587 return ldb_module_send_referral(req
, referral
);
3591 static int replmd_modify(struct ldb_module
*module
, struct ldb_request
*req
)
3593 struct ldb_context
*ldb
;
3594 struct replmd_replicated_request
*ac
;
3595 struct ldb_request
*down_req
;
3596 struct ldb_message
*msg
;
3597 time_t t
= time(NULL
);
3599 bool is_urgent
= false, rodc
= false;
3600 bool is_schema_nc
= false;
3601 unsigned int functional_level
;
3602 const struct ldb_message_element
*guid_el
= NULL
;
3603 struct ldb_control
*sd_propagation_control
;
3604 struct ldb_control
*fix_links_control
= NULL
;
3605 struct ldb_control
*fix_dn_name_control
= NULL
;
3606 struct ldb_control
*fix_dn_sid_control
= NULL
;
3607 struct replmd_private
*replmd_private
=
3608 talloc_get_type(ldb_module_get_private(module
), struct replmd_private
);
3610 /* do not manipulate our control entries */
3611 if (ldb_dn_is_special(req
->op
.mod
.message
->dn
)) {
3612 return ldb_next_request(module
, req
);
3615 sd_propagation_control
= ldb_request_get_control(req
,
3616 DSDB_CONTROL_SEC_DESC_PROPAGATION_OID
);
3617 if (sd_propagation_control
!= NULL
) {
3618 if (req
->op
.mod
.message
->num_elements
!= 1) {
3619 return ldb_module_operr(module
);
3621 ret
= strcmp(req
->op
.mod
.message
->elements
[0].name
,
3622 "nTSecurityDescriptor");
3624 return ldb_module_operr(module
);
3627 return ldb_next_request(module
, req
);
3630 ldb
= ldb_module_get_ctx(module
);
3632 fix_links_control
= ldb_request_get_control(req
,
3633 DSDB_CONTROL_DBCHECK_FIX_DUPLICATE_LINKS
);
3634 if (fix_links_control
!= NULL
) {
3635 struct dsdb_schema
*schema
= NULL
;
3636 const struct dsdb_attribute
*sa
= NULL
;
3638 if (req
->op
.mod
.message
->num_elements
!= 1) {
3639 return ldb_module_operr(module
);
3642 if (LDB_FLAG_MOD_TYPE(req
->op
.mod
.message
->elements
[0].flags
) != LDB_FLAG_MOD_REPLACE
) {
3643 return ldb_module_operr(module
);
3646 schema
= dsdb_get_schema(ldb
, req
);
3647 if (schema
== NULL
) {
3648 return ldb_module_operr(module
);
3651 sa
= dsdb_attribute_by_lDAPDisplayName(schema
,
3652 req
->op
.mod
.message
->elements
[0].name
);
3654 return ldb_module_operr(module
);
3657 if (sa
->linkID
== 0) {
3658 return ldb_module_operr(module
);
3661 fix_links_control
->critical
= false;
3662 return ldb_next_request(module
, req
);
3665 fix_dn_name_control
= ldb_request_get_control(req
,
3666 DSDB_CONTROL_DBCHECK_FIX_LINK_DN_NAME
);
3667 if (fix_dn_name_control
!= NULL
) {
3668 struct dsdb_schema
*schema
= NULL
;
3669 const struct dsdb_attribute
*sa
= NULL
;
3671 if (req
->op
.mod
.message
->num_elements
!= 2) {
3672 return ldb_module_operr(module
);
3675 if (LDB_FLAG_MOD_TYPE(req
->op
.mod
.message
->elements
[0].flags
) != LDB_FLAG_MOD_DELETE
) {
3676 return ldb_module_operr(module
);
3679 if (LDB_FLAG_MOD_TYPE(req
->op
.mod
.message
->elements
[1].flags
) != LDB_FLAG_MOD_ADD
) {
3680 return ldb_module_operr(module
);
3683 if (req
->op
.mod
.message
->elements
[0].num_values
!= 1) {
3684 return ldb_module_operr(module
);
3687 if (req
->op
.mod
.message
->elements
[1].num_values
!= 1) {
3688 return ldb_module_operr(module
);
3691 schema
= dsdb_get_schema(ldb
, req
);
3692 if (schema
== NULL
) {
3693 return ldb_module_operr(module
);
3696 if (ldb_attr_cmp(req
->op
.mod
.message
->elements
[0].name
,
3697 req
->op
.mod
.message
->elements
[1].name
) != 0) {
3698 return ldb_module_operr(module
);
3701 sa
= dsdb_attribute_by_lDAPDisplayName(schema
,
3702 req
->op
.mod
.message
->elements
[0].name
);
3704 return ldb_module_operr(module
);
3707 if (sa
->dn_format
== DSDB_INVALID_DN
) {
3708 return ldb_module_operr(module
);
3711 if (sa
->linkID
!= 0) {
3712 return ldb_module_operr(module
);
3716 * If we are run from dbcheck and we are not updating
3717 * a link (as these would need to be sorted and so
3718 * can't go via such a simple update, then do not
3719 * trigger replicated updates and a new USN from this
3720 * change, it wasn't a real change, just a new
3721 * (correct) string DN
3724 fix_dn_name_control
->critical
= false;
3725 return ldb_next_request(module
, req
);
3728 ldb_debug(ldb
, LDB_DEBUG_TRACE
, "replmd_modify\n");
3730 guid_el
= ldb_msg_find_element(req
->op
.mod
.message
, "objectGUID");
3731 if (guid_el
!= NULL
) {
3732 ldb_set_errstring(ldb
,
3733 "replmd_modify: it's not allowed to change the objectGUID!");
3734 return LDB_ERR_CONSTRAINT_VIOLATION
;
3737 ac
= replmd_ctx_init(module
, req
);
3739 return ldb_module_oom(module
);
3742 functional_level
= dsdb_functional_level(ldb
);
3744 /* we have to copy the message as the caller might have it as a const */
3745 msg
= ldb_msg_copy_shallow(ac
, req
->op
.mod
.message
);
3749 return LDB_ERR_OPERATIONS_ERROR
;
3752 fix_dn_sid_control
= ldb_request_get_control(req
,
3753 DSDB_CONTROL_DBCHECK_FIX_LINK_DN_SID
);
3754 if (fix_dn_sid_control
!= NULL
) {
3755 const struct dsdb_attribute
*sa
= NULL
;
3757 if (msg
->num_elements
!= 1) {
3759 return ldb_module_operr(module
);
3762 if (LDB_FLAG_MOD_TYPE(msg
->elements
[0].flags
) != LDB_FLAG_MOD_ADD
) {
3764 return ldb_module_operr(module
);
3767 if (msg
->elements
[0].num_values
!= 1) {
3769 return ldb_module_operr(module
);
3772 sa
= dsdb_attribute_by_lDAPDisplayName(ac
->schema
,
3773 msg
->elements
[0].name
);
3776 return ldb_module_operr(module
);
3779 if (sa
->dn_format
!= DSDB_NORMAL_DN
) {
3781 return ldb_module_operr(module
);
3784 fix_dn_sid_control
->critical
= false;
3785 ac
->fix_link_sid
= true;
3787 goto handle_linked_attribs
;
3790 ldb_msg_remove_attr(msg
, "whenChanged");
3791 ldb_msg_remove_attr(msg
, "uSNChanged");
3793 is_schema_nc
= ldb_dn_compare_base(replmd_private
->schema_dn
, msg
->dn
) == 0;
3795 ret
= replmd_update_rpmd(module
, ac
->schema
, req
, NULL
,
3796 msg
, &ac
->seq_num
, t
, is_schema_nc
,
3798 if (rodc
&& (ret
== LDB_ERR_REFERRAL
)) {
3799 ret
= send_rodc_referral(req
, ldb
, msg
->dn
);
3805 if (ret
!= LDB_SUCCESS
) {
3810 handle_linked_attribs
:
3811 ret
= replmd_modify_handle_linked_attribs(module
, replmd_private
,
3813 if (ret
!= LDB_SUCCESS
) {
3819 * - replace the old object with the newly constructed one
3822 ac
->is_urgent
= is_urgent
;
3824 ret
= ldb_build_mod_req(&down_req
, ldb
, ac
,
3827 ac
, replmd_op_callback
,
3829 LDB_REQ_SET_LOCATION(down_req
);
3830 if (ret
!= LDB_SUCCESS
) {
3835 /* current partition control is needed by "replmd_op_callback" */
3836 if (ldb_request_get_control(req
, DSDB_CONTROL_CURRENT_PARTITION_OID
) == NULL
) {
3837 ret
= ldb_request_add_control(down_req
,
3838 DSDB_CONTROL_CURRENT_PARTITION_OID
,
3840 if (ret
!= LDB_SUCCESS
) {
3846 /* If we are in functional level 2000, then
3847 * replmd_modify_handle_linked_attribs will have done
3849 if (functional_level
== DS_DOMAIN_FUNCTION_2000
) {
3850 ret
= ldb_request_add_control(down_req
, DSDB_CONTROL_APPLY_LINKS
, false, NULL
);
3851 if (ret
!= LDB_SUCCESS
) {
3857 talloc_steal(down_req
, msg
);
3859 /* we only change whenChanged and uSNChanged if the seq_num
3861 if (ac
->seq_num
!= 0) {
3862 ret
= add_time_element(msg
, "whenChanged", t
);
3863 if (ret
!= LDB_SUCCESS
) {
3869 ret
= add_uint64_element(ldb
, msg
, "uSNChanged", ac
->seq_num
);
3870 if (ret
!= LDB_SUCCESS
) {
3877 /* go on with the call chain */
3878 return ldb_next_request(module
, down_req
);
3881 static int replmd_rename_callback(struct ldb_request
*req
, struct ldb_reply
*ares
);
3884 handle a rename request
3886 On a rename we need to do an extra ldb_modify which sets the
3887 whenChanged and uSNChanged attributes. We do this in a callback after the success.
3889 static int replmd_rename(struct ldb_module
*module
, struct ldb_request
*req
)
3891 struct ldb_context
*ldb
;
3892 struct ldb_control
*fix_dn_name_control
= NULL
;
3893 struct replmd_replicated_request
*ac
;
3895 struct ldb_request
*down_req
;
3897 /* do not manipulate our control entries */
3898 if (ldb_dn_is_special(req
->op
.rename
.olddn
)) {
3899 return ldb_next_request(module
, req
);
3902 fix_dn_name_control
= ldb_request_get_control(req
,
3903 DSDB_CONTROL_DBCHECK_FIX_LINK_DN_NAME
);
3904 if (fix_dn_name_control
!= NULL
) {
3905 return ldb_next_request(module
, req
);
3908 ldb
= ldb_module_get_ctx(module
);
3910 ldb_debug(ldb
, LDB_DEBUG_TRACE
, "replmd_rename\n");
3912 ac
= replmd_ctx_init(module
, req
);
3914 return ldb_module_oom(module
);
3917 ret
= ldb_build_rename_req(&down_req
, ldb
, ac
,
3918 ac
->req
->op
.rename
.olddn
,
3919 ac
->req
->op
.rename
.newdn
,
3921 ac
, replmd_rename_callback
,
3923 LDB_REQ_SET_LOCATION(down_req
);
3924 if (ret
!= LDB_SUCCESS
) {
3929 /* go on with the call chain */
3930 return ldb_next_request(module
, down_req
);
3933 /* After the rename is completed, update the whenchanged etc */
3934 static int replmd_rename_callback(struct ldb_request
*req
, struct ldb_reply
*ares
)
3936 struct ldb_context
*ldb
;
3937 struct ldb_request
*down_req
;
3938 struct ldb_message
*msg
;
3939 const struct dsdb_attribute
*rdn_attr
;
3940 const char *rdn_name
;
3941 const struct ldb_val
*rdn_val
;
3942 const char *attrs
[5] = { NULL
, };
3943 time_t t
= time(NULL
);
3945 bool is_urgent
= false, rodc
= false;
3947 struct replmd_replicated_request
*ac
=
3948 talloc_get_type(req
->context
, struct replmd_replicated_request
);
3949 struct replmd_private
*replmd_private
=
3950 talloc_get_type(ldb_module_get_private(ac
->module
),
3951 struct replmd_private
);
3953 ldb
= ldb_module_get_ctx(ac
->module
);
3955 if (ares
->error
!= LDB_SUCCESS
) {
3956 return ldb_module_done(ac
->req
, ares
->controls
,
3957 ares
->response
, ares
->error
);
3960 if (ares
->type
!= LDB_REPLY_DONE
) {
3961 ldb_set_errstring(ldb
,
3962 "invalid reply type in repl_meta_data rename callback");
3964 return ldb_module_done(ac
->req
, NULL
, NULL
,
3965 LDB_ERR_OPERATIONS_ERROR
);
3969 * - replace the old object with the newly constructed one
3972 msg
= ldb_msg_new(ac
);
3975 return LDB_ERR_OPERATIONS_ERROR
;
3978 msg
->dn
= ac
->req
->op
.rename
.newdn
;
3980 is_schema_nc
= ldb_dn_compare_base(replmd_private
->schema_dn
, msg
->dn
) == 0;
3982 rdn_name
= ldb_dn_get_rdn_name(msg
->dn
);
3983 if (rdn_name
== NULL
) {
3985 return ldb_module_done(ac
->req
, NULL
, NULL
,
3989 /* normalize the rdn attribute name */
3990 rdn_attr
= dsdb_attribute_by_lDAPDisplayName(ac
->schema
, rdn_name
);
3991 if (rdn_attr
== NULL
) {
3993 return ldb_module_done(ac
->req
, NULL
, NULL
,
3996 rdn_name
= rdn_attr
->lDAPDisplayName
;
3998 rdn_val
= ldb_dn_get_rdn_val(msg
->dn
);
3999 if (rdn_val
== NULL
) {
4001 return ldb_module_done(ac
->req
, NULL
, NULL
,
4005 if (ldb_msg_append_value(msg
, rdn_name
, rdn_val
, LDB_FLAG_MOD_REPLACE
) != 0) {
4007 return ldb_module_done(ac
->req
, NULL
, NULL
,
4010 if (ldb_msg_append_value(msg
, "name", rdn_val
, LDB_FLAG_MOD_REPLACE
) != 0) {
4012 return ldb_module_done(ac
->req
, NULL
, NULL
,
4017 * here we let replmd_update_rpmd() only search for
4018 * the existing "replPropertyMetaData" and rdn_name attributes.
4020 * We do not want the existing "name" attribute as
4021 * the "name" attribute needs to get the version
4022 * updated on rename even if the rdn value hasn't changed.
4024 * This is the diff of the meta data, for a moved user
4025 * on a w2k8r2 server:
4028 * -dn: CN=sdf df,CN=Users,DC=bla,DC=base
4029 * +dn: CN=sdf df,OU=TestOU,DC=bla,DC=base
4030 * replPropertyMetaData: NDR: struct replPropertyMetaDataBlob
4031 * version : 0x00000001 (1)
4032 * reserved : 0x00000000 (0)
4033 * @@ -66,11 +66,11 @@ replPropertyMetaData: NDR: struct re
4034 * local_usn : 0x00000000000037a5 (14245)
4035 * array: struct replPropertyMetaData1
4036 * attid : DRSUAPI_ATTID_name (0x90001)
4037 * - version : 0x00000001 (1)
4038 * - originating_change_time : Wed Feb 9 17:20:49 2011 CET
4039 * + version : 0x00000002 (2)
4040 * + originating_change_time : Wed Apr 6 15:21:01 2011 CEST
4041 * originating_invocation_id: 0d36ca05-5507-4e62-aca3-354bab0d39e1
4042 * - originating_usn : 0x00000000000037a5 (14245)
4043 * - local_usn : 0x00000000000037a5 (14245)
4044 * + originating_usn : 0x0000000000003834 (14388)
4045 * + local_usn : 0x0000000000003834 (14388)
4046 * array: struct replPropertyMetaData1
4047 * attid : DRSUAPI_ATTID_userAccountControl (0x90008)
4048 * version : 0x00000004 (4)
4050 attrs
[0] = "replPropertyMetaData";
4051 attrs
[1] = "objectClass";
4052 attrs
[2] = "instanceType";
4053 attrs
[3] = rdn_name
;
4056 ret
= replmd_update_rpmd(ac
->module
, ac
->schema
, req
, attrs
,
4057 msg
, &ac
->seq_num
, t
,
4058 is_schema_nc
, &is_urgent
, &rodc
);
4059 if (rodc
&& (ret
== LDB_ERR_REFERRAL
)) {
4060 ret
= send_rodc_referral(req
, ldb
, ac
->req
->op
.rename
.olddn
);
4062 return ldb_module_done(req
, NULL
, NULL
, ret
);
4065 if (ret
!= LDB_SUCCESS
) {
4067 return ldb_module_done(ac
->req
, NULL
, NULL
, ret
);
4070 if (ac
->seq_num
== 0) {
4072 return ldb_module_done(ac
->req
, NULL
, NULL
,
4074 "internal error seq_num == 0"));
4076 ac
->is_urgent
= is_urgent
;
4078 ret
= ldb_build_mod_req(&down_req
, ldb
, ac
,
4081 ac
, replmd_op_callback
,
4083 LDB_REQ_SET_LOCATION(down_req
);
4084 if (ret
!= LDB_SUCCESS
) {
4089 /* current partition control is needed by "replmd_op_callback" */
4090 if (ldb_request_get_control(req
, DSDB_CONTROL_CURRENT_PARTITION_OID
) == NULL
) {
4091 ret
= ldb_request_add_control(down_req
,
4092 DSDB_CONTROL_CURRENT_PARTITION_OID
,
4094 if (ret
!= LDB_SUCCESS
) {
4100 talloc_steal(down_req
, msg
);
4102 ret
= add_time_element(msg
, "whenChanged", t
);
4103 if (ret
!= LDB_SUCCESS
) {
4109 ret
= add_uint64_element(ldb
, msg
, "uSNChanged", ac
->seq_num
);
4110 if (ret
!= LDB_SUCCESS
) {
4116 /* go on with the call chain - do the modify after the rename */
4117 return ldb_next_request(ac
->module
, down_req
);
4121 * remove links from objects that point at this object when an object
4122 * is deleted. We remove it from the NEXT module per MS-DRSR 5.160
4123 * RemoveObj which states that link removal due to the object being
4124 * deleted is NOT an originating update - they just go away!
4127 static int replmd_delete_remove_link(struct ldb_module
*module
,
4128 const struct dsdb_schema
*schema
,
4129 struct replmd_private
*replmd_private
,
4132 struct ldb_message_element
*el
,
4133 const struct dsdb_attribute
*sa
,
4134 struct ldb_request
*parent
,
4135 bool *caller_should_vanish
)
4138 TALLOC_CTX
*tmp_ctx
= talloc_new(module
);
4139 struct ldb_context
*ldb
= ldb_module_get_ctx(module
);
4141 for (i
=0; i
<el
->num_values
; i
++) {
4142 struct dsdb_dn
*dsdb_dn
;
4144 struct ldb_message
*msg
;
4145 const struct dsdb_attribute
*target_attr
;
4146 struct ldb_message_element
*el2
;
4148 struct ldb_val dn_val
;
4149 uint32_t dsdb_flags
= 0;
4150 const char *attrs
[] = { NULL
, NULL
};
4151 struct ldb_result
*link_res
;
4152 struct ldb_message
*link_msg
;
4153 struct ldb_message_element
*link_el
;
4154 struct parsed_dn
*link_dns
;
4155 struct parsed_dn
*p
= NULL
, *unused
= NULL
;
4157 if (dsdb_dn_is_deleted_val(&el
->values
[i
])) {
4161 dsdb_dn
= dsdb_dn_parse(tmp_ctx
, ldb
, &el
->values
[i
], sa
->syntax
->ldap_oid
);
4163 talloc_free(tmp_ctx
);
4164 return LDB_ERR_OPERATIONS_ERROR
;
4167 /* remove the link */
4168 msg
= ldb_msg_new(tmp_ctx
);
4170 ldb_module_oom(module
);
4171 talloc_free(tmp_ctx
);
4172 return LDB_ERR_OPERATIONS_ERROR
;
4175 msg
->dn
= dsdb_dn
->dn
;
4177 target_attr
= dsdb_attribute_by_linkID(schema
, sa
->linkID
^ 1);
4178 if (target_attr
== NULL
) {
4181 attrs
[0] = target_attr
->lDAPDisplayName
;
4183 ret
= ldb_msg_add_empty(msg
, target_attr
->lDAPDisplayName
,
4184 LDB_FLAG_MOD_DELETE
, &el2
);
4185 if (ret
!= LDB_SUCCESS
) {
4186 ldb_module_oom(module
);
4187 talloc_free(tmp_ctx
);
4188 return LDB_ERR_OPERATIONS_ERROR
;
4191 ret
= dsdb_module_search_dn(module
, tmp_ctx
, &link_res
,
4193 DSDB_FLAG_NEXT_MODULE
|
4194 DSDB_SEARCH_SHOW_EXTENDED_DN
|
4195 DSDB_SEARCH_SHOW_RECYCLED
,
4198 if (ret
== LDB_ERR_NO_SUCH_OBJECT
) {
4199 DBG_WARNING("Failed to find forward link object %s "
4200 "to remove backlink %s on %s\n",
4201 ldb_dn_get_linearized(msg
->dn
),
4202 sa
->lDAPDisplayName
,
4203 ldb_dn_get_linearized(dn
));
4204 *caller_should_vanish
= true;
4208 if (ret
!= LDB_SUCCESS
) {
4209 talloc_free(tmp_ctx
);
4213 link_msg
= link_res
->msgs
[0];
4214 link_el
= ldb_msg_find_element(link_msg
,
4215 target_attr
->lDAPDisplayName
);
4216 if (link_el
== NULL
) {
4217 DBG_WARNING("Failed to find forward link on %s "
4218 "as %s to remove backlink %s on %s\n",
4219 ldb_dn_get_linearized(msg
->dn
),
4220 target_attr
->lDAPDisplayName
,
4221 sa
->lDAPDisplayName
,
4222 ldb_dn_get_linearized(dn
));
4223 *caller_should_vanish
= true;
4228 * This call 'upgrades' the links in link_dns, but we
4229 * do not commit the result back into the database, so
4230 * this is safe to call in FL2000 or on databases that
4231 * have been run at that level in the past.
4233 ret
= get_parsed_dns_trusted_fallback(module
, replmd_private
,
4236 target_attr
->syntax
->ldap_oid
,
4238 if (ret
!= LDB_SUCCESS
) {
4239 talloc_free(tmp_ctx
);
4243 ret
= parsed_dn_find(ldb
, link_dns
, link_el
->num_values
,
4247 target_attr
->syntax
->ldap_oid
, false);
4248 if (ret
!= LDB_SUCCESS
) {
4249 talloc_free(tmp_ctx
);
4254 DBG_WARNING("Failed to find forward link on %s "
4255 "as %s to remove backlink %s on %s\n",
4256 ldb_dn_get_linearized(msg
->dn
),
4257 target_attr
->lDAPDisplayName
,
4258 sa
->lDAPDisplayName
,
4259 ldb_dn_get_linearized(dn
));
4260 *caller_should_vanish
= true;
4265 * If we find a backlink to ourself, we will delete
4266 * the forward link before we get to process that
4267 * properly, so just let the caller process this via
4270 * We do this once we are sure we have the forward
4271 * link (to ourself) in case something is very wrong
4272 * and they are out of sync.
4274 if (ldb_dn_compare(dsdb_dn
->dn
, dn
) == 0) {
4278 /* This needs to get the Binary DN, by first searching */
4279 dn_str
= dsdb_dn_get_linearized(tmp_ctx
,
4282 dn_val
= data_blob_string_const(dn_str
);
4283 el2
->values
= &dn_val
;
4284 el2
->num_values
= 1;
4287 * Ensure that we tell the modification to vanish any linked
4288 * attributes (not simply mark them as isDeleted = TRUE)
4290 dsdb_flags
|= DSDB_REPLMD_VANISH_LINKS
;
4292 ret
= dsdb_module_modify(module
, msg
, dsdb_flags
|DSDB_FLAG_OWN_MODULE
, parent
);
4293 if (ret
!= LDB_SUCCESS
) {
4294 talloc_free(tmp_ctx
);
4298 talloc_free(tmp_ctx
);
4304 handle update of replication meta data for deletion of objects
4306 This also handles the mapping of delete to a rename operation
4307 to allow deletes to be replicated.
4309 It also handles the incoming deleted objects, to ensure they are
4310 fully deleted here. In that case re_delete is true, and we do not
4311 use this as a signal to change the deleted state, just reinforce it.
4314 static int replmd_delete_internals(struct ldb_module
*module
, struct ldb_request
*req
, bool re_delete
)
4316 int ret
= LDB_ERR_OTHER
;
4317 bool retb
, disallow_move_on_delete
;
4318 struct ldb_dn
*old_dn
= NULL
, *new_dn
= NULL
;
4319 const char *rdn_name
;
4320 const struct ldb_val
*rdn_value
, *new_rdn_value
;
4322 struct ldb_context
*ldb
= ldb_module_get_ctx(module
);
4323 const struct dsdb_schema
*schema
;
4324 struct ldb_message
*msg
, *old_msg
;
4325 struct ldb_message_element
*el
;
4326 TALLOC_CTX
*tmp_ctx
;
4327 struct ldb_result
*res
, *parent_res
;
4328 static const char * const preserved_attrs
[] = {
4330 * This list MUST be kept in case-insensitive sorted order,
4331 * as we use it in a binary search with ldb_attr_cmp().
4333 * We get this hard-coded list from
4334 * MS-ADTS section 3.1.1.5.5.1.1 "Tombstone Requirements".
4338 "distinguishedName",
4339 "dNReferenceUpdate",
4351 "msDS-LastKnownRDN",
4356 "nTSecurityDescriptor",
4361 "proxiedObjectName",
4362 "replPropertyMetaData",
4364 "securityIdentifier",
4372 "userAccountControl",
4378 * DO NOT JUST APPEND TO THIS LIST.
4380 * In case you missed the note at the top, this list is kept
4381 * in case-insensitive sorted order. In the unlikely event you
4382 * need to add an attribute, please add it in the RIGHT PLACE.
4385 static const char * const all_attrs
[] = {
4386 DSDB_SECRET_ATTRIBUTES
,
4390 static const struct ldb_val true_val
= {
4391 .data
= discard_const_p(uint8_t, "TRUE"),
4396 uint32_t dsdb_flags
= 0;
4397 struct replmd_private
*replmd_private
;
4398 enum deletion_state deletion_state
, next_deletion_state
;
4400 if (ldb_dn_is_special(req
->op
.del
.dn
)) {
4401 return ldb_next_request(module
, req
);
4405 * We have to allow dbcheck to remove an object that
4406 * is beyond repair, and to do so totally. This could
4407 * mean we we can get a partial object from the other
4408 * DC, causing havoc, so dbcheck suggests
4409 * re-replication first. dbcheck sets both DBCHECK
4410 * and RELAX in this situation.
4412 if (ldb_request_get_control(req
, LDB_CONTROL_RELAX_OID
)
4413 && ldb_request_get_control(req
, DSDB_CONTROL_DBCHECK
)) {
4414 /* really, really remove it */
4415 return ldb_next_request(module
, req
);
4418 tmp_ctx
= talloc_new(ldb
);
4421 return LDB_ERR_OPERATIONS_ERROR
;
4424 schema
= dsdb_get_schema(ldb
, tmp_ctx
);
4426 talloc_free(tmp_ctx
);
4427 return LDB_ERR_OPERATIONS_ERROR
;
4430 old_dn
= ldb_dn_copy(tmp_ctx
, req
->op
.del
.dn
);
4432 /* we need the complete msg off disk, so we can work out which
4433 attributes need to be removed */
4434 ret
= dsdb_module_search_dn(module
, tmp_ctx
, &res
, old_dn
, all_attrs
,
4435 DSDB_FLAG_NEXT_MODULE
|
4436 DSDB_SEARCH_SHOW_RECYCLED
|
4437 DSDB_SEARCH_REVEAL_INTERNALS
|
4438 DSDB_SEARCH_SHOW_DN_IN_STORAGE_FORMAT
, req
);
4439 if (ret
!= LDB_SUCCESS
) {
4440 ldb_asprintf_errstring(ldb_module_get_ctx(module
),
4441 "repmd_delete: Failed to %s %s, because we failed to find it: %s",
4442 re_delete
? "re-delete" : "delete",
4443 ldb_dn_get_linearized(old_dn
),
4444 ldb_errstring(ldb_module_get_ctx(module
)));
4445 talloc_free(tmp_ctx
);
4448 old_msg
= res
->msgs
[0];
4450 replmd_deletion_state(module
, old_msg
,
4452 &next_deletion_state
);
4454 /* This supports us noticing an incoming isDeleted and acting on it */
4456 SMB_ASSERT(deletion_state
> OBJECT_NOT_DELETED
);
4457 next_deletion_state
= deletion_state
;
4460 if (next_deletion_state
== OBJECT_REMOVED
) {
4462 * We have to prevent objects being deleted, even if
4463 * the administrator really wants them gone, as
4464 * without the tombstone, we can get a partial object
4465 * from the other DC, causing havoc.
4467 * The only other valid case is when the 180 day
4468 * timeout has expired, when relax is specified.
4470 if (ldb_request_get_control(req
, LDB_CONTROL_RELAX_OID
)) {
4471 /* it is already deleted - really remove it this time */
4472 talloc_free(tmp_ctx
);
4473 return ldb_next_request(module
, req
);
4476 ldb_asprintf_errstring(ldb
, "Refusing to delete tombstone object %s. "
4477 "This check is to prevent corruption of the replicated state.",
4478 ldb_dn_get_linearized(old_msg
->dn
));
4479 return LDB_ERR_UNWILLING_TO_PERFORM
;
4482 rdn_name
= ldb_dn_get_rdn_name(old_dn
);
4483 rdn_value
= ldb_dn_get_rdn_val(old_dn
);
4484 if ((rdn_name
== NULL
) || (rdn_value
== NULL
)) {
4485 talloc_free(tmp_ctx
);
4486 return ldb_operr(ldb
);
4489 msg
= ldb_msg_new(tmp_ctx
);
4491 ldb_module_oom(module
);
4492 talloc_free(tmp_ctx
);
4493 return LDB_ERR_OPERATIONS_ERROR
;
4498 /* consider the SYSTEM_FLAG_DISALLOW_MOVE_ON_DELETE flag */
4499 disallow_move_on_delete
=
4500 (ldb_msg_find_attr_as_int(old_msg
, "systemFlags", 0)
4501 & SYSTEM_FLAG_DISALLOW_MOVE_ON_DELETE
);
4503 /* work out where we will be renaming this object to */
4504 if (!disallow_move_on_delete
) {
4505 struct ldb_dn
*deleted_objects_dn
;
4506 ret
= dsdb_get_deleted_objects_dn(ldb
, tmp_ctx
, old_dn
,
4507 &deleted_objects_dn
);
4510 * We should not move objects if we can't find the
4511 * deleted objects DN. Not moving (or otherwise
4512 * harming) the Deleted Objects DN itself is handled
4515 if (re_delete
&& (ret
!= LDB_SUCCESS
)) {
4516 new_dn
= ldb_dn_get_parent(tmp_ctx
, old_dn
);
4517 if (new_dn
== NULL
) {
4518 ldb_module_oom(module
);
4519 talloc_free(tmp_ctx
);
4520 return LDB_ERR_OPERATIONS_ERROR
;
4522 } else if (ret
!= LDB_SUCCESS
) {
4523 /* this is probably an attempted delete on a partition
4524 * that doesn't allow delete operations, such as the
4525 * schema partition */
4526 ldb_asprintf_errstring(ldb
, "No Deleted Objects container for DN %s",
4527 ldb_dn_get_linearized(old_dn
));
4528 talloc_free(tmp_ctx
);
4529 return LDB_ERR_UNWILLING_TO_PERFORM
;
4531 new_dn
= deleted_objects_dn
;
4534 new_dn
= ldb_dn_get_parent(tmp_ctx
, old_dn
);
4535 if (new_dn
== NULL
) {
4536 ldb_module_oom(module
);
4537 talloc_free(tmp_ctx
);
4538 return LDB_ERR_OPERATIONS_ERROR
;
4542 /* get the objects GUID from the search we just did */
4543 guid
= samdb_result_guid(old_msg
, "objectGUID");
4545 if (deletion_state
== OBJECT_NOT_DELETED
) {
4546 struct ldb_message_element
*is_deleted_el
;
4548 ret
= replmd_make_deleted_child_dn(tmp_ctx
,
4551 rdn_name
, rdn_value
,
4554 if (ret
!= LDB_SUCCESS
) {
4555 talloc_free(tmp_ctx
);
4559 ret
= ldb_msg_add_value(msg
, "isDeleted", &true_val
,
4561 if (ret
!= LDB_SUCCESS
) {
4562 ldb_asprintf_errstring(ldb
, __location__
4563 ": Failed to add isDeleted string to the msg");
4564 talloc_free(tmp_ctx
);
4567 is_deleted_el
->flags
= LDB_FLAG_MOD_REPLACE
;
4570 * No matter what has happened with other renames etc, try again to
4571 * get this to be under the deleted DN. See MS-DRSR 5.160 RemoveObj
4574 struct ldb_dn
*rdn
= ldb_dn_copy(tmp_ctx
, old_dn
);
4575 retb
= ldb_dn_remove_base_components(rdn
, ldb_dn_get_comp_num(rdn
) - 1);
4577 ldb_asprintf_errstring(ldb
, __location__
4578 ": Unable to add a prepare rdn of %s",
4579 ldb_dn_get_linearized(rdn
));
4580 talloc_free(tmp_ctx
);
4581 return LDB_ERR_OPERATIONS_ERROR
;
4583 SMB_ASSERT(ldb_dn_get_comp_num(rdn
) == 1);
4585 retb
= ldb_dn_add_child(new_dn
, rdn
);
4587 ldb_asprintf_errstring(ldb
, __location__
4588 ": Unable to add rdn %s to base dn: %s",
4589 ldb_dn_get_linearized(rdn
),
4590 ldb_dn_get_linearized(new_dn
));
4591 talloc_free(tmp_ctx
);
4592 return LDB_ERR_OPERATIONS_ERROR
;
4597 now we need to modify the object in the following ways:
4599 - add isDeleted=TRUE
4600 - update rDN and name, with new rDN
4601 - remove linked attributes
4602 - remove objectCategory and sAMAccountType
4603 - remove attribs not on the preserved list
4604 - preserved if in above list, or is rDN
4605 - remove all linked attribs from this object
4606 - remove all links from other objects to this object
4607 (note we use the backlinks to do this, so we won't find one-way
4608 links that still point to this object, or deactivated two-way
4609 links, i.e. 'member' after the user has been removed from the
4611 - add lastKnownParent
4612 - update replPropertyMetaData?
4614 see MS-ADTS "Tombstone Requirements" section 3.1.1.5.5.1.1
4617 if (deletion_state
== OBJECT_NOT_DELETED
) {
4618 struct ldb_dn
*parent_dn
= ldb_dn_get_parent(tmp_ctx
, old_dn
);
4619 char *parent_dn_str
= NULL
;
4620 struct ldb_message_element
*p_el
;
4622 /* we need the storage form of the parent GUID */
4623 ret
= dsdb_module_search_dn(module
, tmp_ctx
, &parent_res
,
4625 DSDB_FLAG_NEXT_MODULE
|
4626 DSDB_SEARCH_SHOW_DN_IN_STORAGE_FORMAT
|
4627 DSDB_SEARCH_REVEAL_INTERNALS
|
4628 DSDB_SEARCH_SHOW_RECYCLED
, req
);
4629 if (ret
!= LDB_SUCCESS
) {
4630 ldb_asprintf_errstring(ldb_module_get_ctx(module
),
4631 "repmd_delete: Failed to %s %s, "
4632 "because we failed to find it's parent (%s): %s",
4633 re_delete
? "re-delete" : "delete",
4634 ldb_dn_get_linearized(old_dn
),
4635 ldb_dn_get_linearized(parent_dn
),
4636 ldb_errstring(ldb_module_get_ctx(module
)));
4637 talloc_free(tmp_ctx
);
4642 * Now we can use the DB version,
4643 * it will have the extended DN info in it
4645 parent_dn
= parent_res
->msgs
[0]->dn
;
4646 parent_dn_str
= ldb_dn_get_extended_linearized(tmp_ctx
,
4649 if (parent_dn_str
== NULL
) {
4650 talloc_free(tmp_ctx
);
4651 return ldb_module_oom(module
);
4654 ret
= ldb_msg_add_steal_string(msg
, "lastKnownParent",
4656 if (ret
!= LDB_SUCCESS
) {
4657 ldb_asprintf_errstring(ldb
, __location__
4658 ": Failed to add lastKnownParent "
4659 "string when deleting %s",
4660 ldb_dn_get_linearized(old_dn
));
4661 talloc_free(tmp_ctx
);
4664 p_el
= ldb_msg_find_element(msg
,
4667 talloc_free(tmp_ctx
);
4668 return ldb_module_operr(module
);
4670 p_el
->flags
= LDB_FLAG_MOD_REPLACE
;
4672 if (next_deletion_state
== OBJECT_DELETED
) {
4673 ret
= ldb_msg_add_value(msg
, "msDS-LastKnownRDN", rdn_value
, NULL
);
4674 if (ret
!= LDB_SUCCESS
) {
4675 ldb_asprintf_errstring(ldb
, __location__
4676 ": Failed to add msDS-LastKnownRDN "
4677 "string when deleting %s",
4678 ldb_dn_get_linearized(old_dn
));
4679 talloc_free(tmp_ctx
);
4682 p_el
= ldb_msg_find_element(msg
,
4683 "msDS-LastKnownRDN");
4685 talloc_free(tmp_ctx
);
4686 return ldb_module_operr(module
);
4688 p_el
->flags
= LDB_FLAG_MOD_ADD
;
4692 switch (next_deletion_state
) {
4694 case OBJECT_RECYCLED
:
4695 case OBJECT_TOMBSTONE
:
4698 * MS-ADTS 3.1.1.5.5.1.1 Tombstone Requirements
4699 * describes what must be removed from a tombstone
4702 * MS-ADTS 3.1.1.5.5.1.3 Recycled-Object Requirements
4703 * describes what must be removed from a recycled
4709 * we also mark it as recycled, meaning this object can't be
4710 * recovered (we are stripping its attributes).
4711 * This is done only if we have this schema object of course ...
4712 * This behavior is identical to the one of Windows 2008R2 which
4713 * always set the isRecycled attribute, even if the recycle-bin is
4714 * not activated and what ever the forest level is.
4716 if (dsdb_attribute_by_lDAPDisplayName(schema
, "isRecycled") != NULL
) {
4717 struct ldb_message_element
*is_recycled_el
;
4719 ret
= ldb_msg_add_value(msg
, "isRecycled", &true_val
,
4721 if (ret
!= LDB_SUCCESS
) {
4722 DEBUG(0,(__location__
": Failed to add isRecycled string to the msg\n"));
4723 ldb_module_oom(module
);
4724 talloc_free(tmp_ctx
);
4727 is_recycled_el
->flags
= LDB_FLAG_MOD_REPLACE
;
4730 replmd_private
= talloc_get_type(ldb_module_get_private(module
),
4731 struct replmd_private
);
4732 /* work out which of the old attributes we will be removing */
4733 for (i
=0; i
<old_msg
->num_elements
; i
++) {
4734 const struct dsdb_attribute
*sa
;
4735 el
= &old_msg
->elements
[i
];
4736 sa
= dsdb_attribute_by_lDAPDisplayName(schema
, el
->name
);
4738 const char *old_dn_str
4739 = ldb_dn_get_linearized(old_dn
);
4741 ldb_asprintf_errstring(ldb
,
4744 "not found in schema "
4745 "when deleting %s. "
4746 "Existing record is invalid",
4749 talloc_free(tmp_ctx
);
4750 return LDB_ERR_OPERATIONS_ERROR
;
4752 if (ldb_attr_cmp(el
->name
, rdn_name
) == 0) {
4753 /* don't remove the rDN */
4757 if (sa
->linkID
& 1) {
4758 bool caller_should_vanish
= false;
4760 * we have a backlink in this object
4761 * that needs to be removed. We're not
4762 * allowed to remove it directly
4763 * however, so we instead setup a
4764 * modify to delete the corresponding
4767 ret
= replmd_delete_remove_link(module
, schema
,
4771 &caller_should_vanish
);
4772 if (ret
!= LDB_SUCCESS
) {
4773 const char *old_dn_str
4774 = ldb_dn_get_linearized(old_dn
);
4775 ldb_asprintf_errstring(ldb
,
4777 ": Failed to remove backlink of "
4778 "%s when deleting %s: %s",
4781 ldb_errstring(ldb
));
4782 talloc_free(tmp_ctx
);
4783 return LDB_ERR_OPERATIONS_ERROR
;
4786 if (caller_should_vanish
== false) {
4788 * now we continue, which means we
4789 * won't remove this backlink
4796 * Otherwise vanish the link, we are
4797 * out of sync and the controlling
4798 * object does not have the source
4802 dsdb_flags
|= DSDB_REPLMD_VANISH_LINKS
;
4804 } else if (sa
->linkID
== 0) {
4805 const char * const *attr
= NULL
;
4806 if (sa
->searchFlags
& SEARCH_FLAG_PRESERVEONDELETE
) {
4809 BINARY_ARRAY_SEARCH_V(preserved_attrs
,
4810 ARRAY_SIZE(preserved_attrs
),
4815 * If we are preserving, do not do the
4816 * ldb_msg_add_empty() below, continue
4817 * to the next element
4824 * Ensure that we tell the modification to vanish any linked
4825 * attributes (not simply mark them as isDeleted = TRUE)
4827 dsdb_flags
|= DSDB_REPLMD_VANISH_LINKS
;
4829 ret
= ldb_msg_add_empty(msg
, el
->name
, LDB_FLAG_MOD_DELETE
, NULL
);
4830 if (ret
!= LDB_SUCCESS
) {
4831 talloc_free(tmp_ctx
);
4832 ldb_module_oom(module
);
4839 case OBJECT_DELETED
:
4841 * MS-ADTS 3.1.1.5.5.1.2 Deleted-Object Requirements
4842 * describes what must be removed from a deleted
4846 ret
= ldb_msg_add_empty(msg
, "objectCategory", LDB_FLAG_MOD_REPLACE
, NULL
);
4847 if (ret
!= LDB_SUCCESS
) {
4848 talloc_free(tmp_ctx
);
4849 ldb_module_oom(module
);
4853 ret
= ldb_msg_add_empty(msg
, "sAMAccountType", LDB_FLAG_MOD_REPLACE
, NULL
);
4854 if (ret
!= LDB_SUCCESS
) {
4855 talloc_free(tmp_ctx
);
4856 ldb_module_oom(module
);
4866 if (deletion_state
== OBJECT_NOT_DELETED
) {
4867 const struct dsdb_attribute
*sa
;
4869 /* work out what the new rdn value is, for updating the
4870 rDN and name fields */
4871 new_rdn_value
= ldb_dn_get_rdn_val(new_dn
);
4872 if (new_rdn_value
== NULL
) {
4873 talloc_free(tmp_ctx
);
4874 return ldb_operr(ldb
);
4877 sa
= dsdb_attribute_by_lDAPDisplayName(schema
, rdn_name
);
4879 talloc_free(tmp_ctx
);
4880 return LDB_ERR_OPERATIONS_ERROR
;
4883 ret
= ldb_msg_add_value(msg
, sa
->lDAPDisplayName
, new_rdn_value
,
4885 if (ret
!= LDB_SUCCESS
) {
4886 talloc_free(tmp_ctx
);
4889 el
->flags
= LDB_FLAG_MOD_REPLACE
;
4891 el
= ldb_msg_find_element(old_msg
, "name");
4893 ret
= ldb_msg_add_value(msg
, "name", new_rdn_value
, &el
);
4894 if (ret
!= LDB_SUCCESS
) {
4895 talloc_free(tmp_ctx
);
4898 el
->flags
= LDB_FLAG_MOD_REPLACE
;
4903 * TODO: Per MS-DRSR 5.160 RemoveObj we should remove links directly, not as an originating update!
4908 * No matter what has happned with other renames, try again to
4909 * get this to be under the deleted DN.
4911 if (strcmp(ldb_dn_get_linearized(old_dn
), ldb_dn_get_linearized(new_dn
)) != 0) {
4912 /* now rename onto the new DN */
4913 ret
= dsdb_module_rename(module
, old_dn
, new_dn
, DSDB_FLAG_NEXT_MODULE
, req
);
4914 if (ret
!= LDB_SUCCESS
){
4915 DEBUG(0,(__location__
": Failed to rename object from '%s' to '%s' - %s\n",
4916 ldb_dn_get_linearized(old_dn
),
4917 ldb_dn_get_linearized(new_dn
),
4918 ldb_errstring(ldb
)));
4919 talloc_free(tmp_ctx
);
4925 ret
= dsdb_module_modify(module
, msg
, dsdb_flags
|DSDB_FLAG_OWN_MODULE
, req
);
4926 if (ret
!= LDB_SUCCESS
) {
4929 * This should not fail, so be quite verbose in the
4930 * error handling if it fails
4932 if (strcmp(ldb_dn_get_linearized(old_dn
),
4933 ldb_dn_get_linearized(new_dn
)) != 0) {
4934 DBG_NOTICE("Failure to handle '%s' of object %s "
4935 "after successful rename to %s. "
4936 "Error during tombstone modification was: %s\n",
4937 re_delete
? "re-delete" : "delete",
4938 ldb_dn_get_linearized(new_dn
),
4939 ldb_dn_get_linearized(old_dn
),
4940 ldb_errstring(ldb
));
4942 DBG_NOTICE("Failure to handle '%s' of object %s. "
4943 "Error during tombstone modification was: %s\n",
4944 re_delete
? "re-delete" : "delete",
4945 ldb_dn_get_linearized(new_dn
),
4946 ldb_errstring(ldb
));
4948 s
= ldb_ldif_message_redacted_string(ldb_module_get_ctx(module
),
4950 LDB_CHANGETYPE_MODIFY
,
4953 DBG_INFO("Failed tombstone modify%s was:\n%s\n",
4954 (dsdb_flags
& DSDB_REPLMD_VANISH_LINKS
) ?
4955 " with VANISH_LINKS" : "",
4957 ldb_asprintf_errstring(ldb
,
4958 "replmd_delete: Failed to modify"
4959 " object %s in '%s' - %s",
4960 ldb_dn_get_linearized(old_dn
),
4961 re_delete
? "re-delete" : "delete",
4962 ldb_errstring(ldb
));
4963 talloc_free(tmp_ctx
);
4967 talloc_free(tmp_ctx
);
4969 return ldb_module_done(req
, NULL
, NULL
, LDB_SUCCESS
);
4972 static int replmd_delete(struct ldb_module
*module
, struct ldb_request
*req
)
4974 return replmd_delete_internals(module
, req
, false);
4978 static int replmd_replicated_request_error(struct replmd_replicated_request
*ar
, int ret
)
4983 static int replmd_replicated_request_werror(struct replmd_replicated_request
*ar
, WERROR status
)
4985 int ret
= LDB_ERR_OTHER
;
4986 /* TODO: do some error mapping */
4988 /* Let the caller know the full WERROR */
4989 ar
->objs
->error
= status
;
4995 static struct replPropertyMetaData1
*
4996 replmd_replPropertyMetaData1_find_attid(struct replPropertyMetaDataBlob
*md_blob
,
4997 enum drsuapi_DsAttributeId attid
)
5000 struct replPropertyMetaDataCtr1
*rpmd_ctr
= &md_blob
->ctr
.ctr1
;
5002 for (i
= 0; i
< rpmd_ctr
->count
; i
++) {
5003 if (rpmd_ctr
->array
[i
].attid
== attid
) {
5004 return &rpmd_ctr
->array
[i
];
5012 return true if an update is newer than an existing entry
5013 see section 5.11 of MS-ADTS
5015 static bool replmd_update_is_newer(const struct GUID
*current_invocation_id
,
5016 const struct GUID
*update_invocation_id
,
5017 uint32_t current_version
,
5018 uint32_t update_version
,
5019 NTTIME current_change_time
,
5020 NTTIME update_change_time
)
5022 if (update_version
!= current_version
) {
5023 return update_version
> current_version
;
5025 if (update_change_time
!= current_change_time
) {
5026 return update_change_time
> current_change_time
;
5028 return GUID_compare(update_invocation_id
, current_invocation_id
) > 0;
5031 static bool replmd_replPropertyMetaData1_is_newer(struct replPropertyMetaData1
*cur_m
,
5032 struct replPropertyMetaData1
*new_m
)
5034 return replmd_update_is_newer(&cur_m
->originating_invocation_id
,
5035 &new_m
->originating_invocation_id
,
5038 cur_m
->originating_change_time
,
5039 new_m
->originating_change_time
);
5042 static bool replmd_replPropertyMetaData1_new_should_be_taken(uint32_t dsdb_repl_flags
,
5043 struct replPropertyMetaData1
*cur_m
,
5044 struct replPropertyMetaData1
*new_m
)
5049 * If the new replPropertyMetaData entry for this attribute is
5050 * not provided (this happens in the case where we look for
5051 * ATTID_name, but the name was not changed), then the local
5052 * state is clearly still current, as the remote
5053 * server didn't send it due to being older the high watermark
5056 if (new_m
== NULL
) {
5060 if (dsdb_repl_flags
& DSDB_REPL_FLAG_PRIORITISE_INCOMING
) {
5062 * if we compare equal then do an
5063 * update. This is used when a client
5064 * asks for a FULL_SYNC, and can be
5065 * used to recover a corrupt
5068 * This call is a bit tricky, what we
5069 * are doing it turning the 'is_newer'
5070 * call into a 'not is older' by
5071 * swapping cur_m and new_m, and negating the
5074 cmp
= !replmd_replPropertyMetaData1_is_newer(new_m
,
5077 cmp
= replmd_replPropertyMetaData1_is_newer(cur_m
,
5085 form a DN for a deleted (DEL:) or conflict (CNF:) DN
5087 static int replmd_make_prefix_child_dn(TALLOC_CTX
*tmp_ctx
,
5088 struct ldb_context
*ldb
,
5090 const char *four_char_prefix
,
5091 const char *rdn_name
,
5092 const struct ldb_val
*rdn_value
,
5095 struct ldb_val deleted_child_rdn_val
;
5096 struct GUID_txt_buf guid_str
;
5100 GUID_buf_string(&guid
, &guid_str
);
5102 retb
= ldb_dn_add_child_fmt(dn
, "X=Y");
5104 ldb_asprintf_errstring(ldb
, __location__
5105 ": Unable to add a formatted child to dn: %s",
5106 ldb_dn_get_linearized(dn
));
5107 return LDB_ERR_OPERATIONS_ERROR
;
5111 * TODO: Per MS-ADTS 3.1.1.5.5 Delete Operation
5112 * we should truncate this value to ensure the RDN is not more than 255 chars.
5114 * However we MS-ADTS 3.1.1.5.1.2 Naming Constraints indicates that:
5116 * "Naming constraints are not enforced for replicated
5117 * updates." so this is safe and we don't have to work out not
5118 * splitting a UTF8 char right now.
5120 deleted_child_rdn_val
= ldb_val_dup(tmp_ctx
, rdn_value
);
5123 * sizeof(guid_str.buf) will always be longer than
5124 * strlen(guid_str.buf) but we allocate using this and
5125 * waste the trailing bytes to avoid scaring folks
5126 * with memcpy() using strlen() below
5129 deleted_child_rdn_val
.data
5130 = talloc_realloc(tmp_ctx
, deleted_child_rdn_val
.data
,
5132 rdn_value
->length
+ 5
5133 + sizeof(guid_str
.buf
));
5134 if (!deleted_child_rdn_val
.data
) {
5135 ldb_asprintf_errstring(ldb
, __location__
5136 ": Unable to add a formatted child to dn: %s",
5137 ldb_dn_get_linearized(dn
));
5138 return LDB_ERR_OPERATIONS_ERROR
;
5141 deleted_child_rdn_val
.length
=
5142 rdn_value
->length
+ 5
5143 + strlen(guid_str
.buf
);
5145 SMB_ASSERT(deleted_child_rdn_val
.length
<
5146 talloc_get_size(deleted_child_rdn_val
.data
));
5149 * talloc won't allocate more than 256MB so we can't
5150 * overflow but just to be sure
5152 if (deleted_child_rdn_val
.length
< rdn_value
->length
) {
5153 return LDB_ERR_OPERATIONS_ERROR
;
5156 deleted_child_rdn_val
.data
[rdn_value
->length
] = 0x0a;
5157 memcpy(&deleted_child_rdn_val
.data
[rdn_value
->length
+ 1],
5158 four_char_prefix
, 4);
5159 memcpy(&deleted_child_rdn_val
.data
[rdn_value
->length
+ 5],
5161 sizeof(guid_str
.buf
));
5163 /* Now set the value into the RDN, without parsing it */
5164 ret
= ldb_dn_set_component(
5168 deleted_child_rdn_val
);
5177 static struct ldb_dn
*replmd_conflict_dn(TALLOC_CTX
*mem_ctx
,
5178 struct ldb_context
*ldb
,
5182 const struct ldb_val
*rdn_val
;
5183 const char *rdn_name
;
5184 struct ldb_dn
*new_dn
;
5187 rdn_val
= ldb_dn_get_rdn_val(dn
);
5188 rdn_name
= ldb_dn_get_rdn_name(dn
);
5189 if (!rdn_val
|| !rdn_name
) {
5193 new_dn
= ldb_dn_get_parent(mem_ctx
, dn
);
5198 ret
= replmd_make_prefix_child_dn(mem_ctx
,
5204 if (ret
!= LDB_SUCCESS
) {
5213 static int replmd_make_deleted_child_dn(TALLOC_CTX
*tmp_ctx
,
5214 struct ldb_context
*ldb
,
5216 const char *rdn_name
,
5217 const struct ldb_val
*rdn_value
,
5220 return replmd_make_prefix_child_dn(tmp_ctx
,
5230 perform a modify operation which sets the rDN and name attributes to
5231 their current values. This has the effect of changing these
5232 attributes to have been last updated by the current DC. This is
5233 needed to ensure that renames performed as part of conflict
5234 resolution are propagated to other DCs
5236 static int replmd_name_modify(struct replmd_replicated_request
*ar
,
5237 struct ldb_request
*req
, struct ldb_dn
*dn
)
5239 struct ldb_message
*msg
;
5240 const char *rdn_name
;
5241 const struct ldb_val
*rdn_val
;
5242 const struct dsdb_attribute
*rdn_attr
;
5245 msg
= ldb_msg_new(req
);
5251 rdn_name
= ldb_dn_get_rdn_name(dn
);
5252 if (rdn_name
== NULL
) {
5256 /* normalize the rdn attribute name */
5257 rdn_attr
= dsdb_attribute_by_lDAPDisplayName(ar
->schema
, rdn_name
);
5258 if (rdn_attr
== NULL
) {
5261 rdn_name
= rdn_attr
->lDAPDisplayName
;
5263 rdn_val
= ldb_dn_get_rdn_val(dn
);
5264 if (rdn_val
== NULL
) {
5268 if (ldb_msg_append_value(msg
, rdn_name
, rdn_val
, LDB_FLAG_MOD_REPLACE
) != 0) {
5271 if (ldb_msg_append_value(msg
, "name", rdn_val
, LDB_FLAG_MOD_REPLACE
) != 0) {
5276 * We have to mark this as a replicated update otherwise
5277 * schema_data may reject a rename in the schema partition
5280 ret
= dsdb_module_modify(ar
->module
, msg
,
5281 DSDB_FLAG_OWN_MODULE
|DSDB_FLAG_REPLICATED_UPDATE
,
5283 if (ret
!= LDB_SUCCESS
) {
5284 DEBUG(0,(__location__
": Failed to modify rDN/name of DN being DRS renamed '%s' - %s\n",
5285 ldb_dn_get_linearized(dn
),
5286 ldb_errstring(ldb_module_get_ctx(ar
->module
))));
5296 DEBUG(0,(__location__
": Failed to setup modify rDN/name of DN being DRS renamed '%s'\n",
5297 ldb_dn_get_linearized(dn
)));
5298 return LDB_ERR_OPERATIONS_ERROR
;
5303 callback for conflict DN handling where we have renamed the incoming
5304 record. After renaming it, we need to ensure the change of name and
5305 rDN for the incoming record is seen as an originating update by this DC.
5307 This also handles updating lastKnownParent for entries sent to lostAndFound
5309 static int replmd_op_name_modify_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
);
5313 struct ldb_dn
*conflict_dn
= NULL
;
5316 if (ares
->error
!= LDB_SUCCESS
) {
5317 /* call the normal callback for everything except success */
5318 return replmd_op_callback(req
, ares
);
5321 switch (req
->operation
) {
5323 conflict_dn
= req
->op
.add
.message
->dn
;
5326 conflict_dn
= req
->op
.mod
.message
->dn
;
5329 smb_panic("replmd_op_name_modify_callback called in unknown circumstances");
5332 /* perform a modify of the rDN and name of the record */
5333 ret
= replmd_name_modify(ar
, req
, conflict_dn
);
5334 if (ret
!= LDB_SUCCESS
) {
5336 return replmd_op_callback(req
, ares
);
5339 if (ar
->objs
->objects
[ar
->index_current
].last_known_parent
) {
5340 struct ldb_message
*msg
= ldb_msg_new(req
);
5342 ldb_module_oom(ar
->module
);
5343 return LDB_ERR_OPERATIONS_ERROR
;
5346 msg
->dn
= req
->op
.add
.message
->dn
;
5348 ret
= ldb_msg_add_steal_string(msg
, "lastKnownParent",
5349 ldb_dn_get_extended_linearized(msg
, ar
->objs
->objects
[ar
->index_current
].last_known_parent
, 1));
5350 if (ret
!= LDB_SUCCESS
) {
5351 DEBUG(0,(__location__
": Failed to add lastKnownParent string to the msg\n"));
5352 ldb_module_oom(ar
->module
);
5355 msg
->elements
[0].flags
= LDB_FLAG_MOD_REPLACE
;
5357 ret
= dsdb_module_modify(ar
->module
, msg
, DSDB_FLAG_OWN_MODULE
, req
);
5358 if (ret
!= LDB_SUCCESS
) {
5359 DEBUG(0,(__location__
": Failed to modify lastKnownParent of lostAndFound DN '%s' - %s\n",
5360 ldb_dn_get_linearized(msg
->dn
),
5361 ldb_errstring(ldb_module_get_ctx(ar
->module
))));
5367 return replmd_op_callback(req
, ares
);
5373 * A helper for replmd_op_possible_conflict_callback() and
5374 * replmd_replicated_handle_rename()
5376 static int incoming_dn_should_be_renamed(TALLOC_CTX
*mem_ctx
,
5377 struct replmd_replicated_request
*ar
,
5378 struct ldb_dn
*conflict_dn
,
5379 struct ldb_result
**res
,
5380 bool *rename_incoming_record
)
5384 enum ndr_err_code ndr_err
;
5385 const struct ldb_val
*omd_value
= NULL
;
5386 struct replPropertyMetaDataBlob omd
, *rmd
= NULL
;
5387 struct ldb_context
*ldb
= ldb_module_get_ctx(ar
->module
);
5388 const char *attrs
[] = { "replPropertyMetaData", "objectGUID", NULL
};
5389 struct replPropertyMetaData1
*omd_name
= NULL
;
5390 struct replPropertyMetaData1
*rmd_name
= NULL
;
5391 struct ldb_message
*msg
= NULL
;
5393 ret
= samdb_rodc(ldb
, &rodc
);
5394 if (ret
!= LDB_SUCCESS
) {
5395 ldb_asprintf_errstring(
5397 "Failed to determine if we are an RODC when attempting "
5398 "to form conflict DN: %s",
5399 ldb_errstring(ldb
));
5400 return LDB_ERR_OPERATIONS_ERROR
;
5405 * We are on an RODC, or were a GC for this
5406 * partition, so we have to fail this until
5407 * someone who owns the partition sorts it
5410 ldb_asprintf_errstring(
5412 "Conflict adding object '%s' from incoming replication "
5413 "but we are read only for the partition. \n"
5414 " - We must fail the operation until a master for this "
5415 "partition resolves the conflict",
5416 ldb_dn_get_linearized(conflict_dn
));
5417 return LDB_ERR_OPERATIONS_ERROR
;
5421 * first we need the replPropertyMetaData attribute from the
5424 ret
= dsdb_module_search_dn(ar
->module
, mem_ctx
, res
, conflict_dn
,
5426 DSDB_FLAG_NEXT_MODULE
|
5427 DSDB_SEARCH_SHOW_DELETED
|
5428 DSDB_SEARCH_SHOW_RECYCLED
, ar
->req
);
5429 if (ret
!= LDB_SUCCESS
) {
5430 DBG_ERR(__location__
5431 ": Unable to find object for conflicting record '%s'\n",
5432 ldb_dn_get_linearized(conflict_dn
));
5433 return LDB_ERR_OPERATIONS_ERROR
;
5436 msg
= (*res
)->msgs
[0];
5437 omd_value
= ldb_msg_find_ldb_val(msg
, "replPropertyMetaData");
5438 if (omd_value
== NULL
) {
5439 DBG_ERR(__location__
5440 ": Unable to find replPropertyMetaData for conflicting "
5442 ldb_dn_get_linearized(conflict_dn
));
5443 return LDB_ERR_OPERATIONS_ERROR
;
5446 ndr_err
= ndr_pull_struct_blob(
5447 omd_value
, msg
, &omd
,
5448 (ndr_pull_flags_fn_t
)ndr_pull_replPropertyMetaDataBlob
);
5449 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err
)) {
5450 DBG_ERR(__location__
5451 ": Failed to parse old replPropertyMetaData for %s\n",
5452 ldb_dn_get_linearized(conflict_dn
));
5453 return LDB_ERR_OPERATIONS_ERROR
;
5456 rmd
= ar
->objs
->objects
[ar
->index_current
].meta_data
;
5459 * we decide which is newer based on the RPMD on the name
5460 * attribute. See [MS-DRSR] ResolveNameConflict.
5462 * We expect omd_name to be present, as this is from a local
5463 * search, but while rmd_name should have been given to us by
5464 * the remote server, if it is missing we just prefer the
5466 * replmd_replPropertyMetaData1_new_should_be_taken()
5468 rmd_name
= replmd_replPropertyMetaData1_find_attid(rmd
,
5469 DRSUAPI_ATTID_name
);
5470 omd_name
= replmd_replPropertyMetaData1_find_attid(&omd
,
5471 DRSUAPI_ATTID_name
);
5473 DBG_ERR(__location__
5474 ": Failed to find name attribute in "
5475 "local LDB replPropertyMetaData for %s\n",
5476 ldb_dn_get_linearized(conflict_dn
));
5477 return LDB_ERR_OPERATIONS_ERROR
;
5481 * Should we preserve the current record, and so rename the
5482 * incoming record to be a conflict?
5484 *rename_incoming_record
=
5485 !replmd_replPropertyMetaData1_new_should_be_taken(
5486 (ar
->objs
->dsdb_repl_flags
&
5487 DSDB_REPL_FLAG_PRIORITISE_INCOMING
),
5488 omd_name
, rmd_name
);
5495 callback for replmd_replicated_apply_add()
5496 This copes with the creation of conflict records in the case where
5497 the DN exists, but with a different objectGUID
5499 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
))
5501 struct ldb_dn
*conflict_dn
;
5502 struct replmd_replicated_request
*ar
=
5503 talloc_get_type_abort(req
->context
, struct replmd_replicated_request
);
5504 struct ldb_result
*res
;
5506 bool rename_incoming_record
;
5507 struct ldb_message
*msg
;
5508 struct ldb_request
*down_req
= NULL
;
5510 /* call the normal callback for success */
5511 if (ares
->error
== LDB_SUCCESS
) {
5512 return callback(req
, ares
);
5516 * we have a conflict, and need to decide if we will keep the
5517 * new record or the old record
5520 msg
= ar
->objs
->objects
[ar
->index_current
].msg
;
5521 conflict_dn
= msg
->dn
;
5523 /* For failures other than conflicts, fail the whole operation here */
5524 if (ares
->error
!= LDB_ERR_ENTRY_ALREADY_EXISTS
) {
5525 ldb_asprintf_errstring(ldb_module_get_ctx(ar
->module
), "Failed to locally apply remote add of %s: %s",
5526 ldb_dn_get_linearized(conflict_dn
),
5527 ldb_errstring(ldb_module_get_ctx(ar
->module
)));
5529 return ldb_module_done(ar
->req
, NULL
, NULL
,
5530 LDB_ERR_OPERATIONS_ERROR
);
5534 ret
= incoming_dn_should_be_renamed(req
, ar
, conflict_dn
, &res
,
5535 &rename_incoming_record
);
5536 if (ret
!= LDB_SUCCESS
) {
5540 if (rename_incoming_record
) {
5542 struct ldb_dn
*new_dn
;
5544 guid
= samdb_result_guid(msg
, "objectGUID");
5545 if (GUID_all_zero(&guid
)) {
5546 DEBUG(0,(__location__
": Failed to find objectGUID for conflicting incoming record %s\n",
5547 ldb_dn_get_linearized(conflict_dn
)));
5550 new_dn
= replmd_conflict_dn(req
,
5551 ldb_module_get_ctx(ar
->module
),
5552 conflict_dn
, &guid
);
5553 if (new_dn
== NULL
) {
5554 DEBUG(0,(__location__
": Failed to form conflict DN for %s\n",
5555 ldb_dn_get_linearized(conflict_dn
)));
5559 DEBUG(2,(__location__
": Resolving conflict record via incoming rename '%s' -> '%s'\n",
5560 ldb_dn_get_linearized(conflict_dn
), ldb_dn_get_linearized(new_dn
)));
5562 /* re-submit the request, but with the new DN */
5563 callback
= replmd_op_name_modify_callback
;
5566 /* we are renaming the existing record */
5568 struct ldb_dn
*new_dn
;
5570 guid
= samdb_result_guid(res
->msgs
[0], "objectGUID");
5571 if (GUID_all_zero(&guid
)) {
5572 DEBUG(0,(__location__
": Failed to find objectGUID for existing conflict record %s\n",
5573 ldb_dn_get_linearized(conflict_dn
)));
5577 new_dn
= replmd_conflict_dn(req
,
5578 ldb_module_get_ctx(ar
->module
),
5579 conflict_dn
, &guid
);
5580 if (new_dn
== NULL
) {
5581 DEBUG(0,(__location__
": Failed to form conflict DN for %s\n",
5582 ldb_dn_get_linearized(conflict_dn
)));
5586 DEBUG(2,(__location__
": Resolving conflict record via existing-record rename '%s' -> '%s'\n",
5587 ldb_dn_get_linearized(conflict_dn
), ldb_dn_get_linearized(new_dn
)));
5589 ret
= dsdb_module_rename(ar
->module
, conflict_dn
, new_dn
,
5590 DSDB_FLAG_OWN_MODULE
, req
);
5591 if (ret
!= LDB_SUCCESS
) {
5592 DEBUG(0,(__location__
": Failed to rename conflict dn '%s' to '%s' - %s\n",
5593 ldb_dn_get_linearized(conflict_dn
),
5594 ldb_dn_get_linearized(new_dn
),
5595 ldb_errstring(ldb_module_get_ctx(ar
->module
))));
5600 * now we need to ensure that the rename is seen as an
5601 * originating update. We do that with a modify.
5603 ret
= replmd_name_modify(ar
, req
, new_dn
);
5604 if (ret
!= LDB_SUCCESS
) {
5608 DEBUG(2,(__location__
": With conflicting record renamed, re-apply replicated creation of '%s'\n",
5609 ldb_dn_get_linearized(req
->op
.add
.message
->dn
)));
5612 ret
= ldb_build_add_req(&down_req
,
5613 ldb_module_get_ctx(ar
->module
),
5620 if (ret
!= LDB_SUCCESS
) {
5623 LDB_REQ_SET_LOCATION(down_req
);
5625 /* current partition control needed by "repmd_op_callback" */
5626 ret
= ldb_request_add_control(down_req
,
5627 DSDB_CONTROL_CURRENT_PARTITION_OID
,
5629 if (ret
!= LDB_SUCCESS
) {
5630 return replmd_replicated_request_error(ar
, ret
);
5633 if (ar
->objs
->dsdb_repl_flags
& DSDB_REPL_FLAG_PARTIAL_REPLICA
) {
5634 /* this tells the partition module to make it a
5635 partial replica if creating an NC */
5636 ret
= ldb_request_add_control(down_req
,
5637 DSDB_CONTROL_PARTIAL_REPLICA
,
5639 if (ret
!= LDB_SUCCESS
) {
5640 return replmd_replicated_request_error(ar
, ret
);
5645 * Finally we re-run the add, otherwise the new record won't
5646 * exist, as we are here because of that exact failure!
5648 return ldb_next_request(ar
->module
, down_req
);
5651 /* on failure make the caller get the error. This means
5652 * replication will stop with an error, but there is not much
5655 if (ret
== LDB_SUCCESS
) {
5656 ret
= LDB_ERR_OPERATIONS_ERROR
;
5658 return ldb_module_done(ar
->req
, NULL
, NULL
,
5663 callback for replmd_replicated_apply_add()
5664 This copes with the creation of conflict records in the case where
5665 the DN exists, but with a different objectGUID
5667 static int replmd_op_add_callback(struct ldb_request
*req
, struct ldb_reply
*ares
)
5669 struct replmd_replicated_request
*ar
=
5670 talloc_get_type_abort(req
->context
, struct replmd_replicated_request
);
5672 if (ar
->objs
->objects
[ar
->index_current
].last_known_parent
) {
5673 /* This is like a conflict DN, where we put the object in LostAndFound
5674 see MS-DRSR 4.1.10.6.10 FindBestParentObject */
5675 return replmd_op_possible_conflict_callback(req
, ares
, replmd_op_name_modify_callback
);
5678 return replmd_op_possible_conflict_callback(req
, ares
, replmd_op_callback
);
5682 this is called when a new object comes in over DRS
5684 static int replmd_replicated_apply_add(struct replmd_replicated_request
*ar
)
5686 struct ldb_context
*ldb
;
5687 struct ldb_request
*change_req
;
5688 enum ndr_err_code ndr_err
;
5689 struct ldb_message
*msg
;
5690 struct replPropertyMetaDataBlob
*md
;
5691 struct ldb_val md_value
;
5694 bool remote_isDeleted
= false;
5697 time_t t
= time(NULL
);
5698 const struct ldb_val
*rdn_val
;
5699 struct replmd_private
*replmd_private
=
5700 talloc_get_type(ldb_module_get_private(ar
->module
),
5701 struct replmd_private
);
5702 unix_to_nt_time(&now
, t
);
5704 ldb
= ldb_module_get_ctx(ar
->module
);
5705 msg
= ar
->objs
->objects
[ar
->index_current
].msg
;
5706 md
= ar
->objs
->objects
[ar
->index_current
].meta_data
;
5707 is_schema_nc
= ldb_dn_compare_base(replmd_private
->schema_dn
, msg
->dn
) == 0;
5709 ret
= ldb_sequence_number(ldb
, LDB_SEQ_NEXT
, &ar
->seq_num
);
5710 if (ret
!= LDB_SUCCESS
) {
5711 return replmd_replicated_request_error(ar
, ret
);
5714 ret
= dsdb_msg_add_guid(msg
,
5715 &ar
->objs
->objects
[ar
->index_current
].object_guid
,
5717 if (ret
!= LDB_SUCCESS
) {
5718 return replmd_replicated_request_error(ar
, ret
);
5721 ret
= ldb_msg_add_string(msg
, "whenChanged", ar
->objs
->objects
[ar
->index_current
].when_changed
);
5722 if (ret
!= LDB_SUCCESS
) {
5723 return replmd_replicated_request_error(ar
, ret
);
5726 ret
= samdb_msg_add_uint64(ldb
, msg
, msg
, "uSNCreated", ar
->seq_num
);
5727 if (ret
!= LDB_SUCCESS
) {
5728 return replmd_replicated_request_error(ar
, ret
);
5731 ret
= samdb_msg_add_uint64(ldb
, msg
, msg
, "uSNChanged", ar
->seq_num
);
5732 if (ret
!= LDB_SUCCESS
) {
5733 return replmd_replicated_request_error(ar
, ret
);
5736 /* remove any message elements that have zero values */
5737 for (i
=0; i
<msg
->num_elements
; i
++) {
5738 struct ldb_message_element
*el
= &msg
->elements
[i
];
5740 if (el
->num_values
== 0) {
5741 if (ldb_attr_cmp(msg
->elements
[i
].name
, "objectClass") == 0) {
5742 ldb_asprintf_errstring(ldb
, __location__
5743 ": empty objectClass sent on %s, aborting replication\n",
5744 ldb_dn_get_linearized(msg
->dn
));
5745 return replmd_replicated_request_error(ar
, LDB_ERR_OBJECT_CLASS_VIOLATION
);
5748 DEBUG(4,(__location__
": Removing attribute %s with num_values==0\n",
5750 ldb_msg_remove_element(msg
, &msg
->elements
[i
]);
5757 struct GUID_txt_buf guid_txt
;
5759 char *s
= ldb_ldif_message_redacted_string(ldb
, ar
,
5762 DEBUG(8, ("DRS replication add message of %s:\n%s\n",
5763 GUID_buf_string(&ar
->objs
->objects
[ar
->index_current
].object_guid
, &guid_txt
),
5766 } else if (DEBUGLVL(4)) {
5767 struct GUID_txt_buf guid_txt
;
5768 DEBUG(4, ("DRS replication add DN of %s is %s\n",
5769 GUID_buf_string(&ar
->objs
->objects
[ar
->index_current
].object_guid
, &guid_txt
),
5770 ldb_dn_get_linearized(msg
->dn
)));
5772 remote_isDeleted
= ldb_msg_find_attr_as_bool(msg
,
5773 "isDeleted", false);
5776 * the meta data array is already sorted by the caller, except
5777 * for the RDN, which needs to be added.
5781 rdn_val
= ldb_dn_get_rdn_val(msg
->dn
);
5782 ret
= replmd_update_rpmd_rdn_attr(ldb
, msg
, rdn_val
, NULL
,
5783 md
, ar
, now
, is_schema_nc
,
5785 if (ret
!= LDB_SUCCESS
) {
5786 ldb_asprintf_errstring(ldb
, "%s: error during DRS repl ADD: %s", __func__
, ldb_errstring(ldb
));
5787 return replmd_replicated_request_error(ar
, ret
);
5790 ret
= replmd_replPropertyMetaDataCtr1_sort_and_verify(ldb
, &md
->ctr
.ctr1
, msg
->dn
);
5791 if (ret
!= LDB_SUCCESS
) {
5792 ldb_asprintf_errstring(ldb
, "%s: error during DRS repl ADD: %s", __func__
, ldb_errstring(ldb
));
5793 return replmd_replicated_request_error(ar
, ret
);
5796 for (i
=0; i
< md
->ctr
.ctr1
.count
; i
++) {
5797 md
->ctr
.ctr1
.array
[i
].local_usn
= ar
->seq_num
;
5799 ndr_err
= ndr_push_struct_blob(&md_value
, msg
, md
,
5800 (ndr_push_flags_fn_t
)ndr_push_replPropertyMetaDataBlob
);
5801 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err
)) {
5802 NTSTATUS nt_status
= ndr_map_error2ntstatus(ndr_err
);
5803 return replmd_replicated_request_werror(ar
, ntstatus_to_werror(nt_status
));
5805 ret
= ldb_msg_add_value(msg
, "replPropertyMetaData", &md_value
, NULL
);
5806 if (ret
!= LDB_SUCCESS
) {
5807 return replmd_replicated_request_error(ar
, ret
);
5810 replmd_ldb_message_sort(msg
, ar
->schema
);
5812 if (!remote_isDeleted
) {
5814 * Ensure any local ACL inheritance is applied from
5815 * the parent object.
5817 * This is needed because descriptor is above
5818 * repl_meta_data in the module stack, so this will
5819 * not be triggered 'naturally' by the flow of
5822 ret
= dsdb_module_schedule_sd_propagation(ar
->module
,
5823 ar
->objs
->partition_dn
,
5824 ar
->objs
->objects
[ar
->index_current
].object_guid
,
5825 ar
->objs
->objects
[ar
->index_current
].parent_guid
?
5826 *ar
->objs
->objects
[ar
->index_current
].parent_guid
:
5829 if (ret
!= LDB_SUCCESS
) {
5830 return replmd_replicated_request_error(ar
, ret
);
5834 ar
->isDeleted
= remote_isDeleted
;
5836 ret
= ldb_build_add_req(&change_req
,
5842 replmd_op_add_callback
,
5844 LDB_REQ_SET_LOCATION(change_req
);
5845 if (ret
!= LDB_SUCCESS
) return replmd_replicated_request_error(ar
, ret
);
5847 /* current partition control needed by "repmd_op_callback" */
5848 ret
= ldb_request_add_control(change_req
,
5849 DSDB_CONTROL_CURRENT_PARTITION_OID
,
5851 if (ret
!= LDB_SUCCESS
) return replmd_replicated_request_error(ar
, ret
);
5853 if (ar
->objs
->dsdb_repl_flags
& DSDB_REPL_FLAG_PARTIAL_REPLICA
) {
5854 /* this tells the partition module to make it a
5855 partial replica if creating an NC */
5856 ret
= ldb_request_add_control(change_req
,
5857 DSDB_CONTROL_PARTIAL_REPLICA
,
5859 if (ret
!= LDB_SUCCESS
) return replmd_replicated_request_error(ar
, ret
);
5862 return ldb_next_request(ar
->module
, change_req
);
5865 static int replmd_replicated_apply_search_for_parent_callback(struct ldb_request
*req
,
5866 struct ldb_reply
*ares
)
5868 struct replmd_replicated_request
*ar
= talloc_get_type(req
->context
,
5869 struct replmd_replicated_request
);
5873 return ldb_module_done(ar
->req
, NULL
, NULL
,
5874 LDB_ERR_OPERATIONS_ERROR
);
5878 * The error NO_SUCH_OBJECT is not expected, unless the search
5879 * base is the partition DN, and that case doesn't happen here
5880 * because then we wouldn't get a parent_guid_value in any
5883 if (ares
->error
!= LDB_SUCCESS
) {
5884 return ldb_module_done(ar
->req
, ares
->controls
,
5885 ares
->response
, ares
->error
);
5888 switch (ares
->type
) {
5889 case LDB_REPLY_ENTRY
:
5891 struct ldb_message
*parent_msg
= ares
->message
;
5892 struct ldb_message
*msg
= ar
->objs
->objects
[ar
->index_current
].msg
;
5893 struct ldb_dn
*parent_dn
= NULL
;
5896 if (!ldb_msg_check_string_attribute(msg
, "isDeleted", "TRUE")
5897 && ldb_msg_check_string_attribute(parent_msg
, "isDeleted", "TRUE")) {
5898 /* Per MS-DRSR 4.1.10.6.10
5899 * FindBestParentObject we need to move this
5900 * new object under a deleted object to
5902 struct ldb_dn
*nc_root
;
5904 ret
= dsdb_find_nc_root(ldb_module_get_ctx(ar
->module
), msg
, msg
->dn
, &nc_root
);
5905 if (ret
== LDB_ERR_NO_SUCH_OBJECT
) {
5906 ldb_asprintf_errstring(ldb_module_get_ctx(ar
->module
),
5907 "No suitable NC root found for %s. "
5908 "We need to move this object because parent object %s "
5909 "is deleted, but this object is not.",
5910 ldb_dn_get_linearized(msg
->dn
),
5911 ldb_dn_get_linearized(parent_msg
->dn
));
5912 return ldb_module_done(ar
->req
, NULL
, NULL
, LDB_ERR_OPERATIONS_ERROR
);
5913 } else if (ret
!= LDB_SUCCESS
) {
5914 ldb_asprintf_errstring(ldb_module_get_ctx(ar
->module
),
5915 "Unable to find NC root for %s: %s. "
5916 "We need to move this object because parent object %s "
5917 "is deleted, but this object is not.",
5918 ldb_dn_get_linearized(msg
->dn
),
5919 ldb_errstring(ldb_module_get_ctx(ar
->module
)),
5920 ldb_dn_get_linearized(parent_msg
->dn
));
5921 return ldb_module_done(ar
->req
, NULL
, NULL
, LDB_ERR_OPERATIONS_ERROR
);
5924 ret
= dsdb_wellknown_dn(ldb_module_get_ctx(ar
->module
), msg
,
5926 DS_GUID_LOSTANDFOUND_CONTAINER
,
5928 if (ret
!= LDB_SUCCESS
) {
5929 ldb_asprintf_errstring(ldb_module_get_ctx(ar
->module
),
5930 "Unable to find LostAndFound Container for %s "
5931 "in partition %s: %s. "
5932 "We need to move this object because parent object %s "
5933 "is deleted, but this object is not.",
5934 ldb_dn_get_linearized(msg
->dn
), ldb_dn_get_linearized(nc_root
),
5935 ldb_errstring(ldb_module_get_ctx(ar
->module
)),
5936 ldb_dn_get_linearized(parent_msg
->dn
));
5937 return ldb_module_done(ar
->req
, NULL
, NULL
, LDB_ERR_OPERATIONS_ERROR
);
5939 ar
->objs
->objects
[ar
->index_current
].last_known_parent
5940 = talloc_steal(ar
->objs
->objects
[ar
->index_current
].msg
, parent_msg
->dn
);
5944 = talloc_steal(ar
->objs
->objects
[ar
->index_current
].msg
, parent_msg
->dn
);
5947 ar
->objs
->objects
[ar
->index_current
].local_parent_dn
= parent_dn
;
5949 comp_num
= ldb_dn_get_comp_num(msg
->dn
);
5951 if (!ldb_dn_remove_base_components(msg
->dn
, comp_num
- 1)) {
5953 return ldb_module_done(ar
->req
, NULL
, NULL
, ldb_module_operr(ar
->module
));
5956 if (!ldb_dn_add_base(msg
->dn
, parent_dn
)) {
5958 return ldb_module_done(ar
->req
, NULL
, NULL
, ldb_module_operr(ar
->module
));
5962 case LDB_REPLY_REFERRAL
:
5963 /* we ignore referrals */
5966 case LDB_REPLY_DONE
:
5968 if (ar
->objs
->objects
[ar
->index_current
].local_parent_dn
== NULL
) {
5969 struct GUID_txt_buf str_buf
;
5970 if (ar
->search_msg
!= NULL
) {
5971 ldb_asprintf_errstring(ldb_module_get_ctx(ar
->module
),
5972 "No parent with GUID %s found for object locally known as %s",
5973 GUID_buf_string(ar
->objs
->objects
[ar
->index_current
].parent_guid
, &str_buf
),
5974 ldb_dn_get_linearized(ar
->search_msg
->dn
));
5976 ldb_asprintf_errstring(ldb_module_get_ctx(ar
->module
),
5977 "No parent with GUID %s found for object remotely known as %s",
5978 GUID_buf_string(ar
->objs
->objects
[ar
->index_current
].parent_guid
, &str_buf
),
5979 ldb_dn_get_linearized(ar
->objs
->objects
[ar
->index_current
].msg
->dn
));
5983 * This error code is really important, as it
5984 * is the flag back to the callers to retry
5985 * this with DRSUAPI_DRS_GET_ANC, and so get
5986 * the parent objects before the child
5989 return ldb_module_done(ar
->req
, NULL
, NULL
,
5990 replmd_replicated_request_werror(ar
, WERR_DS_DRA_MISSING_PARENT
));
5993 if (ar
->search_msg
!= NULL
) {
5994 ret
= replmd_replicated_apply_merge(ar
);
5996 ret
= replmd_replicated_apply_add(ar
);
5998 if (ret
!= LDB_SUCCESS
) {
5999 return ldb_module_done(ar
->req
, NULL
, NULL
, ret
);
6008 * Look for the parent object, so we put the new object in the right
6009 * place This is akin to NameObject in MS-DRSR - this routine and the
6010 * callbacks find the right parent name, and correct name for this
6014 static int replmd_replicated_apply_search_for_parent(struct replmd_replicated_request
*ar
)
6016 struct ldb_context
*ldb
;
6020 struct ldb_request
*search_req
;
6021 static const char *attrs
[] = {"isDeleted", NULL
};
6022 struct GUID_txt_buf guid_str_buf
;
6024 ldb
= ldb_module_get_ctx(ar
->module
);
6026 if (ar
->objs
->objects
[ar
->index_current
].parent_guid
== NULL
) {
6027 if (ar
->search_msg
!= NULL
) {
6028 return replmd_replicated_apply_merge(ar
);
6030 return replmd_replicated_apply_add(ar
);
6034 tmp_str
= GUID_buf_string(ar
->objs
->objects
[ar
->index_current
].parent_guid
,
6037 filter
= talloc_asprintf(ar
, "(objectGUID=%s)", tmp_str
);
6038 if (!filter
) return replmd_replicated_request_werror(ar
, WERR_NOT_ENOUGH_MEMORY
);
6040 ret
= ldb_build_search_req(&search_req
,
6043 ar
->objs
->partition_dn
,
6049 replmd_replicated_apply_search_for_parent_callback
,
6051 LDB_REQ_SET_LOCATION(search_req
);
6053 ret
= dsdb_request_add_controls(search_req
,
6054 DSDB_SEARCH_SHOW_RECYCLED
|
6055 DSDB_SEARCH_SHOW_DELETED
|
6056 DSDB_SEARCH_SHOW_EXTENDED_DN
);
6057 if (ret
!= LDB_SUCCESS
) {
6061 return ldb_next_request(ar
->module
, search_req
);
6065 handle renames that come in over DRS replication
6067 static int replmd_replicated_handle_rename(struct replmd_replicated_request
*ar
,
6068 struct ldb_message
*msg
,
6069 struct ldb_request
*parent
,
6070 bool *renamed_to_conflict
)
6073 TALLOC_CTX
*tmp_ctx
= talloc_new(msg
);
6074 struct ldb_result
*res
;
6075 struct ldb_dn
*conflict_dn
;
6076 bool rename_incoming_record
;
6077 struct ldb_dn
*new_dn
;
6080 DEBUG(4,("replmd_replicated_request rename %s => %s\n",
6081 ldb_dn_get_linearized(ar
->search_msg
->dn
),
6082 ldb_dn_get_linearized(msg
->dn
)));
6085 ret
= dsdb_module_rename(ar
->module
, ar
->search_msg
->dn
, msg
->dn
,
6086 DSDB_FLAG_NEXT_MODULE
, ar
->req
);
6087 if (ret
== LDB_SUCCESS
) {
6088 talloc_free(tmp_ctx
);
6092 if (ret
!= LDB_ERR_ENTRY_ALREADY_EXISTS
) {
6093 talloc_free(tmp_ctx
);
6094 ldb_asprintf_errstring(ldb_module_get_ctx(ar
->module
), "Failed to locally apply remote rename from %s to %s: %s",
6095 ldb_dn_get_linearized(ar
->search_msg
->dn
),
6096 ldb_dn_get_linearized(msg
->dn
),
6097 ldb_errstring(ldb_module_get_ctx(ar
->module
)));
6101 conflict_dn
= msg
->dn
;
6104 ret
= incoming_dn_should_be_renamed(tmp_ctx
, ar
, conflict_dn
, &res
,
6105 &rename_incoming_record
);
6106 if (ret
!= LDB_SUCCESS
) {
6110 if (rename_incoming_record
) {
6112 new_dn
= replmd_conflict_dn(msg
,
6113 ldb_module_get_ctx(ar
->module
),
6115 &ar
->objs
->objects
[ar
->index_current
].object_guid
);
6116 if (new_dn
== NULL
) {
6117 ldb_asprintf_errstring(ldb_module_get_ctx(ar
->module
),
6118 "Failed to form conflict DN for %s\n",
6119 ldb_dn_get_linearized(msg
->dn
));
6121 talloc_free(tmp_ctx
);
6122 return replmd_replicated_request_werror(ar
, WERR_NOT_ENOUGH_MEMORY
);
6125 ret
= dsdb_module_rename(ar
->module
, ar
->search_msg
->dn
, new_dn
,
6126 DSDB_FLAG_NEXT_MODULE
, ar
->req
);
6127 if (ret
!= LDB_SUCCESS
) {
6128 ldb_asprintf_errstring(ldb_module_get_ctx(ar
->module
),
6129 "Failed to rename incoming conflicting dn '%s' (was '%s') to '%s' - %s\n",
6130 ldb_dn_get_linearized(conflict_dn
),
6131 ldb_dn_get_linearized(ar
->search_msg
->dn
),
6132 ldb_dn_get_linearized(new_dn
),
6133 ldb_errstring(ldb_module_get_ctx(ar
->module
)));
6134 talloc_free(tmp_ctx
);
6135 return replmd_replicated_request_werror(ar
, WERR_DS_DRA_DB_ERROR
);
6139 *renamed_to_conflict
= true;
6140 talloc_free(tmp_ctx
);
6144 /* we are renaming the existing record */
6146 guid
= samdb_result_guid(res
->msgs
[0], "objectGUID");
6147 if (GUID_all_zero(&guid
)) {
6148 DEBUG(0,(__location__
": Failed to find objectGUID for existing conflict record %s\n",
6149 ldb_dn_get_linearized(conflict_dn
)));
6153 new_dn
= replmd_conflict_dn(tmp_ctx
,
6154 ldb_module_get_ctx(ar
->module
),
6155 conflict_dn
, &guid
);
6156 if (new_dn
== NULL
) {
6157 DEBUG(0,(__location__
": Failed to form conflict DN for %s\n",
6158 ldb_dn_get_linearized(conflict_dn
)));
6162 DEBUG(2,(__location__
": Resolving conflict record via existing-record rename '%s' -> '%s'\n",
6163 ldb_dn_get_linearized(conflict_dn
), ldb_dn_get_linearized(new_dn
)));
6165 ret
= dsdb_module_rename(ar
->module
, conflict_dn
, new_dn
,
6166 DSDB_FLAG_OWN_MODULE
, ar
->req
);
6167 if (ret
!= LDB_SUCCESS
) {
6168 DEBUG(0,(__location__
": Failed to rename conflict dn '%s' to '%s' - %s\n",
6169 ldb_dn_get_linearized(conflict_dn
),
6170 ldb_dn_get_linearized(new_dn
),
6171 ldb_errstring(ldb_module_get_ctx(ar
->module
))));
6176 * now we need to ensure that the rename is seen as an
6177 * originating update. We do that with a modify.
6179 ret
= replmd_name_modify(ar
, ar
->req
, new_dn
);
6180 if (ret
!= LDB_SUCCESS
) {
6184 DEBUG(2,(__location__
": With conflicting record renamed, re-apply replicated rename '%s' -> '%s'\n",
6185 ldb_dn_get_linearized(ar
->search_msg
->dn
),
6186 ldb_dn_get_linearized(msg
->dn
)));
6189 * With the other record out of the way, do the rename we had
6192 ret
= dsdb_module_rename(ar
->module
, ar
->search_msg
->dn
, msg
->dn
,
6193 DSDB_FLAG_NEXT_MODULE
, ar
->req
);
6194 if (ret
!= LDB_SUCCESS
) {
6195 DEBUG(0,(__location__
": After conflict resolution, failed to rename dn '%s' to '%s' - %s\n",
6196 ldb_dn_get_linearized(ar
->search_msg
->dn
),
6197 ldb_dn_get_linearized(msg
->dn
),
6198 ldb_errstring(ldb_module_get_ctx(ar
->module
))));
6202 talloc_free(tmp_ctx
);
6206 * On failure make the caller get the error
6207 * This means replication will stop with an error,
6208 * but there is not much else we can do. In the
6209 * LDB_ERR_ENTRY_ALREADY_EXISTS case this is exactly what is
6212 if (ret
== LDB_SUCCESS
) {
6213 ret
= LDB_ERR_OPERATIONS_ERROR
;
6216 talloc_free(tmp_ctx
);
6221 static int replmd_replicated_apply_merge(struct replmd_replicated_request
*ar
)
6223 struct ldb_context
*ldb
;
6224 struct ldb_request
*change_req
;
6225 enum ndr_err_code ndr_err
;
6226 struct ldb_message
*msg
;
6227 struct replPropertyMetaDataBlob
*rmd
;
6228 struct replPropertyMetaDataBlob omd
;
6229 const struct ldb_val
*omd_value
;
6230 struct replPropertyMetaDataBlob nmd
;
6231 struct ldb_val nmd_value
;
6232 struct GUID remote_parent_guid
;
6235 unsigned int removed_attrs
= 0;
6237 int (*callback
)(struct ldb_request
*req
, struct ldb_reply
*ares
) = replmd_op_callback
;
6238 bool isDeleted
= false;
6239 bool local_isDeleted
= false;
6240 bool remote_isDeleted
= false;
6241 bool take_remote_isDeleted
= false;
6242 bool sd_updated
= false;
6243 bool renamed
= false;
6244 bool renamed_to_conflict
= false;
6245 bool is_schema_nc
= false;
6247 const struct ldb_val
*old_rdn
, *new_rdn
;
6248 struct replmd_private
*replmd_private
=
6249 talloc_get_type(ldb_module_get_private(ar
->module
),
6250 struct replmd_private
);
6252 time_t t
= time(NULL
);
6253 unix_to_nt_time(&now
, t
);
6255 ldb
= ldb_module_get_ctx(ar
->module
);
6256 msg
= ar
->objs
->objects
[ar
->index_current
].msg
;
6258 is_schema_nc
= ldb_dn_compare_base(replmd_private
->schema_dn
, msg
->dn
) == 0;
6260 rmd
= ar
->objs
->objects
[ar
->index_current
].meta_data
;
6264 /* find existing meta data */
6265 omd_value
= ldb_msg_find_ldb_val(ar
->search_msg
, "replPropertyMetaData");
6267 ndr_err
= ndr_pull_struct_blob(omd_value
, ar
, &omd
,
6268 (ndr_pull_flags_fn_t
)ndr_pull_replPropertyMetaDataBlob
);
6269 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err
)) {
6270 nt_status
= ndr_map_error2ntstatus(ndr_err
);
6271 return replmd_replicated_request_werror(ar
, ntstatus_to_werror(nt_status
));
6274 if (omd
.version
!= 1) {
6275 return replmd_replicated_request_werror(ar
, WERR_DS_DRA_INTERNAL_ERROR
);
6280 struct GUID_txt_buf guid_txt
;
6282 char *s
= ldb_ldif_message_redacted_string(ldb
, ar
,
6283 LDB_CHANGETYPE_MODIFY
, msg
);
6284 DEBUG(8, ("Initial DRS replication modify message of %s is:\n%s\n"
6287 GUID_buf_string(&ar
->objs
->objects
[ar
->index_current
].object_guid
, &guid_txt
),
6289 ndr_print_struct_string(s
,
6290 (ndr_print_fn_t
)ndr_print_replPropertyMetaDataBlob
,
6291 "existing replPropertyMetaData",
6293 ndr_print_struct_string(s
,
6294 (ndr_print_fn_t
)ndr_print_replPropertyMetaDataBlob
,
6295 "incoming replPropertyMetaData",
6298 } else if (DEBUGLVL(4)) {
6299 struct GUID_txt_buf guid_txt
;
6301 DEBUG(4, ("Initial DRS replication modify DN of %s is: %s\n",
6302 GUID_buf_string(&ar
->objs
->objects
[ar
->index_current
].object_guid
,
6304 ldb_dn_get_linearized(msg
->dn
)));
6307 local_isDeleted
= ldb_msg_find_attr_as_bool(ar
->search_msg
,
6308 "isDeleted", false);
6309 remote_isDeleted
= ldb_msg_find_attr_as_bool(msg
,
6310 "isDeleted", false);
6313 * Fill in the remote_parent_guid with the GUID or an all-zero
6316 if (ar
->objs
->objects
[ar
->index_current
].parent_guid
!= NULL
) {
6317 remote_parent_guid
= *ar
->objs
->objects
[ar
->index_current
].parent_guid
;
6319 remote_parent_guid
= GUID_zero();
6323 * To ensure we follow a complex rename chain around, we have
6324 * to confirm that the DN is the same (mostly to confirm the
6325 * RDN) and the parentGUID is the same.
6327 * This ensures we keep things under the correct parent, which
6328 * replmd_replicated_handle_rename() will do.
6331 if (strcmp(ldb_dn_get_linearized(msg
->dn
), ldb_dn_get_linearized(ar
->search_msg
->dn
)) == 0
6332 && GUID_equal(&remote_parent_guid
, &ar
->local_parent_guid
)) {
6336 * handle renames, even just by case that come in over
6337 * DRS. Changes in the parent DN don't hit us here,
6338 * because the search for a parent will clean up those
6341 * We also have already filtered out the case where
6342 * the peer has an older name to what we have (see
6343 * replmd_replicated_apply_search_callback())
6345 ret
= replmd_replicated_handle_rename(ar
, msg
, ar
->req
, &renamed_to_conflict
);
6348 * This looks strange, but we must set this after any
6349 * rename, otherwise the SD propegation will not
6350 * happen (which might matter if we have a new parent)
6352 * The additional case of calling
6353 * replmd_op_name_modify_callback (below) is
6354 * controlled by renamed_to_conflict.
6359 if (ret
!= LDB_SUCCESS
) {
6360 ldb_debug(ldb
, LDB_DEBUG_FATAL
,
6361 "replmd_replicated_request rename %s => %s failed - %s\n",
6362 ldb_dn_get_linearized(ar
->search_msg
->dn
),
6363 ldb_dn_get_linearized(msg
->dn
),
6364 ldb_errstring(ldb
));
6365 return replmd_replicated_request_werror(ar
, WERR_DS_DRA_DB_ERROR
);
6368 if (renamed_to_conflict
== true) {
6370 * Set the callback to one that will fix up the name
6371 * metadata on the new conflict DN
6373 callback
= replmd_op_name_modify_callback
;
6378 nmd
.ctr
.ctr1
.count
= omd
.ctr
.ctr1
.count
+ rmd
->ctr
.ctr1
.count
;
6379 nmd
.ctr
.ctr1
.array
= talloc_array(ar
,
6380 struct replPropertyMetaData1
,
6381 nmd
.ctr
.ctr1
.count
);
6382 if (!nmd
.ctr
.ctr1
.array
) return replmd_replicated_request_werror(ar
, WERR_NOT_ENOUGH_MEMORY
);
6384 /* first copy the old meta data */
6385 for (i
=0; i
< omd
.ctr
.ctr1
.count
; i
++) {
6386 nmd
.ctr
.ctr1
.array
[ni
] = omd
.ctr
.ctr1
.array
[i
];
6391 /* now merge in the new meta data */
6392 for (i
=0; i
< rmd
->ctr
.ctr1
.count
; i
++) {
6395 for (j
=0; j
< ni
; j
++) {
6398 if (rmd
->ctr
.ctr1
.array
[i
].attid
!= nmd
.ctr
.ctr1
.array
[j
].attid
) {
6402 cmp
= replmd_replPropertyMetaData1_new_should_be_taken(
6403 ar
->objs
->dsdb_repl_flags
,
6404 &nmd
.ctr
.ctr1
.array
[j
],
6405 &rmd
->ctr
.ctr1
.array
[i
]);
6407 /* replace the entry */
6408 nmd
.ctr
.ctr1
.array
[j
] = rmd
->ctr
.ctr1
.array
[i
];
6409 if (ar
->seq_num
== 0) {
6410 ret
= ldb_sequence_number(ldb
, LDB_SEQ_NEXT
, &ar
->seq_num
);
6411 if (ret
!= LDB_SUCCESS
) {
6412 return replmd_replicated_request_error(ar
, ret
);
6415 nmd
.ctr
.ctr1
.array
[j
].local_usn
= ar
->seq_num
;
6416 switch (nmd
.ctr
.ctr1
.array
[j
].attid
) {
6417 case DRSUAPI_ATTID_ntSecurityDescriptor
:
6420 case DRSUAPI_ATTID_isDeleted
:
6421 take_remote_isDeleted
= true;
6430 if (rmd
->ctr
.ctr1
.array
[i
].attid
!= DRSUAPI_ATTID_instanceType
) {
6431 DEBUG(3,("Discarding older DRS attribute update to %s on %s from %s\n",
6432 msg
->elements
[i
-removed_attrs
].name
,
6433 ldb_dn_get_linearized(msg
->dn
),
6434 GUID_string(ar
, &rmd
->ctr
.ctr1
.array
[i
].originating_invocation_id
)));
6437 /* we don't want to apply this change so remove the attribute */
6438 ldb_msg_remove_element(msg
, &msg
->elements
[i
-removed_attrs
]);
6445 if (found
) continue;
6447 nmd
.ctr
.ctr1
.array
[ni
] = rmd
->ctr
.ctr1
.array
[i
];
6448 if (ar
->seq_num
== 0) {
6449 ret
= ldb_sequence_number(ldb
, LDB_SEQ_NEXT
, &ar
->seq_num
);
6450 if (ret
!= LDB_SUCCESS
) {
6451 return replmd_replicated_request_error(ar
, ret
);
6454 nmd
.ctr
.ctr1
.array
[ni
].local_usn
= ar
->seq_num
;
6455 switch (nmd
.ctr
.ctr1
.array
[ni
].attid
) {
6456 case DRSUAPI_ATTID_ntSecurityDescriptor
:
6459 case DRSUAPI_ATTID_isDeleted
:
6460 take_remote_isDeleted
= true;
6469 * finally correct the size of the meta_data array
6471 nmd
.ctr
.ctr1
.count
= ni
;
6473 new_rdn
= ldb_dn_get_rdn_val(msg
->dn
);
6474 old_rdn
= ldb_dn_get_rdn_val(ar
->search_msg
->dn
);
6477 ret
= replmd_update_rpmd_rdn_attr(ldb
, msg
, new_rdn
, old_rdn
,
6478 &nmd
, ar
, now
, is_schema_nc
,
6480 if (ret
!= LDB_SUCCESS
) {
6481 ldb_asprintf_errstring(ldb
, "%s: error during DRS repl merge: %s", __func__
, ldb_errstring(ldb
));
6482 return replmd_replicated_request_error(ar
, ret
);
6486 * sort the new meta data array
6488 ret
= replmd_replPropertyMetaDataCtr1_sort_and_verify(ldb
, &nmd
.ctr
.ctr1
, msg
->dn
);
6489 if (ret
!= LDB_SUCCESS
) {
6490 ldb_asprintf_errstring(ldb
, "%s: error during DRS repl merge: %s", __func__
, ldb_errstring(ldb
));
6495 * Work out if this object is deleted, so we can prune any extra attributes. See MS-DRSR 4.1.10.6.9
6498 * This also controls SD propagation below
6500 if (take_remote_isDeleted
) {
6501 isDeleted
= remote_isDeleted
;
6503 isDeleted
= local_isDeleted
;
6506 ar
->isDeleted
= isDeleted
;
6509 * check if some replicated attributes left, otherwise skip the ldb_modify() call
6511 if (msg
->num_elements
== 0) {
6512 ldb_debug(ldb
, LDB_DEBUG_TRACE
, "replmd_replicated_apply_merge[%u]: skip replace\n",
6515 return replmd_replicated_apply_isDeleted(ar
);
6518 ldb_debug(ldb
, LDB_DEBUG_TRACE
, "replmd_replicated_apply_merge[%u]: replace %u attributes\n",
6519 ar
->index_current
, msg
->num_elements
);
6523 * This is an new name for this object, so we must
6524 * inherit from the parent
6526 * This is needed because descriptor is above
6527 * repl_meta_data in the module stack, so this will
6528 * not be triggered 'naturally' by the flow of
6531 ret
= dsdb_module_schedule_sd_propagation(ar
->module
,
6532 ar
->objs
->partition_dn
,
6533 ar
->objs
->objects
[ar
->index_current
].object_guid
,
6534 ar
->objs
->objects
[ar
->index_current
].parent_guid
?
6535 *ar
->objs
->objects
[ar
->index_current
].parent_guid
:
6538 if (ret
!= LDB_SUCCESS
) {
6539 return ldb_operr(ldb
);
6543 if (sd_updated
&& !isDeleted
) {
6545 * This is an existing object, so there is no need to
6546 * inherit from the parent, but we must inherit any
6547 * incoming changes to our child objects.
6549 * This is needed because descriptor is above
6550 * repl_meta_data in the module stack, so this will
6551 * not be triggered 'naturally' by the flow of
6554 ret
= dsdb_module_schedule_sd_propagation(ar
->module
,
6555 ar
->objs
->partition_dn
,
6556 ar
->objs
->objects
[ar
->index_current
].object_guid
,
6557 ar
->objs
->objects
[ar
->index_current
].parent_guid
?
6558 *ar
->objs
->objects
[ar
->index_current
].parent_guid
:
6561 if (ret
!= LDB_SUCCESS
) {
6562 return ldb_operr(ldb
);
6566 /* create the meta data value */
6567 ndr_err
= ndr_push_struct_blob(&nmd_value
, msg
, &nmd
,
6568 (ndr_push_flags_fn_t
)ndr_push_replPropertyMetaDataBlob
);
6569 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err
)) {
6570 nt_status
= ndr_map_error2ntstatus(ndr_err
);
6571 return replmd_replicated_request_werror(ar
, ntstatus_to_werror(nt_status
));
6575 * when we know that we'll modify the record, add the whenChanged, uSNChanged
6576 * and replPopertyMetaData attributes
6578 ret
= ldb_msg_add_string(msg
, "whenChanged", ar
->objs
->objects
[ar
->index_current
].when_changed
);
6579 if (ret
!= LDB_SUCCESS
) {
6580 return replmd_replicated_request_error(ar
, ret
);
6582 ret
= samdb_msg_add_uint64(ldb
, msg
, msg
, "uSNChanged", ar
->seq_num
);
6583 if (ret
!= LDB_SUCCESS
) {
6584 return replmd_replicated_request_error(ar
, ret
);
6586 ret
= ldb_msg_add_value(msg
, "replPropertyMetaData", &nmd_value
, NULL
);
6587 if (ret
!= LDB_SUCCESS
) {
6588 return replmd_replicated_request_error(ar
, ret
);
6591 replmd_ldb_message_sort(msg
, ar
->schema
);
6593 /* we want to replace the old values */
6594 for (i
=0; i
< msg
->num_elements
; i
++) {
6595 msg
->elements
[i
].flags
= LDB_FLAG_MOD_REPLACE
;
6596 if (ldb_attr_cmp(msg
->elements
[i
].name
, "objectClass") == 0) {
6597 if (msg
->elements
[i
].num_values
== 0) {
6598 ldb_asprintf_errstring(ldb
, __location__
6599 ": objectClass removed on %s, aborting replication\n",
6600 ldb_dn_get_linearized(msg
->dn
));
6601 return replmd_replicated_request_error(ar
, LDB_ERR_OBJECT_CLASS_VIOLATION
);
6607 struct GUID_txt_buf guid_txt
;
6609 char *s
= ldb_ldif_message_redacted_string(ldb
, ar
,
6610 LDB_CHANGETYPE_MODIFY
,
6612 DEBUG(8, ("Final DRS replication modify message of %s:\n%s\n",
6613 GUID_buf_string(&ar
->objs
->objects
[ar
->index_current
].object_guid
,
6617 } else if (DEBUGLVL(4)) {
6618 struct GUID_txt_buf guid_txt
;
6620 DEBUG(4, ("Final DRS replication modify DN of %s is %s\n",
6621 GUID_buf_string(&ar
->objs
->objects
[ar
->index_current
].object_guid
,
6623 ldb_dn_get_linearized(msg
->dn
)));
6626 ret
= ldb_build_mod_req(&change_req
,
6634 LDB_REQ_SET_LOCATION(change_req
);
6635 if (ret
!= LDB_SUCCESS
) return replmd_replicated_request_error(ar
, ret
);
6637 /* current partition control needed by "repmd_op_callback" */
6638 ret
= ldb_request_add_control(change_req
,
6639 DSDB_CONTROL_CURRENT_PARTITION_OID
,
6641 if (ret
!= LDB_SUCCESS
) return replmd_replicated_request_error(ar
, ret
);
6643 return ldb_next_request(ar
->module
, change_req
);
6646 static int replmd_replicated_apply_search_callback(struct ldb_request
*req
,
6647 struct ldb_reply
*ares
)
6649 struct replmd_replicated_request
*ar
= talloc_get_type(req
->context
,
6650 struct replmd_replicated_request
);
6654 return ldb_module_done(ar
->req
, NULL
, NULL
,
6655 LDB_ERR_OPERATIONS_ERROR
);
6657 if (ares
->error
!= LDB_SUCCESS
&&
6658 ares
->error
!= LDB_ERR_NO_SUCH_OBJECT
) {
6659 return ldb_module_done(ar
->req
, ares
->controls
,
6660 ares
->response
, ares
->error
);
6663 switch (ares
->type
) {
6664 case LDB_REPLY_ENTRY
:
6665 ar
->search_msg
= talloc_steal(ar
, ares
->message
);
6668 case LDB_REPLY_REFERRAL
:
6669 /* we ignore referrals */
6672 case LDB_REPLY_DONE
:
6674 struct replPropertyMetaData1
*md_remote
;
6675 struct replPropertyMetaData1
*md_local
;
6677 struct replPropertyMetaDataBlob omd
;
6678 const struct ldb_val
*omd_value
;
6679 struct replPropertyMetaDataBlob
*rmd
;
6680 struct ldb_message
*msg
;
6682 ar
->objs
->objects
[ar
->index_current
].local_parent_dn
= NULL
;
6683 ar
->objs
->objects
[ar
->index_current
].last_known_parent
= NULL
;
6686 * This is the ADD case, find the appropriate parent,
6687 * as this object doesn't exist locally:
6689 if (ar
->search_msg
== NULL
) {
6690 ret
= replmd_replicated_apply_search_for_parent(ar
);
6691 if (ret
!= LDB_SUCCESS
) {
6692 return ldb_module_done(ar
->req
, NULL
, NULL
, ret
);
6699 * Otherwise, in the MERGE case, work out if we are
6700 * attempting a rename, and if so find the parent the
6701 * newly renamed object wants to belong under (which
6702 * may not be the parent in it's attached string DN
6704 rmd
= ar
->objs
->objects
[ar
->index_current
].meta_data
;
6708 /* find existing meta data */
6709 omd_value
= ldb_msg_find_ldb_val(ar
->search_msg
, "replPropertyMetaData");
6711 enum ndr_err_code ndr_err
;
6712 ndr_err
= ndr_pull_struct_blob(omd_value
, ar
, &omd
,
6713 (ndr_pull_flags_fn_t
)ndr_pull_replPropertyMetaDataBlob
);
6714 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err
)) {
6715 NTSTATUS nt_status
= ndr_map_error2ntstatus(ndr_err
);
6716 return replmd_replicated_request_werror(ar
, ntstatus_to_werror(nt_status
));
6719 if (omd
.version
!= 1) {
6720 return replmd_replicated_request_werror(ar
, WERR_DS_DRA_INTERNAL_ERROR
);
6724 ar
->local_parent_guid
= samdb_result_guid(ar
->search_msg
, "parentGUID");
6726 instanceType
= ldb_msg_find_attr_as_int(ar
->search_msg
, "instanceType", 0);
6727 if (((instanceType
& INSTANCE_TYPE_IS_NC_HEAD
) == 0)
6728 && GUID_all_zero(&ar
->local_parent_guid
)) {
6729 DEBUG(0, ("Refusing to replicate new version of %s "
6730 "as local object has an all-zero parentGUID attribute, "
6731 "despite not being an NC root\n",
6732 ldb_dn_get_linearized(ar
->search_msg
->dn
)));
6733 return replmd_replicated_request_werror(ar
, WERR_DS_DRA_INTERNAL_ERROR
);
6737 * now we need to check for double renames. We could have a
6738 * local rename pending which our replication partner hasn't
6739 * received yet. We choose which one wins by looking at the
6740 * attribute stamps on the two objects, the newer one wins.
6742 * This also simply applies the correct algorithms for
6743 * determining if a change was made to name at all, or
6744 * if the object has just been renamed under the same
6747 md_remote
= replmd_replPropertyMetaData1_find_attid(rmd
, DRSUAPI_ATTID_name
);
6748 md_local
= replmd_replPropertyMetaData1_find_attid(&omd
, DRSUAPI_ATTID_name
);
6750 DEBUG(0,(__location__
": Failed to find name attribute in local LDB replPropertyMetaData for %s\n",
6751 ldb_dn_get_linearized(ar
->search_msg
->dn
)));
6752 return replmd_replicated_request_werror(ar
, WERR_DS_DRA_DB_ERROR
);
6756 * if there is no name attribute given then we have to assume the
6757 * object we've received has the older name
6759 if (replmd_replPropertyMetaData1_new_should_be_taken(
6760 ar
->objs
->dsdb_repl_flags
& DSDB_REPL_FLAG_PRIORITISE_INCOMING
,
6761 md_local
, md_remote
)) {
6762 struct GUID_txt_buf p_guid_local
;
6763 struct GUID_txt_buf p_guid_remote
;
6764 msg
= ar
->objs
->objects
[ar
->index_current
].msg
;
6766 /* Merge on the existing object, with rename */
6768 DEBUG(4,(__location__
": Looking for new parent for object %s currently under %s "
6769 "as incoming object changing to %s under %s\n",
6770 ldb_dn_get_linearized(ar
->search_msg
->dn
),
6771 GUID_buf_string(&ar
->local_parent_guid
, &p_guid_local
),
6772 ldb_dn_get_linearized(msg
->dn
),
6773 GUID_buf_string(ar
->objs
->objects
[ar
->index_current
].parent_guid
,
6775 ret
= replmd_replicated_apply_search_for_parent(ar
);
6777 struct GUID_txt_buf p_guid_local
;
6778 struct GUID_txt_buf p_guid_remote
;
6779 msg
= ar
->objs
->objects
[ar
->index_current
].msg
;
6782 * Merge on the existing object, force no
6783 * rename (code below just to explain why in
6787 if (strcmp(ldb_dn_get_linearized(ar
->search_msg
->dn
),
6788 ldb_dn_get_linearized(msg
->dn
)) == 0) {
6789 if (ar
->objs
->objects
[ar
->index_current
].parent_guid
!= NULL
&&
6790 GUID_equal(&ar
->local_parent_guid
,
6791 ar
->objs
->objects
[ar
->index_current
].parent_guid
)
6793 DEBUG(4,(__location__
": Keeping object %s at under %s "
6794 "despite incoming object changing parent to %s\n",
6795 ldb_dn_get_linearized(ar
->search_msg
->dn
),
6796 GUID_buf_string(&ar
->local_parent_guid
, &p_guid_local
),
6797 GUID_buf_string(ar
->objs
->objects
[ar
->index_current
].parent_guid
,
6801 DEBUG(4,(__location__
": Keeping object %s at under %s "
6802 " and rejecting older rename to %s under %s\n",
6803 ldb_dn_get_linearized(ar
->search_msg
->dn
),
6804 GUID_buf_string(&ar
->local_parent_guid
, &p_guid_local
),
6805 ldb_dn_get_linearized(msg
->dn
),
6806 GUID_buf_string(ar
->objs
->objects
[ar
->index_current
].parent_guid
,
6810 * This assignment ensures that the strcmp()
6811 * and GUID_equal() calls in
6812 * replmd_replicated_apply_merge() avoids the
6815 ar
->objs
->objects
[ar
->index_current
].parent_guid
=
6816 &ar
->local_parent_guid
;
6818 msg
->dn
= ar
->search_msg
->dn
;
6819 ret
= replmd_replicated_apply_merge(ar
);
6821 if (ret
!= LDB_SUCCESS
) {
6822 return ldb_module_done(ar
->req
, NULL
, NULL
, ret
);
6832 * Returns true if we can group together processing this link attribute,
6833 * i.e. it has the same source-object and attribute ID as other links
6834 * already in the group
6836 static bool la_entry_matches_group(struct la_entry
*la_entry
,
6837 struct la_group
*la_group
)
6839 struct la_entry
*prev
= la_group
->la_entries
;
6841 return (la_entry
->la
->attid
== prev
->la
->attid
&&
6842 GUID_equal(&la_entry
->la
->identifier
->guid
,
6843 &prev
->la
->identifier
->guid
));
6847 * Creates a new la_entry to store replication info for a single
6850 static struct la_entry
*
6851 create_la_entry(struct replmd_private
*replmd_private
,
6852 struct drsuapi_DsReplicaLinkedAttribute
*la
,
6853 uint32_t dsdb_repl_flags
)
6855 struct la_entry
*la_entry
;
6857 if (replmd_private
->la_ctx
== NULL
) {
6858 replmd_private
->la_ctx
= talloc_new(replmd_private
);
6860 la_entry
= talloc(replmd_private
->la_ctx
, struct la_entry
);
6861 if (la_entry
== NULL
) {
6864 la_entry
->la
= talloc(la_entry
,
6865 struct drsuapi_DsReplicaLinkedAttribute
);
6866 if (la_entry
->la
== NULL
) {
6867 talloc_free(la_entry
);
6870 *la_entry
->la
= *la
;
6871 la_entry
->dsdb_repl_flags
= dsdb_repl_flags
;
6874 * we need to steal the non-scalars so they stay
6875 * around until the end of the transaction
6877 talloc_steal(la_entry
->la
, la_entry
->la
->identifier
);
6878 talloc_steal(la_entry
->la
, la_entry
->la
->value
.blob
);
6884 * Stores the linked attributes received in the replication chunk - these get
6885 * applied at the end of the transaction. We also check that each linked
6886 * attribute is valid, i.e. source and target objects are known.
6888 static int replmd_store_linked_attributes(struct replmd_replicated_request
*ar
)
6890 int ret
= LDB_SUCCESS
;
6892 struct ldb_module
*module
= ar
->module
;
6893 struct replmd_private
*replmd_private
=
6894 talloc_get_type(ldb_module_get_private(module
), struct replmd_private
);
6895 struct la_group
*la_group
= NULL
;
6896 struct ldb_context
*ldb
;
6897 TALLOC_CTX
*tmp_ctx
= NULL
;
6898 struct ldb_message
*src_msg
= NULL
;
6899 const struct dsdb_attribute
*attr
= NULL
;
6901 ldb
= ldb_module_get_ctx(module
);
6903 DEBUG(4,("linked_attributes_count=%u\n", ar
->objs
->linked_attributes_count
));
6905 /* save away the linked attributes for the end of the transaction */
6906 for (i
= 0; i
< ar
->objs
->linked_attributes_count
; i
++) {
6907 struct la_entry
*la_entry
;
6910 /* create an entry to store the received link attribute info */
6911 la_entry
= create_la_entry(replmd_private
,
6912 &ar
->objs
->linked_attributes
[i
],
6913 ar
->objs
->dsdb_repl_flags
);
6914 if (la_entry
== NULL
) {
6916 return LDB_ERR_OPERATIONS_ERROR
;
6920 * check if we're still dealing with the same source object
6923 new_srcobj
= (la_group
== NULL
||
6924 !la_entry_matches_group(la_entry
, la_group
));
6928 /* get a new mem_ctx to lookup the source object */
6929 TALLOC_FREE(tmp_ctx
);
6930 tmp_ctx
= talloc_new(ar
);
6931 if (tmp_ctx
== NULL
) {
6933 return LDB_ERR_OPERATIONS_ERROR
;
6936 /* verify the link source exists */
6937 ret
= replmd_get_la_entry_source(module
, la_entry
,
6942 * When we fail to find the source object, the error
6943 * code we pass back here is really important. It flags
6944 * back to the callers to retry this request with
6945 * DRSUAPI_DRS_GET_ANC. This case should never happen
6946 * if we're replicating from a Samba DC, but it is
6947 * needed to talk to a Windows DC
6949 if (ret
== LDB_ERR_NO_SUCH_OBJECT
) {
6950 WERROR err
= WERR_DS_DRA_MISSING_PARENT
;
6951 ret
= replmd_replicated_request_werror(ar
,
6957 ret
= replmd_verify_link_target(ar
, tmp_ctx
, la_entry
,
6959 if (ret
!= LDB_SUCCESS
) {
6963 /* group the links together by source-object for efficiency */
6965 la_group
= talloc_zero(replmd_private
->la_ctx
,
6967 if (la_group
== NULL
) {
6969 return LDB_ERR_OPERATIONS_ERROR
;
6971 DLIST_ADD(replmd_private
->la_list
, la_group
);
6973 DLIST_ADD(la_group
->la_entries
, la_entry
);
6974 replmd_private
->total_links
++;
6977 TALLOC_FREE(tmp_ctx
);
6981 static int replmd_replicated_uptodate_vector(struct replmd_replicated_request
*ar
);
6983 static int replmd_replicated_apply_next(struct replmd_replicated_request
*ar
)
6985 struct ldb_context
*ldb
;
6989 struct ldb_request
*search_req
;
6990 static const char *attrs
[] = { "repsFrom", "replUpToDateVector",
6991 "parentGUID", "instanceType",
6992 "replPropertyMetaData", "nTSecurityDescriptor",
6993 "isDeleted", NULL
};
6994 struct GUID_txt_buf guid_str_buf
;
6996 if (ar
->index_current
>= ar
->objs
->num_objects
) {
6999 * Now that we've applied all the objects, check the new linked
7000 * attributes and store them (we apply them in .prepare_commit)
7002 ret
= replmd_store_linked_attributes(ar
);
7004 if (ret
!= LDB_SUCCESS
) {
7008 /* done applying objects, move on to the next stage */
7009 return replmd_replicated_uptodate_vector(ar
);
7012 ldb
= ldb_module_get_ctx(ar
->module
);
7013 ar
->search_msg
= NULL
;
7014 ar
->isDeleted
= false;
7016 tmp_str
= GUID_buf_string(&ar
->objs
->objects
[ar
->index_current
].object_guid
,
7019 filter
= talloc_asprintf(ar
, "(objectGUID=%s)", tmp_str
);
7020 if (!filter
) return replmd_replicated_request_werror(ar
, WERR_NOT_ENOUGH_MEMORY
);
7022 ret
= ldb_build_search_req(&search_req
,
7025 ar
->objs
->partition_dn
,
7031 replmd_replicated_apply_search_callback
,
7033 LDB_REQ_SET_LOCATION(search_req
);
7036 * We set DSDB_SEARCH_SHOW_EXTENDED_DN to get the GUID on the
7037 * DN. This in turn helps our operational module find the
7038 * record by GUID, not DN lookup which is more error prone if
7039 * DN indexing changes. We prefer to keep chasing GUIDs
7040 * around if possible, even within a transaction.
7042 * The aim here is to keep replication moving and allow a
7045 ret
= dsdb_request_add_controls(search_req
, DSDB_SEARCH_SHOW_RECYCLED
7046 |DSDB_SEARCH_SHOW_EXTENDED_DN
);
7048 if (ret
!= LDB_SUCCESS
) {
7052 return ldb_next_request(ar
->module
, search_req
);
7056 * Returns true if we need to do extra processing to handle deleted object
7057 * changes received via replication
7059 static bool replmd_should_apply_isDeleted(struct replmd_replicated_request
*ar
,
7060 struct ldb_message
*msg
)
7062 struct ldb_dn
*deleted_objects_dn
;
7065 if (!ar
->isDeleted
) {
7067 /* not a deleted object, so don't set isDeleted */
7071 ret
= dsdb_get_deleted_objects_dn(ldb_module_get_ctx(ar
->module
),
7073 &deleted_objects_dn
);
7076 * if the Deleted Object container lookup failed, then just apply
7077 * isDeleted (note that it doesn't exist for the Schema partition)
7079 if (ret
!= LDB_SUCCESS
) {
7084 * the Deleted Objects container has isDeleted set but is not entirely
7085 * a deleted object, so DON'T re-apply isDeleted to it
7087 if (ldb_dn_compare(msg
->dn
, deleted_objects_dn
) == 0) {
7095 * This is essentially a wrapper for replmd_replicated_apply_next()
7097 * This is needed to ensure that both codepaths call this handler.
7099 static int replmd_replicated_apply_isDeleted(struct replmd_replicated_request
*ar
)
7101 struct ldb_message
*msg
= ar
->objs
->objects
[ar
->index_current
].msg
;
7103 bool apply_isDeleted
;
7104 struct ldb_request
*del_req
= NULL
;
7105 struct ldb_result
*res
= NULL
;
7106 TALLOC_CTX
*tmp_ctx
= NULL
;
7108 apply_isDeleted
= replmd_should_apply_isDeleted(ar
, msg
);
7110 if (!apply_isDeleted
) {
7113 ar
->index_current
++;
7114 return replmd_replicated_apply_next(ar
);
7118 * Do a delete here again, so that if there is
7119 * anything local that conflicts with this
7120 * object being deleted, it is removed. This
7121 * includes links. See MS-DRSR 4.1.10.6.9
7124 * If the object is already deleted, and there
7125 * is no more work required, it doesn't do
7129 /* This has been updated to point to the DN we eventually did the modify on */
7131 tmp_ctx
= talloc_new(ar
);
7133 ret
= ldb_oom(ldb_module_get_ctx(ar
->module
));
7137 res
= talloc_zero(tmp_ctx
, struct ldb_result
);
7139 ret
= ldb_oom(ldb_module_get_ctx(ar
->module
));
7140 talloc_free(tmp_ctx
);
7144 /* Build a delete request, which hopefully will artually turn into nothing */
7145 ret
= ldb_build_del_req(&del_req
, ldb_module_get_ctx(ar
->module
), tmp_ctx
,
7149 ldb_modify_default_callback
,
7151 LDB_REQ_SET_LOCATION(del_req
);
7152 if (ret
!= LDB_SUCCESS
) {
7153 talloc_free(tmp_ctx
);
7158 * This is the guts of the call, call back
7159 * into our delete code, but setting the
7160 * re_delete flag so we delete anything that
7161 * shouldn't be there on a deleted or recycled
7164 ret
= replmd_delete_internals(ar
->module
, del_req
, true);
7165 if (ret
== LDB_SUCCESS
) {
7166 ret
= ldb_wait(del_req
->handle
, LDB_WAIT_ALL
);
7169 talloc_free(tmp_ctx
);
7170 if (ret
!= LDB_SUCCESS
) {
7174 ar
->index_current
++;
7175 return replmd_replicated_apply_next(ar
);
7178 static int replmd_replicated_uptodate_modify_callback(struct ldb_request
*req
,
7179 struct ldb_reply
*ares
)
7181 struct ldb_context
*ldb
;
7182 struct replmd_replicated_request
*ar
= talloc_get_type(req
->context
,
7183 struct replmd_replicated_request
);
7184 ldb
= ldb_module_get_ctx(ar
->module
);
7187 return ldb_module_done(ar
->req
, NULL
, NULL
,
7188 LDB_ERR_OPERATIONS_ERROR
);
7190 if (ares
->error
!= LDB_SUCCESS
) {
7191 return ldb_module_done(ar
->req
, ares
->controls
,
7192 ares
->response
, ares
->error
);
7195 if (ares
->type
!= LDB_REPLY_DONE
) {
7196 ldb_asprintf_errstring(ldb
, "Invalid LDB reply type %d", ares
->type
);
7197 return ldb_module_done(ar
->req
, NULL
, NULL
,
7198 LDB_ERR_OPERATIONS_ERROR
);
7203 return ldb_module_done(ar
->req
, NULL
, NULL
, LDB_SUCCESS
);
7206 static int replmd_replicated_uptodate_modify(struct replmd_replicated_request
*ar
)
7208 struct ldb_context
*ldb
;
7209 struct ldb_request
*change_req
;
7210 enum ndr_err_code ndr_err
;
7211 struct ldb_message
*msg
;
7212 struct replUpToDateVectorBlob ouv
;
7213 const struct ldb_val
*ouv_value
;
7214 const struct drsuapi_DsReplicaCursor2CtrEx
*ruv
;
7215 struct replUpToDateVectorBlob nuv
;
7216 struct ldb_val nuv_value
;
7217 struct ldb_message_element
*nuv_el
= NULL
;
7218 struct ldb_message_element
*orf_el
= NULL
;
7219 struct repsFromToBlob nrf
;
7220 struct ldb_val
*nrf_value
= NULL
;
7221 struct ldb_message_element
*nrf_el
= NULL
;
7225 time_t t
= time(NULL
);
7228 uint32_t instanceType
;
7230 ldb
= ldb_module_get_ctx(ar
->module
);
7231 ruv
= ar
->objs
->uptodateness_vector
;
7237 unix_to_nt_time(&now
, t
);
7239 if (ar
->search_msg
== NULL
) {
7240 /* this happens for a REPL_OBJ call where we are
7241 creating the target object by replicating it. The
7242 subdomain join code does this for the partition DN
7244 DEBUG(4,(__location__
": Skipping UDV and repsFrom update as no target DN\n"));
7245 return ldb_module_done(ar
->req
, NULL
, NULL
, LDB_SUCCESS
);
7248 instanceType
= ldb_msg_find_attr_as_uint(ar
->search_msg
, "instanceType", 0);
7249 if (! (instanceType
& INSTANCE_TYPE_IS_NC_HEAD
)) {
7250 DEBUG(4,(__location__
": Skipping UDV and repsFrom update as not NC root: %s\n",
7251 ldb_dn_get_linearized(ar
->search_msg
->dn
)));
7252 return ldb_module_done(ar
->req
, NULL
, NULL
, LDB_SUCCESS
);
7256 * first create the new replUpToDateVector
7258 ouv_value
= ldb_msg_find_ldb_val(ar
->search_msg
, "replUpToDateVector");
7260 ndr_err
= ndr_pull_struct_blob(ouv_value
, ar
, &ouv
,
7261 (ndr_pull_flags_fn_t
)ndr_pull_replUpToDateVectorBlob
);
7262 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err
)) {
7263 NTSTATUS nt_status
= ndr_map_error2ntstatus(ndr_err
);
7264 return replmd_replicated_request_werror(ar
, ntstatus_to_werror(nt_status
));
7267 if (ouv
.version
!= 2) {
7268 return replmd_replicated_request_werror(ar
, WERR_DS_DRA_INTERNAL_ERROR
);
7273 * the new uptodateness vector will at least
7274 * contain 1 entry, one for the source_dsa
7276 * plus optional values from our old vector and the one from the source_dsa
7278 nuv
.ctr
.ctr2
.count
= ouv
.ctr
.ctr2
.count
;
7279 if (ruv
) nuv
.ctr
.ctr2
.count
+= ruv
->count
;
7280 nuv
.ctr
.ctr2
.cursors
= talloc_array(ar
,
7281 struct drsuapi_DsReplicaCursor2
,
7282 nuv
.ctr
.ctr2
.count
);
7283 if (!nuv
.ctr
.ctr2
.cursors
) return replmd_replicated_request_werror(ar
, WERR_NOT_ENOUGH_MEMORY
);
7285 /* first copy the old vector */
7286 for (i
=0; i
< ouv
.ctr
.ctr2
.count
; i
++) {
7287 nuv
.ctr
.ctr2
.cursors
[ni
] = ouv
.ctr
.ctr2
.cursors
[i
];
7291 /* merge in the source_dsa vector is available */
7292 for (i
=0; (ruv
&& i
< ruv
->count
); i
++) {
7295 if (GUID_equal(&ruv
->cursors
[i
].source_dsa_invocation_id
,
7296 &ar
->our_invocation_id
)) {
7300 for (j
=0; j
< ni
; j
++) {
7301 if (!GUID_equal(&ruv
->cursors
[i
].source_dsa_invocation_id
,
7302 &nuv
.ctr
.ctr2
.cursors
[j
].source_dsa_invocation_id
)) {
7308 if (ruv
->cursors
[i
].highest_usn
> nuv
.ctr
.ctr2
.cursors
[j
].highest_usn
) {
7309 nuv
.ctr
.ctr2
.cursors
[j
] = ruv
->cursors
[i
];
7314 if (found
) continue;
7316 /* if it's not there yet, add it */
7317 nuv
.ctr
.ctr2
.cursors
[ni
] = ruv
->cursors
[i
];
7322 * finally correct the size of the cursors array
7324 nuv
.ctr
.ctr2
.count
= ni
;
7329 TYPESAFE_QSORT(nuv
.ctr
.ctr2
.cursors
, nuv
.ctr
.ctr2
.count
, drsuapi_DsReplicaCursor2_compare
);
7332 * create the change ldb_message
7334 msg
= ldb_msg_new(ar
);
7335 if (!msg
) return replmd_replicated_request_werror(ar
, WERR_NOT_ENOUGH_MEMORY
);
7336 msg
->dn
= ar
->search_msg
->dn
;
7338 ndr_err
= ndr_push_struct_blob(&nuv_value
, msg
, &nuv
,
7339 (ndr_push_flags_fn_t
)ndr_push_replUpToDateVectorBlob
);
7340 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err
)) {
7341 NTSTATUS nt_status
= ndr_map_error2ntstatus(ndr_err
);
7342 return replmd_replicated_request_werror(ar
, ntstatus_to_werror(nt_status
));
7344 ret
= ldb_msg_add_value(msg
, "replUpToDateVector", &nuv_value
, &nuv_el
);
7345 if (ret
!= LDB_SUCCESS
) {
7346 return replmd_replicated_request_error(ar
, ret
);
7348 nuv_el
->flags
= LDB_FLAG_MOD_REPLACE
;
7351 * now create the new repsFrom value from the given repsFromTo1 structure
7355 nrf
.ctr
.ctr1
= *ar
->objs
->source_dsa
;
7356 nrf
.ctr
.ctr1
.last_attempt
= now
;
7357 nrf
.ctr
.ctr1
.last_success
= now
;
7358 nrf
.ctr
.ctr1
.result_last_attempt
= WERR_OK
;
7361 * first see if we already have a repsFrom value for the current source dsa
7362 * if so we'll later replace this value
7364 orf_el
= ldb_msg_find_element(ar
->search_msg
, "repsFrom");
7366 for (i
=0; i
< orf_el
->num_values
; i
++) {
7367 struct repsFromToBlob
*trf
;
7369 trf
= talloc(ar
, struct repsFromToBlob
);
7370 if (!trf
) return replmd_replicated_request_werror(ar
, WERR_NOT_ENOUGH_MEMORY
);
7372 ndr_err
= ndr_pull_struct_blob(&orf_el
->values
[i
], trf
, trf
,
7373 (ndr_pull_flags_fn_t
)ndr_pull_repsFromToBlob
);
7374 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err
)) {
7375 NTSTATUS nt_status
= ndr_map_error2ntstatus(ndr_err
);
7376 return replmd_replicated_request_werror(ar
, ntstatus_to_werror(nt_status
));
7379 if (trf
->version
!= 1) {
7380 return replmd_replicated_request_werror(ar
, WERR_DS_DRA_INTERNAL_ERROR
);
7384 * we compare the source dsa objectGUID not the invocation_id
7385 * because we want only one repsFrom value per source dsa
7386 * and when the invocation_id of the source dsa has changed we don't need
7387 * the old repsFrom with the old invocation_id
7389 if (!GUID_equal(&trf
->ctr
.ctr1
.source_dsa_obj_guid
,
7390 &ar
->objs
->source_dsa
->source_dsa_obj_guid
)) {
7396 nrf_value
= &orf_el
->values
[i
];
7401 * copy over all old values to the new ldb_message
7403 ret
= ldb_msg_add_empty(msg
, "repsFrom", 0, &nrf_el
);
7404 if (ret
!= LDB_SUCCESS
) return replmd_replicated_request_error(ar
, ret
);
7409 * if we haven't found an old repsFrom value for the current source dsa
7410 * we'll add a new value
7413 struct ldb_val zero_value
;
7414 ZERO_STRUCT(zero_value
);
7415 ret
= ldb_msg_add_value(msg
, "repsFrom", &zero_value
, &nrf_el
);
7416 if (ret
!= LDB_SUCCESS
) return replmd_replicated_request_error(ar
, ret
);
7418 nrf_value
= &nrf_el
->values
[nrf_el
->num_values
- 1];
7421 /* we now fill the value which is already attached to ldb_message */
7422 ndr_err
= ndr_push_struct_blob(nrf_value
, msg
,
7424 (ndr_push_flags_fn_t
)ndr_push_repsFromToBlob
);
7425 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err
)) {
7426 NTSTATUS nt_status
= ndr_map_error2ntstatus(ndr_err
);
7427 return replmd_replicated_request_werror(ar
, ntstatus_to_werror(nt_status
));
7431 * the ldb_message_element for the attribute, has all the old values and the new one
7432 * so we'll replace the whole attribute with all values
7434 nrf_el
->flags
= LDB_FLAG_MOD_REPLACE
;
7436 if (CHECK_DEBUGLVL(4)) {
7437 char *s
= ldb_ldif_message_redacted_string(ldb
, ar
,
7438 LDB_CHANGETYPE_MODIFY
,
7440 DEBUG(4, ("DRS replication up-to-date modify message:\n%s\n", s
));
7444 /* prepare the ldb_modify() request */
7445 ret
= ldb_build_mod_req(&change_req
,
7451 replmd_replicated_uptodate_modify_callback
,
7453 LDB_REQ_SET_LOCATION(change_req
);
7454 if (ret
!= LDB_SUCCESS
) return replmd_replicated_request_error(ar
, ret
);
7456 return ldb_next_request(ar
->module
, change_req
);
7459 static int replmd_replicated_uptodate_search_callback(struct ldb_request
*req
,
7460 struct ldb_reply
*ares
)
7462 struct replmd_replicated_request
*ar
= talloc_get_type(req
->context
,
7463 struct replmd_replicated_request
);
7467 return ldb_module_done(ar
->req
, NULL
, NULL
,
7468 LDB_ERR_OPERATIONS_ERROR
);
7470 if (ares
->error
!= LDB_SUCCESS
&&
7471 ares
->error
!= LDB_ERR_NO_SUCH_OBJECT
) {
7472 return ldb_module_done(ar
->req
, ares
->controls
,
7473 ares
->response
, ares
->error
);
7476 switch (ares
->type
) {
7477 case LDB_REPLY_ENTRY
:
7478 ar
->search_msg
= talloc_steal(ar
, ares
->message
);
7481 case LDB_REPLY_REFERRAL
:
7482 /* we ignore referrals */
7485 case LDB_REPLY_DONE
:
7486 ret
= replmd_replicated_uptodate_modify(ar
);
7487 if (ret
!= LDB_SUCCESS
) {
7488 return ldb_module_done(ar
->req
, NULL
, NULL
, ret
);
7497 static int replmd_replicated_uptodate_vector(struct replmd_replicated_request
*ar
)
7499 struct ldb_context
*ldb
= ldb_module_get_ctx(ar
->module
);
7500 struct replmd_private
*replmd_private
=
7501 talloc_get_type_abort(ldb_module_get_private(ar
->module
),
7502 struct replmd_private
);
7504 static const char *attrs
[] = {
7505 "replUpToDateVector",
7510 struct ldb_request
*search_req
;
7512 ar
->search_msg
= NULL
;
7515 * Let the caller know that we did an originating updates
7517 ar
->objs
->originating_updates
= replmd_private
->originating_updates
;
7519 ret
= ldb_build_search_req(&search_req
,
7522 ar
->objs
->partition_dn
,
7528 replmd_replicated_uptodate_search_callback
,
7530 LDB_REQ_SET_LOCATION(search_req
);
7531 if (ret
!= LDB_SUCCESS
) return replmd_replicated_request_error(ar
, ret
);
7533 return ldb_next_request(ar
->module
, search_req
);
7538 static int replmd_extended_replicated_objects(struct ldb_module
*module
, struct ldb_request
*req
)
7540 struct ldb_context
*ldb
;
7541 struct dsdb_extended_replicated_objects
*objs
;
7542 struct replmd_replicated_request
*ar
;
7543 struct ldb_control
**ctrls
;
7546 ldb
= ldb_module_get_ctx(module
);
7548 ldb_debug(ldb
, LDB_DEBUG_TRACE
, "replmd_extended_replicated_objects\n");
7550 objs
= talloc_get_type(req
->op
.extended
.data
, struct dsdb_extended_replicated_objects
);
7552 ldb_debug(ldb
, LDB_DEBUG_FATAL
, "replmd_extended_replicated_objects: invalid extended data\n");
7553 return LDB_ERR_PROTOCOL_ERROR
;
7556 if (objs
->version
!= DSDB_EXTENDED_REPLICATED_OBJECTS_VERSION
) {
7557 ldb_debug(ldb
, LDB_DEBUG_FATAL
, "replmd_extended_replicated_objects: extended data invalid version [%u != %u]\n",
7558 objs
->version
, DSDB_EXTENDED_REPLICATED_OBJECTS_VERSION
);
7559 return LDB_ERR_PROTOCOL_ERROR
;
7562 ar
= replmd_ctx_init(module
, req
);
7564 return LDB_ERR_OPERATIONS_ERROR
;
7566 /* Set the flags to have the replmd_op_callback run over the full set of objects */
7567 ar
->apply_mode
= true;
7569 ar
->schema
= dsdb_get_schema(ldb
, ar
);
7571 ldb_debug_set(ldb
, LDB_DEBUG_FATAL
, "replmd_ctx_init: no loaded schema found\n");
7573 DEBUG(0,(__location__
": %s\n", ldb_errstring(ldb
)));
7574 return LDB_ERR_CONSTRAINT_VIOLATION
;
7577 ctrls
= req
->controls
;
7579 if (req
->controls
) {
7580 req
->controls
= talloc_memdup(ar
, req
->controls
,
7581 talloc_get_size(req
->controls
));
7582 if (!req
->controls
) return replmd_replicated_request_werror(ar
, WERR_NOT_ENOUGH_MEMORY
);
7585 ret
= ldb_request_add_control(req
, DSDB_CONTROL_REPLICATED_UPDATE_OID
, false, NULL
);
7586 if (ret
!= LDB_SUCCESS
) {
7590 /* If this change contained linked attributes in the body
7591 * (rather than in the links section) we need to update
7592 * backlinks in linked_attributes */
7593 ret
= ldb_request_add_control(req
, DSDB_CONTROL_APPLY_LINKS
, false, NULL
);
7594 if (ret
!= LDB_SUCCESS
) {
7598 ar
->controls
= req
->controls
;
7599 req
->controls
= ctrls
;
7601 return replmd_replicated_apply_next(ar
);
7605 * Checks how to handle an missing target - either we need to fail the
7606 * replication and retry with GET_TGT, ignore the link and continue, or try to
7607 * add a partial link to an unknown target.
7609 static int replmd_allow_missing_target(struct ldb_module
*module
,
7610 TALLOC_CTX
*mem_ctx
,
7611 struct ldb_dn
*target_dn
,
7612 struct ldb_dn
*source_dn
,
7615 uint32_t dsdb_repl_flags
,
7617 const char * missing_str
)
7619 struct ldb_context
*ldb
= ldb_module_get_ctx(module
);
7623 * we may not be able to resolve link targets properly when
7624 * dealing with subsets of objects, e.g. the source is a
7625 * critical object and the target isn't
7628 * When we implement Trusted Domains we need to consider
7629 * whether they get treated as an incomplete replica here or not
7631 if (dsdb_repl_flags
& DSDB_REPL_FLAG_OBJECT_SUBSET
) {
7634 * Ignore the link. We don't increase the highwater-mark in
7635 * the object subset cases, so subsequent replications should
7636 * resolve any missing links
7638 DEBUG(2, ("%s target %s linked from %s\n", missing_str
,
7639 ldb_dn_get_linearized(target_dn
),
7640 ldb_dn_get_linearized(source_dn
)));
7641 *ignore_link
= true;
7645 is_in_same_nc
= dsdb_objects_have_same_nc(ldb
,
7649 if (is_in_same_nc
) {
7651 * We allow the join.py code to point out that all
7652 * replication is completed, so failing now would just
7653 * trigger errors, rather than trigger a GET_TGT
7655 unsigned long long *finished_full_join_ptr
=
7656 talloc_get_type(ldb_get_opaque(ldb
,
7657 DSDB_FULL_JOIN_REPLICATION_COMPLETED_OPAQUE_NAME
),
7658 unsigned long long);
7659 bool finished_full_join
= finished_full_join_ptr
&& *finished_full_join_ptr
;
7662 * if the target is already be up-to-date there's no point in
7663 * retrying. This could be due to bad timing, or if a target
7664 * on a one-way link was deleted. We ignore the link rather
7665 * than failing the replication cycle completely
7667 if (finished_full_join
7668 || dsdb_repl_flags
& DSDB_REPL_FLAG_TARGETS_UPTODATE
) {
7669 *ignore_link
= true;
7670 DBG_WARNING("%s is %s "
7671 "but up to date. Ignoring link from %s\n",
7672 ldb_dn_get_linearized(target_dn
), missing_str
,
7673 ldb_dn_get_linearized(source_dn
));
7677 /* otherwise fail the replication and retry with GET_TGT */
7678 ldb_asprintf_errstring(ldb
, "%s target %s GUID %s linked from %s\n",
7680 ldb_dn_get_linearized(target_dn
),
7681 GUID_string(mem_ctx
, guid
),
7682 ldb_dn_get_linearized(source_dn
));
7683 return LDB_ERR_NO_SUCH_OBJECT
;
7687 * The target of the cross-partition link is missing. Continue
7688 * and try to at least add the forward-link. This isn't great,
7689 * but a partial link can be fixed by dbcheck, so it's better
7690 * than dropping the link completely.
7692 *ignore_link
= false;
7694 if (is_obj_commit
) {
7697 * Only log this when we're actually committing the objects.
7698 * This avoids spurious logs, i.e. if we're just verifying the
7699 * received link during a join.
7701 DBG_WARNING("%s cross-partition target %s linked from %s\n",
7702 missing_str
, ldb_dn_get_linearized(target_dn
),
7703 ldb_dn_get_linearized(source_dn
));
7710 * Checks that the target object for a linked attribute exists.
7711 * @param guid returns the target object's GUID (is returned)if it exists)
7712 * @param ignore_link set to true if the linked attribute should be ignored
7713 * (i.e. the target doesn't exist, but that it's OK to skip the link)
7715 static int replmd_check_target_exists(struct ldb_module
*module
,
7716 struct dsdb_dn
*dsdb_dn
,
7717 struct la_entry
*la_entry
,
7718 struct ldb_dn
*source_dn
,
7723 struct drsuapi_DsReplicaLinkedAttribute
*la
= la_entry
->la
;
7724 struct ldb_context
*ldb
= ldb_module_get_ctx(module
);
7725 struct ldb_result
*target_res
;
7726 TALLOC_CTX
*tmp_ctx
= talloc_new(la_entry
);
7727 const char *attrs
[] = { "isDeleted", "isRecycled", NULL
};
7730 enum deletion_state target_deletion_state
= OBJECT_REMOVED
;
7731 bool active
= (la
->flags
& DRSUAPI_DS_LINKED_ATTRIBUTE_FLAG_ACTIVE
) ? true : false;
7733 *ignore_link
= false;
7734 ntstatus
= dsdb_get_extended_dn_guid(dsdb_dn
->dn
, guid
, "GUID");
7736 if (!NT_STATUS_IS_OK(ntstatus
) && !active
) {
7739 * This strange behaviour (allowing a NULL/missing
7740 * GUID) originally comes from:
7742 * commit e3054ce0fe0f8f62d2f5b2a77893e7a1479128bd
7743 * Author: Andrew Tridgell <tridge@samba.org>
7744 * Date: Mon Dec 21 21:21:55 2009 +1100
7746 * s4-drs: cope better with NULL GUIDS from DRS
7748 * It is valid to get a NULL GUID over DRS for a deleted forward link. We
7749 * need to match by DN if possible when seeing if we should update an
7752 * Pair-Programmed-With: Andrew Bartlett <abartlet@samba.org>
7754 ret
= dsdb_module_search_dn(module
, tmp_ctx
, &target_res
,
7756 DSDB_FLAG_NEXT_MODULE
|
7757 DSDB_SEARCH_SHOW_RECYCLED
|
7758 DSDB_SEARCH_SEARCH_ALL_PARTITIONS
|
7759 DSDB_SEARCH_SHOW_DN_IN_STORAGE_FORMAT
,
7761 } else if (!NT_STATUS_IS_OK(ntstatus
)) {
7762 ldb_asprintf_errstring(ldb
, "Failed to find GUID in linked attribute 0x%x blob for %s from %s",
7764 ldb_dn_get_linearized(dsdb_dn
->dn
),
7765 ldb_dn_get_linearized(source_dn
));
7766 talloc_free(tmp_ctx
);
7767 return LDB_ERR_OPERATIONS_ERROR
;
7769 ret
= dsdb_module_search(module
, tmp_ctx
, &target_res
,
7770 NULL
, LDB_SCOPE_SUBTREE
,
7772 DSDB_FLAG_NEXT_MODULE
|
7773 DSDB_SEARCH_SHOW_RECYCLED
|
7774 DSDB_SEARCH_SEARCH_ALL_PARTITIONS
|
7775 DSDB_SEARCH_SHOW_DN_IN_STORAGE_FORMAT
,
7778 GUID_string(tmp_ctx
, guid
));
7781 if (ret
!= LDB_SUCCESS
) {
7782 ldb_asprintf_errstring(ldb
, "Failed to re-resolve GUID %s: %s\n",
7783 GUID_string(tmp_ctx
, guid
),
7784 ldb_errstring(ldb
));
7785 talloc_free(tmp_ctx
);
7789 if (target_res
->count
== 0) {
7792 * target object is unknown. Check whether to ignore the link,
7793 * fail the replication, or add a partial link
7795 ret
= replmd_allow_missing_target(module
, tmp_ctx
, dsdb_dn
->dn
,
7796 source_dn
, is_obj_commit
, guid
,
7797 la_entry
->dsdb_repl_flags
,
7798 ignore_link
, "Unknown");
7800 } else if (target_res
->count
!= 1) {
7801 ldb_asprintf_errstring(ldb
, "More than one object found matching objectGUID %s\n",
7802 GUID_string(tmp_ctx
, guid
));
7803 ret
= LDB_ERR_OPERATIONS_ERROR
;
7805 struct ldb_message
*target_msg
= target_res
->msgs
[0];
7807 dsdb_dn
->dn
= talloc_steal(dsdb_dn
, target_msg
->dn
);
7809 /* Get the object's state (i.e. Not Deleted, Tombstone, etc) */
7810 replmd_deletion_state(module
, target_msg
,
7811 &target_deletion_state
, NULL
);
7814 * Check for deleted objects as per MS-DRSR 4.1.10.6.14
7815 * ProcessLinkValue(). Link updates should not be sent for
7816 * recycled and tombstone objects (deleting the links should
7817 * happen when we delete the object). This probably means our
7818 * copy of the target object isn't up to date.
7820 if (target_deletion_state
>= OBJECT_RECYCLED
) {
7823 * target object is deleted. Check whether to ignore the
7824 * link, fail the replication, or add a partial link
7826 ret
= replmd_allow_missing_target(module
, tmp_ctx
,
7827 dsdb_dn
->dn
, source_dn
,
7828 is_obj_commit
, guid
,
7829 la_entry
->dsdb_repl_flags
,
7830 ignore_link
, "Deleted");
7834 talloc_free(tmp_ctx
);
7839 * Extracts the key details about the source object for a
7840 * linked-attribute entry.
7841 * This returns the following details:
7842 * @param ret_attr the schema details for the linked attribute
7843 * @param source_msg the search result for the source object
7845 static int replmd_get_la_entry_source(struct ldb_module
*module
,
7846 struct la_entry
*la_entry
,
7847 TALLOC_CTX
*mem_ctx
,
7848 const struct dsdb_attribute
**ret_attr
,
7849 struct ldb_message
**source_msg
)
7851 struct drsuapi_DsReplicaLinkedAttribute
*la
= la_entry
->la
;
7852 struct ldb_context
*ldb
= ldb_module_get_ctx(module
);
7853 const struct dsdb_schema
*schema
= dsdb_get_schema(ldb
, mem_ctx
);
7855 const struct dsdb_attribute
*attr
;
7856 struct ldb_result
*res
;
7857 const char *attrs
[4];
7860 linked_attributes[0]:
7861 &objs->linked_attributes[i]: struct drsuapi_DsReplicaLinkedAttribute
7863 identifier: struct drsuapi_DsReplicaObjectIdentifier
7864 __ndr_size : 0x0000003a (58)
7865 __ndr_size_sid : 0x00000000 (0)
7866 guid : 8e95b6a9-13dd-4158-89db-3220a5be5cc7
7868 __ndr_size_dn : 0x00000000 (0)
7870 attid : DRSUAPI_ATTID_member (0x1F)
7871 value: struct drsuapi_DsAttributeValue
7872 __ndr_size : 0x0000007e (126)
7874 blob : DATA_BLOB length=126
7875 flags : 0x00000001 (1)
7876 1: DRSUAPI_DS_LINKED_ATTRIBUTE_FLAG_ACTIVE
7877 originating_add_time : Wed Sep 2 22:20:01 2009 EST
7878 meta_data: struct drsuapi_DsReplicaMetaData
7879 version : 0x00000015 (21)
7880 originating_change_time : Wed Sep 2 23:39:07 2009 EST
7881 originating_invocation_id: 794640f3-18cf-40ee-a211-a93992b67a64
7882 originating_usn : 0x000000000001e19c (123292)
7884 (for cases where the link is to a normal DN)
7885 &target: struct drsuapi_DsReplicaObjectIdentifier3
7886 __ndr_size : 0x0000007e (126)
7887 __ndr_size_sid : 0x0000001c (28)
7888 guid : 7639e594-db75-4086-b0d4-67890ae46031
7889 sid : S-1-5-21-2848215498-2472035911-1947525656-19924
7890 __ndr_size_dn : 0x00000022 (34)
7891 dn : 'CN=UOne,OU=TestOU,DC=vsofs8,DC=com'
7894 /* find the attribute being modified */
7895 attr
= dsdb_attribute_by_attributeID_id(schema
, la
->attid
);
7897 struct GUID_txt_buf guid_str
;
7898 ldb_asprintf_errstring(ldb
, "Unable to find attributeID 0x%x for link on <GUID=%s>",
7900 GUID_buf_string(&la
->identifier
->guid
,
7902 return LDB_ERR_OPERATIONS_ERROR
;
7906 * All attributes listed here must be dealt with in some way
7907 * by replmd_process_linked_attribute() otherwise in the case
7908 * of isDeleted: FALSE the modify will fail with:
7910 * Failed to apply linked attribute change 'attribute 'isDeleted':
7911 * invalid modify flags on
7912 * 'CN=g1_1527570609273,CN=Users,DC=samba,DC=example,DC=com':
7915 * This is because isDeleted is a Boolean, so FALSE is a
7916 * legitimate value (set by Samba's deletetest.py)
7918 attrs
[0] = attr
->lDAPDisplayName
;
7919 attrs
[1] = "isDeleted";
7920 attrs
[2] = "isRecycled";
7924 * get the existing message from the db for the object with
7925 * this GUID, returning attribute being modified. We will then
7926 * use this msg as the basis for a modify call
7928 ret
= dsdb_module_search(module
, mem_ctx
, &res
, NULL
, LDB_SCOPE_SUBTREE
, attrs
,
7929 DSDB_FLAG_NEXT_MODULE
|
7930 DSDB_SEARCH_SEARCH_ALL_PARTITIONS
|
7931 DSDB_SEARCH_SHOW_RECYCLED
|
7932 DSDB_SEARCH_SHOW_DN_IN_STORAGE_FORMAT
|
7933 DSDB_SEARCH_REVEAL_INTERNALS
,
7935 "objectGUID=%s", GUID_string(mem_ctx
, &la
->identifier
->guid
));
7936 if (ret
!= LDB_SUCCESS
) {
7939 if (res
->count
!= 1) {
7940 ldb_asprintf_errstring(ldb
, "DRS linked attribute for GUID %s - DN not found",
7941 GUID_string(mem_ctx
, &la
->identifier
->guid
));
7942 return LDB_ERR_NO_SUCH_OBJECT
;
7945 *source_msg
= res
->msgs
[0];
7952 * Verifies the target object is known for a linked attribute
7954 static int replmd_verify_link_target(struct replmd_replicated_request
*ar
,
7955 TALLOC_CTX
*mem_ctx
,
7956 struct la_entry
*la_entry
,
7957 struct ldb_dn
*src_dn
,
7958 const struct dsdb_attribute
*attr
)
7960 int ret
= LDB_SUCCESS
;
7961 struct ldb_module
*module
= ar
->module
;
7962 struct dsdb_dn
*tgt_dsdb_dn
= NULL
;
7963 struct GUID guid
= GUID_zero();
7966 struct ldb_context
*ldb
= ldb_module_get_ctx(module
);
7967 struct drsuapi_DsReplicaLinkedAttribute
*la
= la_entry
->la
;
7968 const struct dsdb_schema
*schema
= dsdb_get_schema(ldb
, mem_ctx
);
7970 /* the value blob for the attribute holds the target object DN */
7971 status
= dsdb_dn_la_from_blob(ldb
, attr
, schema
, mem_ctx
,
7972 la
->value
.blob
, &tgt_dsdb_dn
);
7973 if (!W_ERROR_IS_OK(status
)) {
7974 ldb_asprintf_errstring(ldb
, "Failed to parsed linked attribute blob for %s on %s - %s\n",
7975 attr
->lDAPDisplayName
,
7976 ldb_dn_get_linearized(src_dn
),
7977 win_errstr(status
));
7978 return LDB_ERR_OPERATIONS_ERROR
;
7982 * We can skip the target object checks if we're only syncing critical
7983 * objects, or we know the target is up-to-date. If either case, we
7984 * still continue even if the target doesn't exist
7986 if ((la_entry
->dsdb_repl_flags
& (DSDB_REPL_FLAG_OBJECT_SUBSET
|
7987 DSDB_REPL_FLAG_TARGETS_UPTODATE
)) == 0) {
7989 ret
= replmd_check_target_exists(module
, tgt_dsdb_dn
, la_entry
,
7990 src_dn
, false, &guid
, &dummy
);
7994 * When we fail to find the target object, the error code we pass
7995 * back here is really important. It flags back to the callers to
7996 * retry this request with DRSUAPI_DRS_GET_TGT
7998 if (ret
== LDB_ERR_NO_SUCH_OBJECT
) {
7999 ret
= replmd_replicated_request_werror(ar
, WERR_DS_DRA_RECYCLED_TARGET
);
8006 * Finds the current active Parsed-DN value for a single-valued linked
8007 * attribute, if one exists.
8008 * @param ret_pdn assigned the active Parsed-DN, or NULL if none was found
8009 * @returns LDB_SUCCESS (regardless of whether a match was found), unless
8012 static int replmd_get_active_singleval_link(struct ldb_module
*module
,
8013 TALLOC_CTX
*mem_ctx
,
8014 struct parsed_dn pdn_list
[],
8016 const struct dsdb_attribute
*attr
,
8017 struct parsed_dn
**ret_pdn
)
8023 if (!(attr
->ldb_schema_attribute
->flags
& LDB_ATTR_FLAG_SINGLE_VALUE
)) {
8025 /* nothing to do for multi-valued linked attributes */
8029 for (i
= 0; i
< count
; i
++) {
8030 int ret
= LDB_SUCCESS
;
8031 struct parsed_dn
*pdn
= &pdn_list
[i
];
8033 /* skip any inactive links */
8034 if (dsdb_dn_is_deleted_val(pdn
->v
)) {
8038 /* we've found an active value for this attribute */
8041 if (pdn
->dsdb_dn
== NULL
) {
8042 struct ldb_context
*ldb
= ldb_module_get_ctx(module
);
8044 ret
= really_parse_trusted_dn(mem_ctx
, ldb
, pdn
,
8045 attr
->syntax
->ldap_oid
);
8051 /* no active link found */
8056 * @returns true if the replication linked attribute info is newer than we
8057 * already have in our DB
8058 * @param pdn the existing linked attribute info in our DB
8059 * @param la the new linked attribute info received during replication
8061 static bool replmd_link_update_is_newer(struct parsed_dn
*pdn
,
8062 struct drsuapi_DsReplicaLinkedAttribute
*la
)
8064 /* see if this update is newer than what we have already */
8065 struct GUID invocation_id
= GUID_zero();
8066 uint32_t version
= 0;
8067 NTTIME change_time
= 0;
8071 /* no existing info so update is newer */
8075 dsdb_get_extended_dn_guid(pdn
->dsdb_dn
->dn
, &invocation_id
, "RMD_INVOCID");
8076 dsdb_get_extended_dn_uint32(pdn
->dsdb_dn
->dn
, &version
, "RMD_VERSION");
8077 dsdb_get_extended_dn_nttime(pdn
->dsdb_dn
->dn
, &change_time
, "RMD_CHANGETIME");
8079 return replmd_update_is_newer(&invocation_id
,
8080 &la
->meta_data
.originating_invocation_id
,
8082 la
->meta_data
.version
,
8084 la
->meta_data
.originating_change_time
);
8088 * Marks an existing linked attribute value as deleted in the DB
8089 * @param pdn the parsed-DN of the target-value to delete
8091 static int replmd_delete_link_value(struct ldb_module
*module
,
8092 struct replmd_private
*replmd_private
,
8093 TALLOC_CTX
*mem_ctx
,
8094 struct ldb_dn
*src_obj_dn
,
8095 const struct dsdb_schema
*schema
,
8096 const struct dsdb_attribute
*attr
,
8099 struct GUID
*target_guid
,
8100 struct dsdb_dn
*target_dsdb_dn
,
8101 struct ldb_val
*output_val
)
8103 struct ldb_context
*ldb
= ldb_module_get_ctx(module
);
8106 const struct GUID
*invocation_id
= NULL
;
8110 unix_to_nt_time(&now
, t
);
8112 invocation_id
= samdb_ntds_invocation_id(ldb
);
8113 if (invocation_id
== NULL
) {
8114 return LDB_ERR_OPERATIONS_ERROR
;
8117 /* if the existing link is active, remove its backlink */
8121 * NOTE WELL: After this we will never (at runtime) be
8122 * able to find this forward link (for instant
8123 * removal) if/when the link target is deleted.
8125 * We have dbcheck rules to cover this and cope otherwise
8126 * by filtering at runtime (i.e. in the extended_dn module).
8128 ret
= replmd_add_backlink(module
, replmd_private
, schema
,
8129 src_obj_dn
, target_guid
, false,
8131 if (ret
!= LDB_SUCCESS
) {
8136 /* mark the existing value as deleted */
8137 ret
= replmd_update_la_val(mem_ctx
, output_val
, target_dsdb_dn
,
8138 target_dsdb_dn
, invocation_id
, seq_num
,
8139 seq_num
, now
, true);
8144 * Checks for a conflict in single-valued link attributes, and tries to
8145 * resolve the problem if possible.
8147 * Single-valued links should only ever have one active value. If we already
8148 * have an active link value, and during replication we receive an active link
8149 * value for a different target DN, then we need to resolve this inconsistency
8150 * and determine which value should be active. If the received info is better/
8151 * newer than the existing link attribute, then we need to set our existing
8152 * link as deleted. If the received info is worse/older, then we should continue
8153 * to add it, but set it as an inactive link.
8155 * Note that this is a corner-case that is unlikely to happen (but if it does
8156 * happen, we don't want it to break replication completely).
8158 * @param pdn_being_modified the parsed DN corresponding to the received link
8159 * target (note this is NULL if the link does not already exist in our DB)
8160 * @param pdn_list all the source object's Parsed-DNs for this attribute, i.e.
8161 * any existing active or inactive values for the attribute in our DB.
8162 * @param dsdb_dn the target DN for the received link attribute
8163 * @param add_as_inactive gets set to true if the received link is worse than
8164 * the existing link - it should still be added, but as an inactive link.
8166 static int replmd_check_singleval_la_conflict(struct ldb_module
*module
,
8167 struct replmd_private
*replmd_private
,
8168 TALLOC_CTX
*mem_ctx
,
8169 struct ldb_dn
*src_obj_dn
,
8170 struct drsuapi_DsReplicaLinkedAttribute
*la
,
8171 struct dsdb_dn
*dsdb_dn
,
8172 struct parsed_dn
*pdn_being_modified
,
8173 struct parsed_dn
*pdn_list
,
8174 struct ldb_message_element
*old_el
,
8175 const struct dsdb_schema
*schema
,
8176 const struct dsdb_attribute
*attr
,
8178 bool *add_as_inactive
)
8180 struct parsed_dn
*active_pdn
= NULL
;
8181 bool update_is_newer
= false;
8185 * check if there's a conflict for single-valued links, i.e. an active
8186 * linked attribute already exists, but it has a different target value
8188 ret
= replmd_get_active_singleval_link(module
, mem_ctx
, pdn_list
,
8189 old_el
->num_values
, attr
,
8192 if (ret
!= LDB_SUCCESS
) {
8197 * If no active value exists (or the received info is for the currently
8198 * active value), then no conflict exists
8200 if (active_pdn
== NULL
|| active_pdn
== pdn_being_modified
) {
8204 DBG_WARNING("Link conflict for %s attribute on %s\n",
8205 attr
->lDAPDisplayName
, ldb_dn_get_linearized(src_obj_dn
));
8207 /* Work out how to resolve the conflict based on which info is better */
8208 update_is_newer
= replmd_link_update_is_newer(active_pdn
, la
);
8210 if (update_is_newer
) {
8211 DBG_WARNING("Using received value %s, over existing target %s\n",
8212 ldb_dn_get_linearized(dsdb_dn
->dn
),
8213 ldb_dn_get_linearized(active_pdn
->dsdb_dn
->dn
));
8216 * Delete our existing active link. The received info will then
8217 * be added (through normal link processing) as the active value
8219 ret
= replmd_delete_link_value(module
, replmd_private
, old_el
,
8220 src_obj_dn
, schema
, attr
,
8221 seq_num
, true, &active_pdn
->guid
,
8222 active_pdn
->dsdb_dn
,
8225 if (ret
!= LDB_SUCCESS
) {
8229 DBG_WARNING("Using existing target %s, over received value %s\n",
8230 ldb_dn_get_linearized(active_pdn
->dsdb_dn
->dn
),
8231 ldb_dn_get_linearized(dsdb_dn
->dn
));
8234 * we want to keep our existing active link and add the
8235 * received link as inactive
8237 *add_as_inactive
= true;
8244 * Processes one linked attribute received via replication.
8245 * @param src_dn the DN of the source object for the link
8246 * @param attr schema info for the linked attribute
8247 * @param la_entry the linked attribute info received via DRS
8248 * @param element_ctx mem context for msg->element[] (when adding a new value
8249 * we need to realloc old_el->values)
8250 * @param old_el the corresponding msg->element[] for the linked attribute
8251 * @param pdn_list a (binary-searchable) parsed DN array for the existing link
8252 * values in the msg. E.g. for a group, this is the existing members.
8253 * @param change what got modified: either nothing, an existing link value was
8254 * modified, or a new link value was added.
8255 * @returns LDB_SUCCESS if OK, an error otherwise
8257 static int replmd_process_linked_attribute(struct ldb_module
*module
,
8258 TALLOC_CTX
*mem_ctx
,
8259 struct replmd_private
*replmd_private
,
8260 struct ldb_dn
*src_dn
,
8261 const struct dsdb_attribute
*attr
,
8262 struct la_entry
*la_entry
,
8263 struct ldb_request
*parent
,
8264 TALLOC_CTX
*element_ctx
,
8265 struct ldb_message_element
*old_el
,
8266 struct parsed_dn
*pdn_list
,
8267 replmd_link_changed
*change
)
8269 struct drsuapi_DsReplicaLinkedAttribute
*la
= la_entry
->la
;
8270 struct ldb_context
*ldb
= ldb_module_get_ctx(module
);
8271 const struct dsdb_schema
*schema
= dsdb_get_schema(ldb
, mem_ctx
);
8273 struct dsdb_dn
*dsdb_dn
= NULL
;
8274 uint64_t seq_num
= 0;
8275 struct parsed_dn
*pdn
, *next
;
8276 struct GUID guid
= GUID_zero();
8277 bool active
= (la
->flags
& DRSUAPI_DS_LINKED_ATTRIBUTE_FLAG_ACTIVE
)?true:false;
8279 struct dsdb_dn
*old_dsdb_dn
= NULL
;
8280 struct ldb_val
*val_to_update
= NULL
;
8281 bool add_as_inactive
= false;
8284 *change
= LINK_CHANGE_NONE
;
8286 /* the value blob for the attribute holds the target object DN */
8287 status
= dsdb_dn_la_from_blob(ldb
, attr
, schema
, mem_ctx
,
8288 la
->value
.blob
, &dsdb_dn
);
8289 if (!W_ERROR_IS_OK(status
)) {
8290 ldb_asprintf_errstring(ldb
, "Failed to parsed linked attribute blob for %s on %s - %s\n",
8291 attr
->lDAPDisplayName
,
8292 ldb_dn_get_linearized(src_dn
),
8293 win_errstr(status
));
8294 return LDB_ERR_OPERATIONS_ERROR
;
8297 ret
= replmd_check_target_exists(module
, dsdb_dn
, la_entry
, src_dn
,
8298 true, &guid
, &ignore_link
);
8300 if (ret
!= LDB_SUCCESS
) {
8305 * there are some cases where the target object doesn't exist, but it's
8306 * OK to ignore the linked attribute
8312 /* see if this link already exists */
8313 ret
= parsed_dn_find(ldb
, pdn_list
, old_el
->num_values
,
8316 dsdb_dn
->extra_part
, 0,
8318 attr
->syntax
->ldap_oid
,
8320 if (ret
!= LDB_SUCCESS
) {
8324 if (!replmd_link_update_is_newer(pdn
, la
)) {
8325 DEBUG(3,("Discarding older DRS linked attribute update to %s on %s from %s\n",
8326 old_el
->name
, ldb_dn_get_linearized(src_dn
),
8327 GUID_string(mem_ctx
, &la
->meta_data
.originating_invocation_id
)));
8331 /* get a seq_num for this change */
8332 ret
= ldb_sequence_number(ldb
, LDB_SEQ_NEXT
, &seq_num
);
8333 if (ret
!= LDB_SUCCESS
) {
8338 * check for single-valued link conflicts, i.e. an active linked
8339 * attribute already exists, but it has a different target value
8342 ret
= replmd_check_singleval_la_conflict(module
, replmd_private
,
8343 mem_ctx
, src_dn
, la
,
8344 dsdb_dn
, pdn
, pdn_list
,
8345 old_el
, schema
, attr
,
8348 if (ret
!= LDB_SUCCESS
) {
8354 uint32_t rmd_flags
= dsdb_dn_rmd_flags(pdn
->dsdb_dn
->dn
);
8356 if (!(rmd_flags
& DSDB_RMD_FLAG_DELETED
)) {
8357 /* remove the existing backlink */
8358 ret
= replmd_add_backlink(module
, replmd_private
,
8361 &pdn
->guid
, false, attr
,
8363 if (ret
!= LDB_SUCCESS
) {
8368 val_to_update
= pdn
->v
;
8369 old_dsdb_dn
= pdn
->dsdb_dn
;
8370 *change
= LINK_CHANGE_MODIFIED
;
8376 * We know where the new one needs to be, from the *next
8377 * pointer into pdn_list.
8380 offset
= old_el
->num_values
;
8382 if (next
->dsdb_dn
== NULL
) {
8383 ret
= really_parse_trusted_dn(mem_ctx
, ldb
, next
,
8384 attr
->syntax
->ldap_oid
);
8385 if (ret
!= LDB_SUCCESS
) {
8389 offset
= next
- pdn_list
;
8390 if (offset
> old_el
->num_values
) {
8391 return LDB_ERR_OPERATIONS_ERROR
;
8395 old_el
->values
= talloc_realloc(element_ctx
, old_el
->values
,
8396 struct ldb_val
, old_el
->num_values
+1);
8397 if (!old_el
->values
) {
8398 ldb_module_oom(module
);
8399 return LDB_ERR_OPERATIONS_ERROR
;
8402 if (offset
!= old_el
->num_values
) {
8403 memmove(&old_el
->values
[offset
+ 1], &old_el
->values
[offset
],
8404 (old_el
->num_values
- offset
) * sizeof(old_el
->values
[0]));
8407 old_el
->num_values
++;
8409 val_to_update
= &old_el
->values
[offset
];
8411 *change
= LINK_CHANGE_ADDED
;
8414 /* set the link attribute's value to the info that was received */
8415 ret
= replmd_set_la_val(mem_ctx
, val_to_update
, dsdb_dn
, old_dsdb_dn
,
8416 &la
->meta_data
.originating_invocation_id
,
8417 la
->meta_data
.originating_usn
, seq_num
,
8418 la
->meta_data
.originating_change_time
,
8419 la
->meta_data
.version
,
8421 if (ret
!= LDB_SUCCESS
) {
8425 if (add_as_inactive
) {
8427 /* Set the new link as inactive/deleted to avoid conflicts */
8428 ret
= replmd_delete_link_value(module
, replmd_private
, old_el
,
8429 src_dn
, schema
, attr
, seq_num
,
8430 false, &guid
, dsdb_dn
,
8433 if (ret
!= LDB_SUCCESS
) {
8437 } else if (active
) {
8439 /* if the new link is active, then add the new backlink */
8440 ret
= replmd_add_backlink(module
, replmd_private
,
8445 if (ret
!= LDB_SUCCESS
) {
8450 ret
= dsdb_check_single_valued_link(attr
, old_el
);
8451 if (ret
!= LDB_SUCCESS
) {
8455 old_el
->flags
|= LDB_FLAG_INTERNAL_DISABLE_SINGLE_VALUE_CHECK
;
8460 static int replmd_extended(struct ldb_module
*module
, struct ldb_request
*req
)
8462 if (strcmp(req
->op
.extended
.oid
, DSDB_EXTENDED_REPLICATED_OBJECTS_OID
) == 0) {
8463 return replmd_extended_replicated_objects(module
, req
);
8466 return ldb_next_request(module
, req
);
8471 we hook into the transaction operations to allow us to
8472 perform the linked attribute updates at the end of the whole
8473 transaction. This allows a forward linked attribute to be created
8474 before the object is created. During a vampire, w2k8 sends us linked
8475 attributes before the objects they are part of.
8477 static int replmd_start_transaction(struct ldb_module
*module
)
8479 /* create our private structure for this transaction */
8480 struct replmd_private
*replmd_private
= talloc_get_type(ldb_module_get_private(module
),
8481 struct replmd_private
);
8482 replmd_txn_cleanup(replmd_private
);
8484 /* free any leftover mod_usn records from cancelled
8486 while (replmd_private
->ncs
) {
8487 struct nc_entry
*e
= replmd_private
->ncs
;
8488 DLIST_REMOVE(replmd_private
->ncs
, e
);
8492 replmd_private
->originating_updates
= false;
8494 return ldb_next_start_trans(module
);
8498 * Processes a group of linked attributes that apply to the same source-object
8499 * and attribute-ID (and were received in the same replication chunk).
8501 static int replmd_process_la_group(struct ldb_module
*module
,
8502 struct replmd_private
*replmd_private
,
8503 struct la_group
*la_group
)
8505 struct la_entry
*la
= NULL
;
8506 struct la_entry
*prev
= NULL
;
8508 TALLOC_CTX
*tmp_ctx
= NULL
;
8509 struct la_entry
*first_la
= DLIST_TAIL(la_group
->la_entries
);
8510 struct ldb_message
*msg
= NULL
;
8511 enum deletion_state deletion_state
= OBJECT_NOT_DELETED
;
8512 struct ldb_context
*ldb
= ldb_module_get_ctx(module
);
8513 const struct dsdb_attribute
*attr
= NULL
;
8514 struct ldb_message_element
*old_el
= NULL
;
8515 struct parsed_dn
*pdn_list
= NULL
;
8516 replmd_link_changed change_type
;
8517 uint32_t num_changes
= 0;
8519 uint64_t seq_num
= 0;
8521 tmp_ctx
= talloc_new(la_group
);
8522 if (tmp_ctx
== NULL
) {
8523 return ldb_oom(ldb
);
8527 * get the attribute being modified and the search result for the
8530 ret
= replmd_get_la_entry_source(module
, first_la
, tmp_ctx
, &attr
,
8533 if (ret
!= LDB_SUCCESS
) {
8538 * Check for deleted objects per MS-DRSR 4.1.10.6.14
8539 * ProcessLinkValue, because link updates are not applied to
8540 * recycled and tombstone objects. We don't have to delete
8541 * any existing link, that should have happened when the
8542 * object deletion was replicated or initiated.
8544 * This needs isDeleted and isRecycled to be included as
8545 * attributes in the search and so in msg if set.
8547 replmd_deletion_state(module
, msg
, &deletion_state
, NULL
);
8549 if (deletion_state
>= OBJECT_RECYCLED
) {
8550 TALLOC_FREE(tmp_ctx
);
8555 * Now that we know the deletion_state, remove the extra
8556 * attributes added for that purpose. We need to do this
8557 * otherwise in the case of isDeleted: FALSE the modify will
8560 * Failed to apply linked attribute change 'attribute 'isDeleted':
8561 * invalid modify flags on
8562 * 'CN=g1_1527570609273,CN=Users,DC=samba,DC=example,DC=com':
8565 * This is because isDeleted is a Boolean, so FALSE is a
8566 * legitimate value (set by Samba's deletetest.py)
8568 ldb_msg_remove_attr(msg
, "isDeleted");
8569 ldb_msg_remove_attr(msg
, "isRecycled");
8571 /* get the msg->element[] for the link attribute being processed */
8572 old_el
= ldb_msg_find_element(msg
, attr
->lDAPDisplayName
);
8573 if (old_el
== NULL
) {
8574 ret
= ldb_msg_add_empty(msg
, attr
->lDAPDisplayName
,
8575 LDB_FLAG_MOD_REPLACE
, &old_el
);
8576 if (ret
!= LDB_SUCCESS
) {
8577 ldb_module_oom(module
);
8578 return LDB_ERR_OPERATIONS_ERROR
;
8581 old_el
->flags
= LDB_FLAG_MOD_REPLACE
;
8585 * go through and process the link target value(s) for this particular
8586 * source object and attribute. For optimization, the same msg is used
8587 * across multiple calls to replmd_process_linked_attribute().
8588 * Note that we should not add or remove any msg attributes inside the
8589 * loop (we should only add/modify *values* for the attribute being
8590 * processed). Otherwise msg->elements is realloc'd and old_el/pdn_list
8591 * pointers will be invalidated
8593 for (la
= DLIST_TAIL(la_group
->la_entries
); la
; la
=prev
) {
8594 prev
= DLIST_PREV(la
);
8595 DLIST_REMOVE(la_group
->la_entries
, la
);
8598 * parse the existing links (this can be costly for a large
8599 * group, so we try to minimize the times we do it)
8601 if (pdn_list
== NULL
) {
8602 ret
= get_parsed_dns_trusted_fallback(module
,
8606 attr
->syntax
->ldap_oid
,
8609 if (ret
!= LDB_SUCCESS
) {
8613 ret
= replmd_process_linked_attribute(module
, tmp_ctx
,
8615 msg
->dn
, attr
, la
, NULL
,
8616 msg
->elements
, old_el
,
8617 pdn_list
, &change_type
);
8618 if (ret
!= LDB_SUCCESS
) {
8619 replmd_txn_cleanup(replmd_private
);
8624 * Adding a link reallocs memory, and so invalidates all the
8625 * pointers in pdn_list. Reparse the PDNs on the next loop
8627 if (change_type
== LINK_CHANGE_ADDED
) {
8628 TALLOC_FREE(pdn_list
);
8631 if (change_type
!= LINK_CHANGE_NONE
) {
8635 if ((++replmd_private
->num_processed
% 8192) == 0) {
8636 DBG_NOTICE("Processed %u/%u linked attributes\n",
8637 replmd_private
->num_processed
,
8638 replmd_private
->total_links
);
8643 * it's possible we're already up-to-date and so don't need to modify
8644 * the object at all (e.g. doing a 'drs replicate --full-sync')
8646 if (num_changes
== 0) {
8647 TALLOC_FREE(tmp_ctx
);
8652 * Note that adding the whenChanged/etc attributes below will realloc
8653 * msg->elements, invalidating the existing element/parsed-DN pointers
8656 TALLOC_FREE(pdn_list
);
8658 /* update whenChanged/uSNChanged as the object has changed */
8660 ret
= ldb_sequence_number(ldb
, LDB_SEQ_HIGHEST_SEQ
,
8662 if (ret
!= LDB_SUCCESS
) {
8666 ret
= add_time_element(msg
, "whenChanged", t
);
8667 if (ret
!= LDB_SUCCESS
) {
8672 ret
= add_uint64_element(ldb
, msg
, "uSNChanged", seq_num
);
8673 if (ret
!= LDB_SUCCESS
) {
8678 /* apply the link changes to the source object */
8679 ret
= linked_attr_modify(module
, msg
, NULL
);
8680 if (ret
!= LDB_SUCCESS
) {
8681 ldb_debug(ldb
, LDB_DEBUG_WARNING
,
8682 "Failed to apply linked attribute change "
8683 "Error: '%s' DN: '%s' Attribute: '%s'\n",
8685 ldb_dn_get_linearized(msg
->dn
),
8686 attr
->lDAPDisplayName
);
8687 TALLOC_FREE(tmp_ctx
);
8691 TALLOC_FREE(tmp_ctx
);
8696 on prepare commit we loop over our queued la_context structures and
8699 static int replmd_prepare_commit(struct ldb_module
*module
)
8701 struct replmd_private
*replmd_private
=
8702 talloc_get_type(ldb_module_get_private(module
), struct replmd_private
);
8703 struct la_group
*la_group
, *prev
;
8706 if (replmd_private
->la_list
!= NULL
) {
8707 DBG_NOTICE("Processing linked attributes\n");
8711 * Walk the list of linked attributes from DRS replication.
8713 * We walk backwards, to do the first entry first, as we
8714 * added the entries with DLIST_ADD() which puts them at the
8717 * Links are grouped together so we process links for the same
8718 * source object in one go.
8720 for (la_group
= DLIST_TAIL(replmd_private
->la_list
);
8724 prev
= DLIST_PREV(la_group
);
8725 DLIST_REMOVE(replmd_private
->la_list
, la_group
);
8726 ret
= replmd_process_la_group(module
, replmd_private
,
8728 if (ret
!= LDB_SUCCESS
) {
8729 replmd_txn_cleanup(replmd_private
);
8734 replmd_txn_cleanup(replmd_private
);
8736 /* possibly change @REPLCHANGED */
8737 ret
= replmd_notify_store(module
, NULL
);
8738 if (ret
!= LDB_SUCCESS
) {
8742 return ldb_next_prepare_commit(module
);
8745 static int replmd_del_transaction(struct ldb_module
*module
)
8747 struct replmd_private
*replmd_private
=
8748 talloc_get_type(ldb_module_get_private(module
), struct replmd_private
);
8749 replmd_txn_cleanup(replmd_private
);
8751 return ldb_next_del_trans(module
);
8755 static const struct ldb_module_ops ldb_repl_meta_data_module_ops
= {
8756 .name
= "repl_meta_data",
8757 .init_context
= replmd_init
,
8759 .modify
= replmd_modify
,
8760 .rename
= replmd_rename
,
8761 .del
= replmd_delete
,
8762 .extended
= replmd_extended
,
8763 .start_transaction
= replmd_start_transaction
,
8764 .prepare_commit
= replmd_prepare_commit
,
8765 .del_transaction
= replmd_del_transaction
,
8768 int ldb_repl_meta_data_module_init(const char *version
)
8770 LDB_MODULE_CHECK_VERSION(version
);
8771 return ldb_register_module(&ldb_repl_meta_data_module_ops
);