2 Unix SMB/CIFS Implementation.
3 DSDB replication service helper function for outgoing traffic
5 Copyright (C) Stefan Metzmacher 2007
7 This program is free software; you can redistribute it and/or modify
8 it under the terms of the GNU General Public License as published by
9 the Free Software Foundation; either version 3 of the License, or
10 (at your option) any later version.
12 This program is distributed in the hope that it will be useful,
13 but WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 GNU General Public License for more details.
17 You should have received a copy of the GNU General Public License
18 along with this program. If not, see <http://www.gnu.org/licenses/>.
23 #include "dsdb/samdb/samdb.h"
24 #include "auth/auth.h"
25 #include "samba/service.h"
26 #include "lib/events/events.h"
27 #include "dsdb/repl/drepl_service.h"
28 #include <ldb_errors.h>
29 #include "../lib/util/dlinklist.h"
30 #include "librpc/gen_ndr/ndr_misc.h"
31 #include "librpc/gen_ndr/ndr_drsuapi.h"
32 #include "librpc/gen_ndr/ndr_drsblobs.h"
33 #include "libcli/composite/composite.h"
34 #include "auth/gensec/gensec.h"
35 #include "param/param.h"
36 #include "../lib/util/tevent_ntstatus.h"
37 #include "libcli/security/security.h"
40 #define DBGC_CLASS DBGC_DRS_REPL
42 struct dreplsrv_out_drsuapi_state
{
43 struct tevent_context
*ev
;
45 struct dreplsrv_out_connection
*conn
;
47 struct dreplsrv_drsuapi_connection
*drsuapi
;
49 struct drsuapi_DsBindInfoCtr bind_info_ctr
;
50 struct drsuapi_DsBind bind_r
;
53 static void dreplsrv_out_drsuapi_connect_done(struct composite_context
*creq
);
55 struct tevent_req
*dreplsrv_out_drsuapi_send(TALLOC_CTX
*mem_ctx
,
56 struct tevent_context
*ev
,
57 struct dreplsrv_out_connection
*conn
)
59 struct tevent_req
*req
;
60 struct dreplsrv_out_drsuapi_state
*state
;
61 struct composite_context
*creq
;
63 req
= tevent_req_create(mem_ctx
, &state
,
64 struct dreplsrv_out_drsuapi_state
);
71 state
->drsuapi
= conn
->drsuapi
;
73 if (state
->drsuapi
!= NULL
) {
74 struct dcerpc_binding_handle
*b
=
75 state
->drsuapi
->pipe
->binding_handle
;
76 bool is_connected
= dcerpc_binding_handle_is_connected(b
);
80 return tevent_req_post(req
, ev
);
83 TALLOC_FREE(conn
->drsuapi
);
86 state
->drsuapi
= talloc_zero(state
, struct dreplsrv_drsuapi_connection
);
87 if (tevent_req_nomem(state
->drsuapi
, req
)) {
88 return tevent_req_post(req
, ev
);
91 creq
= dcerpc_pipe_connect_b_send(state
, conn
->binding
, &ndr_table_drsuapi
,
92 conn
->service
->system_session_info
->credentials
,
93 ev
, conn
->service
->task
->lp_ctx
);
94 if (tevent_req_nomem(creq
, req
)) {
95 return tevent_req_post(req
, ev
);
97 composite_continue(NULL
, creq
, dreplsrv_out_drsuapi_connect_done
, req
);
102 static void dreplsrv_out_drsuapi_bind_done(struct tevent_req
*subreq
);
104 static void dreplsrv_out_drsuapi_connect_done(struct composite_context
*creq
)
106 struct tevent_req
*req
= talloc_get_type(creq
->async
.private_data
,
108 struct dreplsrv_out_drsuapi_state
*state
= tevent_req_data(req
,
109 struct dreplsrv_out_drsuapi_state
);
111 struct tevent_req
*subreq
;
113 status
= dcerpc_pipe_connect_b_recv(creq
,
115 &state
->drsuapi
->pipe
);
116 if (tevent_req_nterror(req
, status
)) {
120 state
->drsuapi
->drsuapi_handle
= state
->drsuapi
->pipe
->binding_handle
;
122 status
= dcerpc_binding_handle_auth_session_key(
123 state
->drsuapi
->drsuapi_handle
,
125 &state
->drsuapi
->gensec_skey
);
126 if (tevent_req_nterror(req
, status
)) {
130 state
->bind_info_ctr
.length
= 28;
131 state
->bind_info_ctr
.info
.info28
= state
->conn
->service
->bind_info28
;
133 state
->bind_r
.in
.bind_guid
= &state
->conn
->service
->ntds_guid
;
134 state
->bind_r
.in
.bind_info
= &state
->bind_info_ctr
;
135 state
->bind_r
.out
.bind_handle
= &state
->drsuapi
->bind_handle
;
137 subreq
= dcerpc_drsuapi_DsBind_r_send(state
,
139 state
->drsuapi
->drsuapi_handle
,
141 if (tevent_req_nomem(subreq
, req
)) {
144 tevent_req_set_callback(subreq
, dreplsrv_out_drsuapi_bind_done
, req
);
147 static void dreplsrv_out_drsuapi_bind_done(struct tevent_req
*subreq
)
149 struct tevent_req
*req
= tevent_req_callback_data(subreq
,
151 struct dreplsrv_out_drsuapi_state
*state
= tevent_req_data(req
,
152 struct dreplsrv_out_drsuapi_state
);
155 status
= dcerpc_drsuapi_DsBind_r_recv(subreq
, state
);
157 if (tevent_req_nterror(req
, status
)) {
161 if (!W_ERROR_IS_OK(state
->bind_r
.out
.result
)) {
162 status
= werror_to_ntstatus(state
->bind_r
.out
.result
);
163 tevent_req_nterror(req
, status
);
167 ZERO_STRUCT(state
->drsuapi
->remote_info28
);
168 if (state
->bind_r
.out
.bind_info
) {
169 struct drsuapi_DsBindInfo28
*info28
;
170 info28
= &state
->drsuapi
->remote_info28
;
172 switch (state
->bind_r
.out
.bind_info
->length
) {
174 struct drsuapi_DsBindInfo24
*info24
;
175 info24
= &state
->bind_r
.out
.bind_info
->info
.info24
;
177 info28
->supported_extensions
= info24
->supported_extensions
;
178 info28
->site_guid
= info24
->site_guid
;
179 info28
->pid
= info24
->pid
;
180 info28
->repl_epoch
= 0;
184 *info28
= state
->bind_r
.out
.bind_info
->info
.info28
;
188 struct drsuapi_DsBindInfo32
*info32
;
189 info32
= &state
->bind_r
.out
.bind_info
->info
.info32
;
191 info28
->supported_extensions
= info32
->supported_extensions
;
192 info28
->site_guid
= info32
->site_guid
;
193 info28
->pid
= info32
->pid
;
194 info28
->repl_epoch
= info32
->repl_epoch
;
198 struct drsuapi_DsBindInfo48
*info48
;
199 info48
= &state
->bind_r
.out
.bind_info
->info
.info48
;
201 info28
->supported_extensions
= info48
->supported_extensions
;
202 info28
->site_guid
= info48
->site_guid
;
203 info28
->pid
= info48
->pid
;
204 info28
->repl_epoch
= info48
->repl_epoch
;
208 struct drsuapi_DsBindInfo52
*info52
;
209 info52
= &state
->bind_r
.out
.bind_info
->info
.info52
;
211 info28
->supported_extensions
= info52
->supported_extensions
;
212 info28
->site_guid
= info52
->site_guid
;
213 info28
->pid
= info52
->pid
;
214 info28
->repl_epoch
= info52
->repl_epoch
;
218 DEBUG(1, ("Warning: invalid info length in bind info: %d\n",
219 state
->bind_r
.out
.bind_info
->length
));
224 tevent_req_done(req
);
227 NTSTATUS
dreplsrv_out_drsuapi_recv(struct tevent_req
*req
)
229 struct dreplsrv_out_drsuapi_state
*state
= tevent_req_data(req
,
230 struct dreplsrv_out_drsuapi_state
);
233 if (tevent_req_is_nterror(req
, &status
)) {
234 tevent_req_received(req
);
238 state
->conn
->drsuapi
= talloc_move(state
->conn
, &state
->drsuapi
);
240 tevent_req_received(req
);
244 struct dreplsrv_op_pull_source_schema_cycle
{
245 struct repsFromTo1 repsFrom1
;
247 struct drsuapi_DsReplicaObjectListItemEx
*first_object
;
248 struct drsuapi_DsReplicaObjectListItemEx
*last_object
;
249 uint32_t linked_attributes_count
;
250 struct drsuapi_DsReplicaLinkedAttribute
*linked_attributes
;
253 struct dreplsrv_op_pull_source_state
{
254 struct tevent_context
*ev
;
255 struct dreplsrv_out_operation
*op
;
256 void *ndr_struct_ptr
;
258 * Used when we have to re-try with a different NC, eg for
259 * EXOP retry or to get a current schema first
261 struct dreplsrv_partition_source_dsa
*source_dsa_retry
;
262 enum drsuapi_DsExtendedOperation extended_op_retry
;
264 struct dreplsrv_op_pull_source_schema_cycle
*schema_cycle
;
267 static void dreplsrv_op_pull_source_connect_done(struct tevent_req
*subreq
);
269 struct tevent_req
*dreplsrv_op_pull_source_send(TALLOC_CTX
*mem_ctx
,
270 struct tevent_context
*ev
,
271 struct dreplsrv_out_operation
*op
)
273 struct tevent_req
*req
;
274 struct dreplsrv_op_pull_source_state
*state
;
275 struct tevent_req
*subreq
;
277 req
= tevent_req_create(mem_ctx
, &state
,
278 struct dreplsrv_op_pull_source_state
);
285 subreq
= dreplsrv_out_drsuapi_send(state
, ev
, op
->source_dsa
->conn
);
286 if (tevent_req_nomem(subreq
, req
)) {
287 return tevent_req_post(req
, ev
);
289 tevent_req_set_callback(subreq
, dreplsrv_op_pull_source_connect_done
, req
);
294 static bool dreplsrv_op_pull_source_detect_schema_cycle(struct tevent_req
*req
)
296 struct dreplsrv_op_pull_source_state
*state
=
298 struct dreplsrv_op_pull_source_state
);
299 bool is_schema
= false;
301 if (state
->op
->extended_op
== DRSUAPI_EXOP_NONE
) {
302 struct dreplsrv_out_operation
*op
= state
->op
;
303 struct dreplsrv_service
*service
= op
->service
;
304 struct ldb_dn
*schema_dn
= ldb_get_schema_basedn(service
->samdb
);
305 struct dreplsrv_partition
*partition
= op
->source_dsa
->partition
;
307 is_schema
= ldb_dn_compare(partition
->dn
, schema_dn
) == 0;
311 struct dreplsrv_op_pull_source_schema_cycle
*sc
;
313 sc
= talloc_zero(state
,
314 struct dreplsrv_op_pull_source_schema_cycle
);
315 if (tevent_req_nomem(sc
, req
)) {
318 sc
->repsFrom1
= *state
->op
->source_dsa
->repsFrom1
;
320 state
->schema_cycle
= sc
;
326 static void dreplsrv_op_pull_source_get_changes_trigger(struct tevent_req
*req
);
328 static void dreplsrv_op_pull_source_connect_done(struct tevent_req
*subreq
)
330 struct tevent_req
*req
= tevent_req_callback_data(subreq
,
335 status
= dreplsrv_out_drsuapi_recv(subreq
);
337 if (tevent_req_nterror(req
, status
)) {
341 ok
= dreplsrv_op_pull_source_detect_schema_cycle(req
);
346 dreplsrv_op_pull_source_get_changes_trigger(req
);
349 static void dreplsrv_op_pull_source_get_changes_done(struct tevent_req
*subreq
);
352 get a RODC partial attribute set for a replication call
354 static NTSTATUS
dreplsrv_get_rodc_partial_attribute_set(struct dreplsrv_service
*service
,
356 struct drsuapi_DsPartialAttributeSet
**_pas
,
357 struct drsuapi_DsReplicaOIDMapping_Ctr
**pfm
,
360 struct drsuapi_DsPartialAttributeSet
*pas
;
361 struct dsdb_schema
*schema
;
364 pas
= talloc_zero(mem_ctx
, struct drsuapi_DsPartialAttributeSet
);
365 NT_STATUS_HAVE_NO_MEMORY(pas
);
367 schema
= dsdb_get_schema(service
->samdb
, NULL
);
370 pas
->attids
= talloc_array(pas
, enum drsuapi_DsAttributeId
, schema
->num_attributes
);
371 if (pas
->attids
== NULL
) {
373 return NT_STATUS_NO_MEMORY
;
376 for (i
=0; i
<schema
->num_attributes
; i
++) {
377 struct dsdb_attribute
*a
;
378 a
= schema
->attributes_by_attributeID_id
[i
];
379 if (a
->systemFlags
& (DS_FLAG_ATTR_NOT_REPLICATED
| DS_FLAG_ATTR_IS_CONSTRUCTED
)) {
382 if (a
->searchFlags
& SEARCH_FLAG_RODC_ATTRIBUTE
) {
385 pas
->attids
[pas
->num_attids
] = dsdb_attribute_get_attid(a
, for_schema
);
389 pas
->attids
= talloc_realloc(pas
, pas
->attids
, enum drsuapi_DsAttributeId
, pas
->num_attids
);
390 if (pas
->attids
== NULL
) {
392 return NT_STATUS_NO_MEMORY
;
398 dsdb_get_oid_mappings_drsuapi(schema
, true, mem_ctx
, pfm
);
406 get a GC partial attribute set for a replication call
408 static NTSTATUS
dreplsrv_get_gc_partial_attribute_set(struct dreplsrv_service
*service
,
410 struct drsuapi_DsPartialAttributeSet
**_pas
,
411 struct drsuapi_DsReplicaOIDMapping_Ctr
**pfm
)
413 struct drsuapi_DsPartialAttributeSet
*pas
;
414 struct dsdb_schema
*schema
;
417 pas
= talloc_zero(mem_ctx
, struct drsuapi_DsPartialAttributeSet
);
418 NT_STATUS_HAVE_NO_MEMORY(pas
);
420 schema
= dsdb_get_schema(service
->samdb
, NULL
);
423 pas
->attids
= talloc_array(pas
, enum drsuapi_DsAttributeId
, schema
->num_attributes
);
424 if (pas
->attids
== NULL
) {
426 return NT_STATUS_NO_MEMORY
;
429 for (i
=0; i
<schema
->num_attributes
; i
++) {
430 struct dsdb_attribute
*a
;
431 a
= schema
->attributes_by_attributeID_id
[i
];
432 if (a
->isMemberOfPartialAttributeSet
) {
433 pas
->attids
[pas
->num_attids
] = dsdb_attribute_get_attid(a
, false);
438 pas
->attids
= talloc_realloc(pas
, pas
->attids
, enum drsuapi_DsAttributeId
, pas
->num_attids
);
439 if (pas
->attids
== NULL
) {
441 return NT_STATUS_NO_MEMORY
;
447 dsdb_get_oid_mappings_drsuapi(schema
, true, mem_ctx
, pfm
);
454 convert from one udv format to the other
456 static WERROR
udv_convert(TALLOC_CTX
*mem_ctx
,
457 const struct replUpToDateVectorCtr2
*udv
,
458 struct drsuapi_DsReplicaCursorCtrEx
*udv_ex
)
463 udv_ex
->reserved1
= 0;
464 udv_ex
->reserved2
= 0;
465 udv_ex
->count
= udv
->count
;
466 udv_ex
->cursors
= talloc_array(mem_ctx
, struct drsuapi_DsReplicaCursor
, udv
->count
);
467 W_ERROR_HAVE_NO_MEMORY(udv_ex
->cursors
);
469 for (i
=0; i
<udv
->count
; i
++) {
470 udv_ex
->cursors
[i
].source_dsa_invocation_id
= udv
->cursors
[i
].source_dsa_invocation_id
;
471 udv_ex
->cursors
[i
].highest_usn
= udv
->cursors
[i
].highest_usn
;
478 static void dreplsrv_op_pull_source_get_changes_trigger(struct tevent_req
*req
)
480 struct dreplsrv_op_pull_source_state
*state
= tevent_req_data(req
,
481 struct dreplsrv_op_pull_source_state
);
482 const struct repsFromTo1
*rf1
= state
->op
->source_dsa
->repsFrom1
;
483 struct dreplsrv_service
*service
= state
->op
->service
;
484 struct dreplsrv_partition
*partition
= state
->op
->source_dsa
->partition
;
485 struct dreplsrv_drsuapi_connection
*drsuapi
= state
->op
->source_dsa
->conn
->drsuapi
;
486 struct drsuapi_DsGetNCChanges
*r
;
487 struct drsuapi_DsReplicaCursorCtrEx
*uptodateness_vector
;
488 struct tevent_req
*subreq
;
489 struct drsuapi_DsPartialAttributeSet
*pas
= NULL
;
491 uint32_t replica_flags
;
492 struct drsuapi_DsReplicaHighWaterMark highwatermark
;
493 struct drsuapi_DsReplicaOIDMapping_Ctr
*mappings
= NULL
;
494 bool is_schema
= false;
496 if (state
->schema_cycle
!= NULL
) {
498 rf1
= &state
->schema_cycle
->repsFrom1
;
501 r
= talloc(state
, struct drsuapi_DsGetNCChanges
);
502 if (tevent_req_nomem(r
, req
)) {
506 r
->out
.level_out
= talloc(r
, uint32_t);
507 if (tevent_req_nomem(r
->out
.level_out
, req
)) {
510 r
->in
.req
= talloc(r
, union drsuapi_DsGetNCChangesRequest
);
511 if (tevent_req_nomem(r
->in
.req
, req
)) {
514 r
->out
.ctr
= talloc(r
, union drsuapi_DsGetNCChangesCtr
);
515 if (tevent_req_nomem(r
->out
.ctr
, req
)) {
519 if (partition
->uptodatevector
.count
!= 0 &&
520 partition
->uptodatevector_ex
.count
== 0) {
522 werr
= udv_convert(partition
, &partition
->uptodatevector
, &partition
->uptodatevector_ex
);
523 if (!W_ERROR_IS_OK(werr
)) {
524 DEBUG(0,(__location__
": Failed to convert UDV for %s : %s\n",
525 ldb_dn_get_linearized(partition
->dn
), win_errstr(werr
)));
526 tevent_req_nterror(req
, werror_to_ntstatus(werr
));
531 if (partition
->uptodatevector_ex
.count
== 0) {
532 uptodateness_vector
= NULL
;
534 uptodateness_vector
= &partition
->uptodatevector_ex
;
537 replica_flags
= rf1
->replica_flags
;
538 highwatermark
= rf1
->highwatermark
;
540 if (state
->op
->options
& DRSUAPI_DRS_GET_ANC
) {
541 replica_flags
|= DRSUAPI_DRS_GET_ANC
;
544 if (state
->op
->options
& DRSUAPI_DRS_SYNC_FORCED
) {
545 replica_flags
|= DRSUAPI_DRS_SYNC_FORCED
;
548 if (partition
->partial_replica
) {
549 status
= dreplsrv_get_gc_partial_attribute_set(service
, r
,
552 if (!NT_STATUS_IS_OK(status
)) {
553 DEBUG(0,(__location__
": Failed to construct GC partial attribute set : %s\n", nt_errstr(status
)));
554 tevent_req_nterror(req
, status
);
557 replica_flags
&= ~DRSUAPI_DRS_WRIT_REP
;
558 } else if (partition
->rodc_replica
|| state
->op
->extended_op
== DRSUAPI_EXOP_REPL_SECRET
) {
559 status
= dreplsrv_get_rodc_partial_attribute_set(service
, r
,
563 if (!NT_STATUS_IS_OK(status
)) {
564 DEBUG(0,(__location__
": Failed to construct RODC partial attribute set : %s\n", nt_errstr(status
)));
565 tevent_req_nterror(req
, status
);
568 replica_flags
&= ~DRSUAPI_DRS_WRIT_REP
;
569 if (state
->op
->extended_op
== DRSUAPI_EXOP_REPL_SECRET
) {
570 replica_flags
&= ~DRSUAPI_DRS_SPECIAL_SECRET_PROCESSING
;
572 replica_flags
|= DRSUAPI_DRS_SPECIAL_SECRET_PROCESSING
;
579 * Client Behavior When Sending the IDL_DRSGetNCChanges Request
582 * ReplicateNCRequestMsg
584 replica_flags
|= DRSUAPI_DRS_GET_ALL_GROUP_MEMBERSHIP
;
586 replica_flags
|= DRSUAPI_DRS_GET_ALL_GROUP_MEMBERSHIP
;
589 if (state
->op
->extended_op
!= DRSUAPI_EXOP_NONE
) {
591 * If it's an exop never set the ADD_REF even if it's in
594 replica_flags
&= ~DRSUAPI_DRS_ADD_REF
;
597 /* is this a full resync of all objects? */
598 if (state
->op
->options
& DRSUAPI_DRS_FULL_SYNC_NOW
) {
599 ZERO_STRUCT(highwatermark
);
600 /* clear the FULL_SYNC_NOW option for subsequent
601 stages of the replication cycle */
602 state
->op
->options
&= ~DRSUAPI_DRS_FULL_SYNC_NOW
;
603 state
->op
->options
|= DRSUAPI_DRS_FULL_SYNC_IN_PROGRESS
;
604 replica_flags
|= DRSUAPI_DRS_NEVER_SYNCED
;
606 if (state
->op
->options
& DRSUAPI_DRS_FULL_SYNC_IN_PROGRESS
) {
607 uptodateness_vector
= NULL
;
610 r
->in
.bind_handle
= &drsuapi
->bind_handle
;
612 if (drsuapi
->remote_info28
.supported_extensions
& DRSUAPI_SUPPORTED_EXTENSION_GETCHGREQ_V10
) {
614 r
->in
.req
->req10
.destination_dsa_guid
= service
->ntds_guid
;
615 r
->in
.req
->req10
.source_dsa_invocation_id
= rf1
->source_dsa_invocation_id
;
616 r
->in
.req
->req10
.naming_context
= &partition
->nc
;
617 r
->in
.req
->req10
.highwatermark
= highwatermark
;
618 r
->in
.req
->req10
.uptodateness_vector
= uptodateness_vector
;
619 r
->in
.req
->req10
.replica_flags
= replica_flags
;
620 r
->in
.req
->req10
.max_object_count
= 133;
621 r
->in
.req
->req10
.max_ndr_size
= 1336811;
622 r
->in
.req
->req10
.extended_op
= state
->op
->extended_op
;
623 r
->in
.req
->req10
.fsmo_info
= state
->op
->fsmo_info
;
624 r
->in
.req
->req10
.partial_attribute_set
= pas
;
625 r
->in
.req
->req10
.partial_attribute_set_ex
= NULL
;
626 r
->in
.req
->req10
.mapping_ctr
.num_mappings
= mappings
== NULL
? 0 : mappings
->num_mappings
;
627 r
->in
.req
->req10
.mapping_ctr
.mappings
= mappings
== NULL
? NULL
: mappings
->mappings
;
629 /* the only difference to v8 is the more_flags */
630 r
->in
.req
->req10
.more_flags
= state
->op
->more_flags
;
632 } else if (drsuapi
->remote_info28
.supported_extensions
& DRSUAPI_SUPPORTED_EXTENSION_GETCHGREQ_V8
) {
634 r
->in
.req
->req8
.destination_dsa_guid
= service
->ntds_guid
;
635 r
->in
.req
->req8
.source_dsa_invocation_id
= rf1
->source_dsa_invocation_id
;
636 r
->in
.req
->req8
.naming_context
= &partition
->nc
;
637 r
->in
.req
->req8
.highwatermark
= highwatermark
;
638 r
->in
.req
->req8
.uptodateness_vector
= uptodateness_vector
;
639 r
->in
.req
->req8
.replica_flags
= replica_flags
;
640 r
->in
.req
->req8
.max_object_count
= 133;
641 r
->in
.req
->req8
.max_ndr_size
= 1336811;
642 r
->in
.req
->req8
.extended_op
= state
->op
->extended_op
;
643 r
->in
.req
->req8
.fsmo_info
= state
->op
->fsmo_info
;
644 r
->in
.req
->req8
.partial_attribute_set
= pas
;
645 r
->in
.req
->req8
.partial_attribute_set_ex
= NULL
;
646 r
->in
.req
->req8
.mapping_ctr
.num_mappings
= mappings
== NULL
? 0 : mappings
->num_mappings
;
647 r
->in
.req
->req8
.mapping_ctr
.mappings
= mappings
== NULL
? NULL
: mappings
->mappings
;
650 r
->in
.req
->req5
.destination_dsa_guid
= service
->ntds_guid
;
651 r
->in
.req
->req5
.source_dsa_invocation_id
= rf1
->source_dsa_invocation_id
;
652 r
->in
.req
->req5
.naming_context
= &partition
->nc
;
653 r
->in
.req
->req5
.highwatermark
= highwatermark
;
654 r
->in
.req
->req5
.uptodateness_vector
= uptodateness_vector
;
655 r
->in
.req
->req5
.replica_flags
= replica_flags
;
656 r
->in
.req
->req5
.max_object_count
= 133;
657 r
->in
.req
->req5
.max_ndr_size
= 1336770;
658 r
->in
.req
->req5
.extended_op
= state
->op
->extended_op
;
659 r
->in
.req
->req5
.fsmo_info
= state
->op
->fsmo_info
;
663 NDR_PRINT_IN_DEBUG(drsuapi_DsGetNCChanges
, r
);
666 state
->ndr_struct_ptr
= r
;
667 subreq
= dcerpc_drsuapi_DsGetNCChanges_r_send(state
,
669 drsuapi
->drsuapi_handle
,
671 if (tevent_req_nomem(subreq
, req
)) {
674 tevent_req_set_callback(subreq
, dreplsrv_op_pull_source_get_changes_done
, req
);
677 static void dreplsrv_op_pull_source_apply_changes_trigger(struct tevent_req
*req
,
678 struct drsuapi_DsGetNCChanges
*r
,
680 struct drsuapi_DsGetNCChangesCtr1
*ctr1
,
681 struct drsuapi_DsGetNCChangesCtr6
*ctr6
);
683 static void dreplsrv_op_pull_source_get_changes_done(struct tevent_req
*subreq
)
685 struct tevent_req
*req
= tevent_req_callback_data(subreq
,
687 struct dreplsrv_op_pull_source_state
*state
= tevent_req_data(req
,
688 struct dreplsrv_op_pull_source_state
);
690 struct drsuapi_DsGetNCChanges
*r
= talloc_get_type(state
->ndr_struct_ptr
,
691 struct drsuapi_DsGetNCChanges
);
692 uint32_t ctr_level
= 0;
693 struct drsuapi_DsGetNCChangesCtr1
*ctr1
= NULL
;
694 struct drsuapi_DsGetNCChangesCtr6
*ctr6
= NULL
;
695 enum drsuapi_DsExtendedError extended_ret
= DRSUAPI_EXOP_ERR_NONE
;
696 state
->ndr_struct_ptr
= NULL
;
698 status
= dcerpc_drsuapi_DsGetNCChanges_r_recv(subreq
, r
);
700 if (tevent_req_nterror(req
, status
)) {
704 if (!W_ERROR_IS_OK(r
->out
.result
)) {
705 status
= werror_to_ntstatus(r
->out
.result
);
706 tevent_req_nterror(req
, status
);
710 if (*r
->out
.level_out
== 1) {
712 ctr1
= &r
->out
.ctr
->ctr1
;
713 } else if (*r
->out
.level_out
== 2 &&
714 r
->out
.ctr
->ctr2
.mszip1
.ts
) {
716 ctr1
= &r
->out
.ctr
->ctr2
.mszip1
.ts
->ctr1
;
717 } else if (*r
->out
.level_out
== 6) {
719 ctr6
= &r
->out
.ctr
->ctr6
;
720 } else if (*r
->out
.level_out
== 7 &&
721 r
->out
.ctr
->ctr7
.level
== 6 &&
722 r
->out
.ctr
->ctr7
.type
== DRSUAPI_COMPRESSION_TYPE_MSZIP
&&
723 r
->out
.ctr
->ctr7
.ctr
.mszip6
.ts
) {
725 ctr6
= &r
->out
.ctr
->ctr7
.ctr
.mszip6
.ts
->ctr6
;
726 } else if (*r
->out
.level_out
== 7 &&
727 r
->out
.ctr
->ctr7
.level
== 6 &&
728 r
->out
.ctr
->ctr7
.type
== DRSUAPI_COMPRESSION_TYPE_WIN2K3_LZ77_DIRECT2
&&
729 r
->out
.ctr
->ctr7
.ctr
.xpress6
.ts
) {
731 ctr6
= &r
->out
.ctr
->ctr7
.ctr
.xpress6
.ts
->ctr6
;
733 status
= werror_to_ntstatus(WERR_BAD_NET_RESP
);
734 tevent_req_nterror(req
, status
);
738 if (!ctr1
&& !ctr6
) {
739 status
= werror_to_ntstatus(WERR_BAD_NET_RESP
);
740 tevent_req_nterror(req
, status
);
744 if (ctr_level
== 6) {
745 if (!W_ERROR_IS_OK(ctr6
->drs_error
)) {
746 status
= werror_to_ntstatus(ctr6
->drs_error
);
747 tevent_req_nterror(req
, status
);
750 extended_ret
= ctr6
->extended_ret
;
753 if (ctr_level
== 1) {
754 extended_ret
= ctr1
->extended_ret
;
757 if (state
->op
->extended_op
!= DRSUAPI_EXOP_NONE
) {
758 state
->op
->extended_ret
= extended_ret
;
760 if (extended_ret
!= DRSUAPI_EXOP_ERR_SUCCESS
) {
761 status
= NT_STATUS_UNSUCCESSFUL
;
762 tevent_req_nterror(req
, status
);
767 dreplsrv_op_pull_source_apply_changes_trigger(req
, r
, ctr_level
, ctr1
, ctr6
);
771 * If processing a chunk of replication data fails, check if it is due to a
772 * problem that can be fixed by setting extra flags in the GetNCChanges request,
773 * i.e. GET_ANC or GET_TGT.
774 * @returns NT_STATUS_OK if the request was retried, and an error code if not
776 static NTSTATUS
dreplsrv_op_pull_retry_with_flags(struct tevent_req
*req
,
779 struct dreplsrv_op_pull_source_state
*state
;
780 NTSTATUS nt_status
= NT_STATUS_OK
;
782 state
= tevent_req_data(req
, struct dreplsrv_op_pull_source_state
);
785 * Check if we failed to apply the records due to a missing parent or
786 * target object. If so, try again and ask for any missing parent/target
787 * objects to be included this time.
789 if (W_ERROR_EQUAL(error_code
, WERR_DS_DRA_RECYCLED_TARGET
)) {
791 if (state
->op
->more_flags
& DRSUAPI_DRS_GET_TGT
) {
792 DEBUG(1,("Missing target object despite setting DRSUAPI_DRS_GET_TGT flag\n"));
793 nt_status
= NT_STATUS_INVALID_NETWORK_RESPONSE
;
795 state
->op
->more_flags
|= DRSUAPI_DRS_GET_TGT
;
796 DEBUG(1,("Missing target object when we didn't set the DRSUAPI_DRS_GET_TGT flag, retrying\n"));
797 dreplsrv_op_pull_source_get_changes_trigger(req
);
799 } else if (W_ERROR_EQUAL(error_code
, WERR_DS_DRA_MISSING_PARENT
)) {
801 if (state
->op
->options
& DRSUAPI_DRS_GET_ANC
) {
802 DEBUG(1,("Missing parent object despite setting DRSUAPI_DRS_GET_ANC flag\n"));
803 nt_status
= NT_STATUS_INVALID_NETWORK_RESPONSE
;
805 state
->op
->options
|= DRSUAPI_DRS_GET_ANC
;
806 DEBUG(4,("Missing parent object when we didn't set the DRSUAPI_DRS_GET_ANC flag, retrying\n"));
807 dreplsrv_op_pull_source_get_changes_trigger(req
);
810 nt_status
= werror_to_ntstatus(WERR_BAD_NET_RESP
);
817 static void dreplsrv_update_refs_trigger(struct tevent_req
*req
);
819 static void dreplsrv_op_pull_source_apply_changes_trigger(struct tevent_req
*req
,
820 struct drsuapi_DsGetNCChanges
*r
,
822 struct drsuapi_DsGetNCChangesCtr1
*ctr1
,
823 struct drsuapi_DsGetNCChangesCtr6
*ctr6
)
825 struct dreplsrv_op_pull_source_state
*state
= tevent_req_data(req
,
826 struct dreplsrv_op_pull_source_state
);
827 struct repsFromTo1 rf1
= *state
->op
->source_dsa
->repsFrom1
;
828 struct dreplsrv_service
*service
= state
->op
->service
;
829 struct dreplsrv_partition
*partition
= state
->op
->source_dsa
->partition
;
830 struct dreplsrv_drsuapi_connection
*drsuapi
= state
->op
->source_dsa
->conn
->drsuapi
;
831 struct ldb_dn
*schema_dn
= ldb_get_schema_basedn(service
->samdb
);
832 struct dreplsrv_op_pull_source_schema_cycle
*sc
= NULL
;
833 struct dsdb_schema
*schema
;
834 struct dsdb_schema
*working_schema
= NULL
;
835 const struct drsuapi_DsReplicaOIDMapping_Ctr
*mapping_ctr
;
836 uint32_t object_count
;
837 struct drsuapi_DsReplicaObjectListItemEx
*first_object
;
838 uint32_t linked_attributes_count
;
839 struct drsuapi_DsReplicaLinkedAttribute
*linked_attributes
;
840 const struct drsuapi_DsReplicaCursor2CtrEx
*uptodateness_vector
;
841 struct dsdb_extended_replicated_objects
*objects
;
842 bool more_data
= false;
845 uint32_t dsdb_repl_flags
= 0;
846 struct ldb_dn
*nc_root
= NULL
;
847 bool was_schema
= false;
852 mapping_ctr
= &ctr1
->mapping_ctr
;
853 object_count
= ctr1
->object_count
;
854 first_object
= ctr1
->first_object
;
855 linked_attributes_count
= 0;
856 linked_attributes
= NULL
;
857 rf1
.source_dsa_obj_guid
= ctr1
->source_dsa_guid
;
858 rf1
.source_dsa_invocation_id
= ctr1
->source_dsa_invocation_id
;
859 rf1
.highwatermark
= ctr1
->new_highwatermark
;
860 uptodateness_vector
= NULL
; /* TODO: map it */
861 more_data
= ctr1
->more_data
;
864 mapping_ctr
= &ctr6
->mapping_ctr
;
865 object_count
= ctr6
->object_count
;
866 first_object
= ctr6
->first_object
;
867 linked_attributes_count
= ctr6
->linked_attributes_count
;
868 linked_attributes
= ctr6
->linked_attributes
;
869 rf1
.source_dsa_obj_guid
= ctr6
->source_dsa_guid
;
870 rf1
.source_dsa_invocation_id
= ctr6
->source_dsa_invocation_id
;
871 rf1
.highwatermark
= ctr6
->new_highwatermark
;
872 uptodateness_vector
= ctr6
->uptodateness_vector
;
873 more_data
= ctr6
->more_data
;
876 nt_status
= werror_to_ntstatus(WERR_BAD_NET_RESP
);
877 tevent_req_nterror(req
, nt_status
);
882 * We need to cache the schema changes until we replicated
883 * everything before we can apply the new schema.
885 if (state
->schema_cycle
!= NULL
) {
886 TALLOC_CTX
*mem
= NULL
;
887 struct drsuapi_DsReplicaObjectListItemEx
**ptr
= NULL
;
888 struct drsuapi_DsReplicaObjectListItemEx
*l
= NULL
;
891 sc
= state
->schema_cycle
;
895 if (sc
->first_object
== NULL
) {
897 ptr
= &sc
->first_object
;
899 mem
= sc
->last_object
;
900 ptr
= &sc
->last_object
->next_object
;
902 *ptr
= talloc_move(mem
, &first_object
);
903 for (l
= *ptr
; l
!= NULL
; l
= l
->next_object
) {
905 if (l
->next_object
== NULL
) {
911 if (sc
->linked_attributes_count
== 0) {
912 sc
->linked_attributes
= talloc_move(sc
, &linked_attributes
);
913 sc
->linked_attributes_count
= linked_attributes_count
;
914 linked_attributes_count
= 0;
915 } else if (linked_attributes_count
> 0) {
916 struct drsuapi_DsReplicaLinkedAttribute
*new_las
= NULL
;
917 struct drsuapi_DsReplicaLinkedAttribute
*tmp_las
= NULL
;
922 new_count
= sc
->linked_attributes_count
;
923 new_count
+= linked_attributes_count
;
924 if (new_count
> UINT32_MAX
) {
925 nt_status
= werror_to_ntstatus(WERR_BAD_NET_RESP
);
926 tevent_req_nterror(req
, nt_status
);
929 add_size
= linked_attributes_count
;
930 add_size
*= sizeof(linked_attributes
[0]);
931 if (add_size
> SIZE_MAX
) {
932 nt_status
= werror_to_ntstatus(WERR_BAD_NET_RESP
);
933 tevent_req_nterror(req
, nt_status
);
936 add_idx
= sc
->linked_attributes_count
;
938 tmp_las
= talloc_realloc(sc
,
939 sc
->linked_attributes
,
940 struct drsuapi_DsReplicaLinkedAttribute
,
942 if (tevent_req_nomem(tmp_las
, req
)) {
945 new_las
= talloc_move(tmp_las
, &linked_attributes
);
946 memcpy(&tmp_las
[add_idx
], new_las
, add_size
);
947 sc
->linked_attributes
= tmp_las
;
948 sc
->linked_attributes_count
= new_count
;
949 linked_attributes_count
= 0;
953 /* we don't need this structure anymore */
956 dreplsrv_op_pull_source_get_changes_trigger(req
);
960 /* detach sc from state */
961 state
->schema_cycle
= NULL
;
964 schema
= dsdb_get_schema(service
->samdb
, state
);
966 DEBUG(0,(__location__
": Schema is not loaded yet!\n"));
967 tevent_req_nterror(req
, NT_STATUS_INTERNAL_ERROR
);
972 * Decide what working schema to use for object conversion.
973 * We won't need a working schema for empty replicas sent.
976 first_object
= talloc_move(r
, &sc
->first_object
);
977 object_count
= sc
->object_count
;
978 linked_attributes
= talloc_move(r
, &sc
->linked_attributes
);
979 linked_attributes_count
= sc
->linked_attributes_count
;
982 if (first_object
!= NULL
) {
983 /* create working schema to convert objects with */
984 status
= dsdb_repl_make_working_schema(service
->samdb
,
989 &drsuapi
->gensec_skey
,
990 state
, &working_schema
);
991 if (!W_ERROR_IS_OK(status
)) {
992 DEBUG(0,("Failed to create working schema: %s\n",
993 win_errstr(status
)));
994 tevent_req_nterror(req
, NT_STATUS_INTERNAL_ERROR
);
1000 if (partition
->partial_replica
|| partition
->rodc_replica
) {
1001 dsdb_repl_flags
|= DSDB_REPL_FLAG_PARTIAL_REPLICA
;
1003 if (state
->op
->options
& DRSUAPI_DRS_FULL_SYNC_IN_PROGRESS
) {
1004 dsdb_repl_flags
|= DSDB_REPL_FLAG_PRIORITISE_INCOMING
;
1006 if (state
->op
->options
& DRSUAPI_DRS_SPECIAL_SECRET_PROCESSING
) {
1007 dsdb_repl_flags
|= DSDB_REPL_FLAG_EXPECT_NO_SECRETS
;
1009 if (state
->op
->options
& DRSUAPI_DRS_CRITICAL_ONLY
||
1010 state
->op
->extended_op
!= DRSUAPI_EXOP_NONE
) {
1011 dsdb_repl_flags
|= DSDB_REPL_FLAG_OBJECT_SUBSET
;
1014 if (state
->op
->more_flags
& DRSUAPI_DRS_GET_TGT
) {
1015 dsdb_repl_flags
|= DSDB_REPL_FLAG_TARGETS_UPTODATE
;
1018 if (state
->op
->extended_op
!= DRSUAPI_EXOP_NONE
) {
1019 ret
= dsdb_find_nc_root(service
->samdb
, partition
,
1020 partition
->dn
, &nc_root
);
1021 if (ret
!= LDB_SUCCESS
) {
1022 DEBUG(0,(__location__
": Failed to find nc_root for %s\n",
1023 ldb_dn_get_linearized(partition
->dn
)));
1024 tevent_req_nterror(req
, NT_STATUS_INTERNAL_ERROR
);
1028 nc_root
= partition
->dn
;
1031 status
= dsdb_replicated_objects_convert(service
->samdb
,
1032 working_schema
? working_schema
: schema
,
1037 linked_attributes_count
,
1040 uptodateness_vector
,
1041 &drsuapi
->gensec_skey
,
1045 if (W_ERROR_EQUAL(status
, WERR_DS_DRA_SCHEMA_MISMATCH
)) {
1046 struct dreplsrv_partition
*p
;
1047 struct tevent_req
*subreq
= NULL
;
1050 nt_status
= werror_to_ntstatus(WERR_BAD_NET_RESP
);
1051 DBG_ERR("Got mismatch for schema partition: %s/%s\n",
1052 win_errstr(status
), nt_errstr(nt_status
));
1053 tevent_req_nterror(req
, nt_status
);
1057 if (state
->retry_started
) {
1058 nt_status
= werror_to_ntstatus(WERR_BAD_NET_RESP
);
1059 DEBUG(0,("Failed to convert objects after retry: %s/%s\n",
1060 win_errstr(status
), nt_errstr(nt_status
)));
1061 tevent_req_nterror(req
, nt_status
);
1066 * Change info sync or extended operation into a fetch
1067 * of the schema partition, so we get all the schema
1070 * We don't want to re-do the remote exop,
1071 * unless it was REPL_SECRET so we set the
1072 * fallback operation to just be a fetch of
1073 * the relevant partition.
1077 if (state
->op
->extended_op
== DRSUAPI_EXOP_REPL_SECRET
) {
1078 state
->extended_op_retry
= state
->op
->extended_op
;
1080 state
->extended_op_retry
= DRSUAPI_EXOP_NONE
;
1082 state
->op
->extended_op
= DRSUAPI_EXOP_NONE
;
1084 if (ldb_dn_compare(nc_root
, partition
->dn
) == 0) {
1085 state
->source_dsa_retry
= state
->op
->source_dsa
;
1087 status
= dreplsrv_partition_find_for_nc(service
,
1089 ldb_dn_get_linearized(nc_root
),
1091 if (!W_ERROR_IS_OK(status
)) {
1092 DEBUG(2, ("Failed to find requested Naming Context for %s: %s\n",
1093 ldb_dn_get_linearized(nc_root
),
1094 win_errstr(status
)));
1095 nt_status
= werror_to_ntstatus(status
);
1096 tevent_req_nterror(req
, nt_status
);
1099 status
= dreplsrv_partition_source_dsa_by_guid(p
,
1100 &state
->op
->source_dsa
->repsFrom1
->source_dsa_obj_guid
,
1101 &state
->source_dsa_retry
);
1103 if (!W_ERROR_IS_OK(status
)) {
1104 struct GUID_txt_buf str
;
1105 DEBUG(2, ("Failed to find requested source DSA for %s and %s: %s\n",
1106 ldb_dn_get_linearized(nc_root
),
1107 GUID_buf_string(&state
->op
->source_dsa
->repsFrom1
->source_dsa_obj_guid
, &str
),
1108 win_errstr(status
)));
1109 nt_status
= werror_to_ntstatus(status
);
1110 tevent_req_nterror(req
, nt_status
);
1115 /* Find schema naming context to be synchronized first */
1116 status
= dreplsrv_partition_find_for_nc(service
,
1118 ldb_dn_get_linearized(schema_dn
),
1120 if (!W_ERROR_IS_OK(status
)) {
1121 DEBUG(2, ("Failed to find requested Naming Context for schema: %s\n",
1122 win_errstr(status
)));
1123 nt_status
= werror_to_ntstatus(status
);
1124 tevent_req_nterror(req
, nt_status
);
1128 status
= dreplsrv_partition_source_dsa_by_guid(p
,
1129 &state
->op
->source_dsa
->repsFrom1
->source_dsa_obj_guid
,
1130 &state
->op
->source_dsa
);
1131 if (!W_ERROR_IS_OK(status
)) {
1132 struct GUID_txt_buf str
;
1133 DEBUG(2, ("Failed to find requested source DSA for %s and %s: %s\n",
1134 ldb_dn_get_linearized(schema_dn
),
1135 GUID_buf_string(&state
->op
->source_dsa
->repsFrom1
->source_dsa_obj_guid
, &str
),
1136 win_errstr(status
)));
1137 nt_status
= werror_to_ntstatus(status
);
1138 tevent_req_nterror(req
, nt_status
);
1141 DEBUG(4,("Wrong schema when applying reply GetNCChanges, retrying\n"));
1143 state
->retry_started
= true;
1145 subreq
= dreplsrv_out_drsuapi_send(state
,
1147 state
->op
->source_dsa
->conn
);
1148 if (tevent_req_nomem(subreq
, req
)) {
1151 tevent_req_set_callback(subreq
,
1152 dreplsrv_op_pull_source_connect_done
,
1156 } else if (!W_ERROR_IS_OK(status
)) {
1157 nt_status
= werror_to_ntstatus(WERR_BAD_NET_RESP
);
1158 DEBUG(0,("Failed to convert objects: %s/%s\n",
1159 win_errstr(status
), nt_errstr(nt_status
)));
1160 tevent_req_nterror(req
, nt_status
);
1164 status
= dsdb_replicated_objects_commit(service
->samdb
,
1167 &state
->op
->source_dsa
->notify_uSN
);
1168 talloc_free(objects
);
1170 if (!W_ERROR_IS_OK(status
)) {
1173 * Check if this error can be fixed by resending the GetNCChanges
1174 * request with extra flags set (i.e. GET_ANC/GET_TGT)
1176 nt_status
= dreplsrv_op_pull_retry_with_flags(req
, status
);
1178 if (NT_STATUS_IS_OK(nt_status
)) {
1181 * We resent the request. Don't update the highwatermark,
1182 * we'll start this part of the cycle again.
1187 DEBUG(0,("Failed to commit objects: %s/%s\n",
1188 win_errstr(status
), nt_errstr(nt_status
)));
1189 tevent_req_nterror(req
, nt_status
);
1193 if (state
->op
->extended_op
== DRSUAPI_EXOP_NONE
) {
1194 /* if it applied fine, we need to update the highwatermark */
1195 *state
->op
->source_dsa
->repsFrom1
= rf1
;
1198 /* we don't need this maybe very large structure anymore */
1202 dreplsrv_op_pull_source_get_changes_trigger(req
);
1207 * If we had to divert via doing some other thing, such as
1208 * pulling the schema, then go back and do the original
1209 * operation once we are done.
1211 if (state
->source_dsa_retry
!= NULL
) {
1212 struct tevent_req
*subreq
= NULL
;
1214 state
->op
->source_dsa
= state
->source_dsa_retry
;
1215 state
->op
->extended_op
= state
->extended_op_retry
;
1216 state
->source_dsa_retry
= NULL
;
1218 subreq
= dreplsrv_out_drsuapi_send(state
,
1220 state
->op
->source_dsa
->conn
);
1221 if (tevent_req_nomem(subreq
, req
)) {
1224 tevent_req_set_callback(subreq
,
1225 dreplsrv_op_pull_source_connect_done
,
1230 if (state
->op
->extended_op
!= DRSUAPI_EXOP_NONE
||
1231 state
->op
->service
->am_rodc
) {
1233 we don't do the UpdateRefs for extended ops or if we
1236 tevent_req_done(req
);
1240 /* now we need to update the repsTo record for this partition
1241 on the server. These records are initially established when
1242 we join the domain, but they quickly expire. We do it here
1243 so we can use the already established DRSUAPI pipe
1245 dreplsrv_update_refs_trigger(req
);
1248 static void dreplsrv_update_refs_done(struct tevent_req
*subreq
);
1251 send a UpdateRefs request to refresh our repsTo record on the server
1253 static void dreplsrv_update_refs_trigger(struct tevent_req
*req
)
1255 struct dreplsrv_op_pull_source_state
*state
= tevent_req_data(req
,
1256 struct dreplsrv_op_pull_source_state
);
1257 struct dreplsrv_service
*service
= state
->op
->service
;
1258 struct dreplsrv_partition
*partition
= state
->op
->source_dsa
->partition
;
1259 struct dreplsrv_drsuapi_connection
*drsuapi
= state
->op
->source_dsa
->conn
->drsuapi
;
1260 struct drsuapi_DsReplicaUpdateRefs
*r
;
1261 char *ntds_dns_name
;
1262 struct tevent_req
*subreq
;
1264 r
= talloc(state
, struct drsuapi_DsReplicaUpdateRefs
);
1265 if (tevent_req_nomem(r
, req
)) {
1269 ntds_dns_name
= samdb_ntds_msdcs_dns_name(service
->samdb
, r
, &service
->ntds_guid
);
1270 if (tevent_req_nomem(ntds_dns_name
, req
)) {
1275 r
->in
.bind_handle
= &drsuapi
->bind_handle
;
1277 r
->in
.req
.req1
.naming_context
= &partition
->nc
;
1278 r
->in
.req
.req1
.dest_dsa_dns_name
= ntds_dns_name
;
1279 r
->in
.req
.req1
.dest_dsa_guid
= service
->ntds_guid
;
1280 r
->in
.req
.req1
.options
= DRSUAPI_DRS_ADD_REF
| DRSUAPI_DRS_DEL_REF
;
1281 if (!service
->am_rodc
) {
1282 r
->in
.req
.req1
.options
|= DRSUAPI_DRS_WRIT_REP
;
1285 state
->ndr_struct_ptr
= r
;
1286 subreq
= dcerpc_drsuapi_DsReplicaUpdateRefs_r_send(state
,
1288 drsuapi
->drsuapi_handle
,
1290 if (tevent_req_nomem(subreq
, req
)) {
1294 tevent_req_set_callback(subreq
, dreplsrv_update_refs_done
, req
);
1298 receive a UpdateRefs reply
1300 static void dreplsrv_update_refs_done(struct tevent_req
*subreq
)
1302 struct tevent_req
*req
= tevent_req_callback_data(subreq
,
1304 struct dreplsrv_op_pull_source_state
*state
= tevent_req_data(req
,
1305 struct dreplsrv_op_pull_source_state
);
1306 struct drsuapi_DsReplicaUpdateRefs
*r
= talloc_get_type(state
->ndr_struct_ptr
,
1307 struct drsuapi_DsReplicaUpdateRefs
);
1310 state
->ndr_struct_ptr
= NULL
;
1312 status
= dcerpc_drsuapi_DsReplicaUpdateRefs_r_recv(subreq
, r
);
1313 TALLOC_FREE(subreq
);
1314 if (!NT_STATUS_IS_OK(status
)) {
1315 DEBUG(0,("UpdateRefs failed with %s\n",
1316 nt_errstr(status
)));
1317 tevent_req_nterror(req
, status
);
1321 if (!W_ERROR_IS_OK(r
->out
.result
)) {
1322 status
= werror_to_ntstatus(r
->out
.result
);
1323 DEBUG(0,("UpdateRefs failed with %s/%s for %s %s\n",
1324 win_errstr(r
->out
.result
),
1326 r
->in
.req
.req1
.dest_dsa_dns_name
,
1327 r
->in
.req
.req1
.naming_context
->dn
));
1329 * TODO we are currently not sending the
1330 * DsReplicaUpdateRefs at the correct moment,
1331 * we do it just after a GetNcChanges which is
1332 * not always correct.
1333 * Especially when another DC is trying to demote
1334 * it will sends us a DsReplicaSync that will trigger a getNcChanges
1335 * this call will succeed but the DsRecplicaUpdateRefs that we send
1336 * just after will not because the DC is in a demote state and
1337 * will reply us a WERR_DS_DRA_BUSY, this error will cause us to
1338 * answer to the DsReplicaSync with a non OK status, the other DC
1339 * will stop the demote due to this error.
1340 * In order to cope with this we will for the moment consider
1341 * a DS_DRA_BUSY not as an error.
1342 * It's not ideal but it should not have a too huge impact for
1343 * running production as this error otherwise never happen and
1344 * due to the fact the send a DsReplicaUpdateRefs after each getNcChanges
1346 if (!W_ERROR_EQUAL(r
->out
.result
, WERR_DS_DRA_BUSY
)) {
1347 tevent_req_nterror(req
, status
);
1352 DEBUG(4,("UpdateRefs OK for %s %s\n",
1353 r
->in
.req
.req1
.dest_dsa_dns_name
,
1354 r
->in
.req
.req1
.naming_context
->dn
));
1356 tevent_req_done(req
);
1359 WERROR
dreplsrv_op_pull_source_recv(struct tevent_req
*req
)
1363 if (tevent_req_is_nterror(req
, &status
)) {
1364 tevent_req_received(req
);
1365 return ntstatus_to_werror(status
);
1368 tevent_req_received(req
);