2 Unix SMB/CIFS mplementation.
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 "smbd/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"
39 struct dreplsrv_out_drsuapi_state
{
40 struct tevent_context
*ev
;
42 struct dreplsrv_out_connection
*conn
;
44 struct dreplsrv_drsuapi_connection
*drsuapi
;
46 struct drsuapi_DsBindInfoCtr bind_info_ctr
;
47 struct drsuapi_DsBind bind_r
;
50 static void dreplsrv_out_drsuapi_connect_done(struct composite_context
*creq
);
52 struct tevent_req
*dreplsrv_out_drsuapi_send(TALLOC_CTX
*mem_ctx
,
53 struct tevent_context
*ev
,
54 struct dreplsrv_out_connection
*conn
)
56 struct tevent_req
*req
;
57 struct dreplsrv_out_drsuapi_state
*state
;
58 struct composite_context
*creq
;
60 req
= tevent_req_create(mem_ctx
, &state
,
61 struct dreplsrv_out_drsuapi_state
);
68 state
->drsuapi
= conn
->drsuapi
;
70 if (state
->drsuapi
!= NULL
) {
71 struct dcerpc_binding_handle
*b
=
72 state
->drsuapi
->pipe
->binding_handle
;
73 bool is_connected
= dcerpc_binding_handle_is_connected(b
);
77 return tevent_req_post(req
, ev
);
80 TALLOC_FREE(conn
->drsuapi
);
83 state
->drsuapi
= talloc_zero(state
, struct dreplsrv_drsuapi_connection
);
84 if (tevent_req_nomem(state
->drsuapi
, req
)) {
85 return tevent_req_post(req
, ev
);
88 creq
= dcerpc_pipe_connect_b_send(state
, conn
->binding
, &ndr_table_drsuapi
,
89 conn
->service
->system_session_info
->credentials
,
90 ev
, conn
->service
->task
->lp_ctx
);
91 if (tevent_req_nomem(creq
, req
)) {
92 return tevent_req_post(req
, ev
);
94 composite_continue(NULL
, creq
, dreplsrv_out_drsuapi_connect_done
, req
);
99 static void dreplsrv_out_drsuapi_bind_done(struct tevent_req
*subreq
);
101 static void dreplsrv_out_drsuapi_connect_done(struct composite_context
*creq
)
103 struct tevent_req
*req
= talloc_get_type(creq
->async
.private_data
,
105 struct dreplsrv_out_drsuapi_state
*state
= tevent_req_data(req
,
106 struct dreplsrv_out_drsuapi_state
);
108 struct tevent_req
*subreq
;
110 status
= dcerpc_pipe_connect_b_recv(creq
,
112 &state
->drsuapi
->pipe
);
113 if (tevent_req_nterror(req
, status
)) {
117 state
->drsuapi
->drsuapi_handle
= state
->drsuapi
->pipe
->binding_handle
;
119 status
= gensec_session_key(state
->drsuapi
->pipe
->conn
->security_state
.generic_state
,
121 &state
->drsuapi
->gensec_skey
);
122 if (tevent_req_nterror(req
, status
)) {
126 state
->bind_info_ctr
.length
= 28;
127 state
->bind_info_ctr
.info
.info28
= state
->conn
->service
->bind_info28
;
129 state
->bind_r
.in
.bind_guid
= &state
->conn
->service
->ntds_guid
;
130 state
->bind_r
.in
.bind_info
= &state
->bind_info_ctr
;
131 state
->bind_r
.out
.bind_handle
= &state
->drsuapi
->bind_handle
;
133 subreq
= dcerpc_drsuapi_DsBind_r_send(state
,
135 state
->drsuapi
->drsuapi_handle
,
137 if (tevent_req_nomem(subreq
, req
)) {
140 tevent_req_set_callback(subreq
, dreplsrv_out_drsuapi_bind_done
, req
);
143 static void dreplsrv_out_drsuapi_bind_done(struct tevent_req
*subreq
)
145 struct tevent_req
*req
= tevent_req_callback_data(subreq
,
147 struct dreplsrv_out_drsuapi_state
*state
= tevent_req_data(req
,
148 struct dreplsrv_out_drsuapi_state
);
151 status
= dcerpc_drsuapi_DsBind_r_recv(subreq
, state
);
153 if (tevent_req_nterror(req
, status
)) {
157 if (!W_ERROR_IS_OK(state
->bind_r
.out
.result
)) {
158 status
= werror_to_ntstatus(state
->bind_r
.out
.result
);
159 tevent_req_nterror(req
, status
);
163 ZERO_STRUCT(state
->drsuapi
->remote_info28
);
164 if (state
->bind_r
.out
.bind_info
) {
165 struct drsuapi_DsBindInfo28
*info28
;
166 info28
= &state
->drsuapi
->remote_info28
;
168 switch (state
->bind_r
.out
.bind_info
->length
) {
170 struct drsuapi_DsBindInfo24
*info24
;
171 info24
= &state
->bind_r
.out
.bind_info
->info
.info24
;
173 info28
->supported_extensions
= info24
->supported_extensions
;
174 info28
->site_guid
= info24
->site_guid
;
175 info28
->pid
= info24
->pid
;
176 info28
->repl_epoch
= 0;
180 struct drsuapi_DsBindInfo48
*info48
;
181 info48
= &state
->bind_r
.out
.bind_info
->info
.info48
;
183 info28
->supported_extensions
= info48
->supported_extensions
;
184 info28
->site_guid
= info48
->site_guid
;
185 info28
->pid
= info48
->pid
;
186 info28
->repl_epoch
= info48
->repl_epoch
;
190 *info28
= state
->bind_r
.out
.bind_info
->info
.info28
;
195 tevent_req_done(req
);
198 NTSTATUS
dreplsrv_out_drsuapi_recv(struct tevent_req
*req
)
200 struct dreplsrv_out_drsuapi_state
*state
= tevent_req_data(req
,
201 struct dreplsrv_out_drsuapi_state
);
204 if (tevent_req_is_nterror(req
, &status
)) {
205 tevent_req_received(req
);
209 state
->conn
->drsuapi
= talloc_move(state
->conn
, &state
->drsuapi
);
211 tevent_req_received(req
);
215 struct dreplsrv_op_pull_source_state
{
216 struct tevent_context
*ev
;
217 struct dreplsrv_out_operation
*op
;
218 void *ndr_struct_ptr
;
221 static void dreplsrv_op_pull_source_connect_done(struct tevent_req
*subreq
);
223 struct tevent_req
*dreplsrv_op_pull_source_send(TALLOC_CTX
*mem_ctx
,
224 struct tevent_context
*ev
,
225 struct dreplsrv_out_operation
*op
)
227 struct tevent_req
*req
;
228 struct dreplsrv_op_pull_source_state
*state
;
229 struct tevent_req
*subreq
;
231 req
= tevent_req_create(mem_ctx
, &state
,
232 struct dreplsrv_op_pull_source_state
);
239 subreq
= dreplsrv_out_drsuapi_send(state
, ev
, op
->source_dsa
->conn
);
240 if (tevent_req_nomem(subreq
, req
)) {
241 return tevent_req_post(req
, ev
);
243 tevent_req_set_callback(subreq
, dreplsrv_op_pull_source_connect_done
, req
);
248 static void dreplsrv_op_pull_source_get_changes_trigger(struct tevent_req
*req
);
250 static void dreplsrv_op_pull_source_connect_done(struct tevent_req
*subreq
)
252 struct tevent_req
*req
= tevent_req_callback_data(subreq
,
256 status
= dreplsrv_out_drsuapi_recv(subreq
);
258 if (tevent_req_nterror(req
, status
)) {
262 dreplsrv_op_pull_source_get_changes_trigger(req
);
265 static void dreplsrv_op_pull_source_get_changes_done(struct tevent_req
*subreq
);
268 get a RODC partial attribute set for a replication call
270 static NTSTATUS
dreplsrv_get_rodc_partial_attribute_set(struct dreplsrv_service
*service
,
272 struct drsuapi_DsPartialAttributeSet
**_pas
,
275 struct drsuapi_DsPartialAttributeSet
*pas
;
276 struct dsdb_schema
*schema
;
279 pas
= talloc_zero(mem_ctx
, struct drsuapi_DsPartialAttributeSet
);
280 NT_STATUS_HAVE_NO_MEMORY(pas
);
282 schema
= dsdb_get_schema(service
->samdb
, NULL
);
285 pas
->attids
= talloc_array(pas
, enum drsuapi_DsAttributeId
, schema
->num_attributes
);
286 if (pas
->attids
== NULL
) {
288 return NT_STATUS_NO_MEMORY
;
291 for (i
=0; i
<schema
->num_attributes
; i
++) {
292 struct dsdb_attribute
*a
;
293 a
= schema
->attributes_by_attributeID_id
[i
];
294 if (a
->systemFlags
& (DS_FLAG_ATTR_NOT_REPLICATED
| DS_FLAG_ATTR_IS_CONSTRUCTED
)) {
297 if (a
->searchFlags
& SEARCH_FLAG_RODC_ATTRIBUTE
) {
300 pas
->attids
[pas
->num_attids
] = dsdb_attribute_get_attid(a
, for_schema
);
304 pas
->attids
= talloc_realloc(pas
, pas
->attids
, enum drsuapi_DsAttributeId
, pas
->num_attids
);
305 if (pas
->attids
== NULL
) {
307 return NT_STATUS_NO_MEMORY
;
316 get a GC partial attribute set for a replication call
318 static NTSTATUS
dreplsrv_get_gc_partial_attribute_set(struct dreplsrv_service
*service
,
320 struct drsuapi_DsPartialAttributeSet
**_pas
)
322 struct drsuapi_DsPartialAttributeSet
*pas
;
323 struct dsdb_schema
*schema
;
326 pas
= talloc_zero(mem_ctx
, struct drsuapi_DsPartialAttributeSet
);
327 NT_STATUS_HAVE_NO_MEMORY(pas
);
329 schema
= dsdb_get_schema(service
->samdb
, NULL
);
332 pas
->attids
= talloc_array(pas
, enum drsuapi_DsAttributeId
, schema
->num_attributes
);
333 if (pas
->attids
== NULL
) {
335 return NT_STATUS_NO_MEMORY
;
338 for (i
=0; i
<schema
->num_attributes
; i
++) {
339 struct dsdb_attribute
*a
;
340 a
= schema
->attributes_by_attributeID_id
[i
];
341 if (a
->isMemberOfPartialAttributeSet
) {
342 pas
->attids
[pas
->num_attids
] = dsdb_attribute_get_attid(a
, false);
347 pas
->attids
= talloc_realloc(pas
, pas
->attids
, enum drsuapi_DsAttributeId
, pas
->num_attids
);
348 if (pas
->attids
== NULL
) {
350 return NT_STATUS_NO_MEMORY
;
358 convert from one udv format to the other
360 static WERROR
udv_convert(TALLOC_CTX
*mem_ctx
,
361 const struct replUpToDateVectorCtr2
*udv
,
362 struct drsuapi_DsReplicaCursorCtrEx
*udv_ex
)
367 udv_ex
->reserved1
= 0;
368 udv_ex
->reserved2
= 0;
369 udv_ex
->count
= udv
->count
;
370 udv_ex
->cursors
= talloc_array(mem_ctx
, struct drsuapi_DsReplicaCursor
, udv
->count
);
371 W_ERROR_HAVE_NO_MEMORY(udv_ex
->cursors
);
373 for (i
=0; i
<udv
->count
; i
++) {
374 udv_ex
->cursors
[i
].source_dsa_invocation_id
= udv
->cursors
[i
].source_dsa_invocation_id
;
375 udv_ex
->cursors
[i
].highest_usn
= udv
->cursors
[i
].highest_usn
;
382 static void dreplsrv_op_pull_source_get_changes_trigger(struct tevent_req
*req
)
384 struct dreplsrv_op_pull_source_state
*state
= tevent_req_data(req
,
385 struct dreplsrv_op_pull_source_state
);
386 struct repsFromTo1
*rf1
= state
->op
->source_dsa
->repsFrom1
;
387 struct dreplsrv_service
*service
= state
->op
->service
;
388 struct dreplsrv_partition
*partition
= state
->op
->source_dsa
->partition
;
389 struct dreplsrv_drsuapi_connection
*drsuapi
= state
->op
->source_dsa
->conn
->drsuapi
;
390 struct drsuapi_DsGetNCChanges
*r
;
391 struct drsuapi_DsReplicaCursorCtrEx
*uptodateness_vector
;
392 struct tevent_req
*subreq
;
393 struct drsuapi_DsPartialAttributeSet
*pas
= NULL
;
395 uint32_t replica_flags
;
396 struct drsuapi_DsReplicaHighWaterMark highwatermark
;
397 struct ldb_dn
*schema_dn
= ldb_get_schema_basedn(service
->samdb
);
399 r
= talloc(state
, struct drsuapi_DsGetNCChanges
);
400 if (tevent_req_nomem(r
, req
)) {
404 r
->out
.level_out
= talloc(r
, uint32_t);
405 if (tevent_req_nomem(r
->out
.level_out
, req
)) {
408 r
->in
.req
= talloc(r
, union drsuapi_DsGetNCChangesRequest
);
409 if (tevent_req_nomem(r
->in
.req
, req
)) {
412 r
->out
.ctr
= talloc(r
, union drsuapi_DsGetNCChangesCtr
);
413 if (tevent_req_nomem(r
->out
.ctr
, req
)) {
417 if (partition
->uptodatevector
.count
!= 0 &&
418 partition
->uptodatevector_ex
.count
== 0) {
420 werr
= udv_convert(partition
, &partition
->uptodatevector
, &partition
->uptodatevector_ex
);
421 if (!W_ERROR_IS_OK(werr
)) {
422 DEBUG(0,(__location__
": Failed to convert UDV for %s : %s\n",
423 ldb_dn_get_linearized(partition
->dn
), win_errstr(werr
)));
427 if (partition
->uptodatevector_ex
.count
== 0) {
428 uptodateness_vector
= NULL
;
430 uptodateness_vector
= &partition
->uptodatevector_ex
;
433 replica_flags
= rf1
->replica_flags
;
434 highwatermark
= rf1
->highwatermark
;
436 if (partition
->partial_replica
) {
437 status
= dreplsrv_get_gc_partial_attribute_set(service
, r
, &pas
);
438 if (!NT_STATUS_IS_OK(status
)) {
439 DEBUG(0,(__location__
": Failed to construct GC partial attribute set : %s\n", nt_errstr(status
)));
442 replica_flags
&= ~DRSUAPI_DRS_WRIT_REP
;
443 } else if (partition
->rodc_replica
) {
444 bool for_schema
= false;
445 if (ldb_dn_compare_base(schema_dn
, partition
->dn
) == 0) {
449 status
= dreplsrv_get_rodc_partial_attribute_set(service
, r
, &pas
, for_schema
);
450 if (!NT_STATUS_IS_OK(status
)) {
451 DEBUG(0,(__location__
": Failed to construct RODC partial attribute set : %s\n", nt_errstr(status
)));
454 if (state
->op
->extended_op
== DRSUAPI_EXOP_REPL_SECRET
) {
455 replica_flags
&= ~DRSUAPI_DRS_SPECIAL_SECRET_PROCESSING
;
458 if (state
->op
->extended_op
!= DRSUAPI_EXOP_NONE
) {
460 * If it's an exop never set the ADD_REF even if it's in
463 replica_flags
&= ~DRSUAPI_DRS_ADD_REF
;
466 /* is this a full resync of all objects? */
467 if (state
->op
->options
& DRSUAPI_DRS_FULL_SYNC_NOW
) {
468 ZERO_STRUCT(highwatermark
);
469 /* clear the FULL_SYNC_NOW option for subsequent
470 stages of the replication cycle */
471 state
->op
->options
&= ~DRSUAPI_DRS_FULL_SYNC_NOW
;
472 state
->op
->options
|= DRSUAPI_DRS_FULL_SYNC_IN_PROGRESS
;
473 replica_flags
|= DRSUAPI_DRS_NEVER_SYNCED
;
475 if (state
->op
->options
& DRSUAPI_DRS_FULL_SYNC_IN_PROGRESS
) {
476 uptodateness_vector
= NULL
;
479 r
->in
.bind_handle
= &drsuapi
->bind_handle
;
480 if (drsuapi
->remote_info28
.supported_extensions
& DRSUAPI_SUPPORTED_EXTENSION_GETCHGREQ_V8
) {
482 r
->in
.req
->req8
.destination_dsa_guid
= service
->ntds_guid
;
483 r
->in
.req
->req8
.source_dsa_invocation_id
= rf1
->source_dsa_invocation_id
;
484 r
->in
.req
->req8
.naming_context
= &partition
->nc
;
485 r
->in
.req
->req8
.highwatermark
= highwatermark
;
486 r
->in
.req
->req8
.uptodateness_vector
= uptodateness_vector
;
487 r
->in
.req
->req8
.replica_flags
= replica_flags
;
488 r
->in
.req
->req8
.max_object_count
= 133;
489 r
->in
.req
->req8
.max_ndr_size
= 1336811;
490 r
->in
.req
->req8
.extended_op
= state
->op
->extended_op
;
491 r
->in
.req
->req8
.fsmo_info
= state
->op
->fsmo_info
;
492 r
->in
.req
->req8
.partial_attribute_set
= pas
;
493 r
->in
.req
->req8
.partial_attribute_set_ex
= NULL
;
494 r
->in
.req
->req8
.mapping_ctr
.num_mappings
= 0;
495 r
->in
.req
->req8
.mapping_ctr
.mappings
= NULL
;
498 r
->in
.req
->req5
.destination_dsa_guid
= service
->ntds_guid
;
499 r
->in
.req
->req5
.source_dsa_invocation_id
= rf1
->source_dsa_invocation_id
;
500 r
->in
.req
->req5
.naming_context
= &partition
->nc
;
501 r
->in
.req
->req5
.highwatermark
= highwatermark
;
502 r
->in
.req
->req5
.uptodateness_vector
= uptodateness_vector
;
503 r
->in
.req
->req5
.replica_flags
= replica_flags
;
504 r
->in
.req
->req5
.max_object_count
= 133;
505 r
->in
.req
->req5
.max_ndr_size
= 1336770;
506 r
->in
.req
->req5
.extended_op
= state
->op
->extended_op
;
507 r
->in
.req
->req5
.fsmo_info
= state
->op
->fsmo_info
;
511 NDR_PRINT_IN_DEBUG(drsuapi_DsGetNCChanges
, r
);
514 state
->ndr_struct_ptr
= r
;
515 subreq
= dcerpc_drsuapi_DsGetNCChanges_r_send(state
,
517 drsuapi
->drsuapi_handle
,
519 if (tevent_req_nomem(subreq
, req
)) {
522 tevent_req_set_callback(subreq
, dreplsrv_op_pull_source_get_changes_done
, req
);
525 static void dreplsrv_op_pull_source_apply_changes_trigger(struct tevent_req
*req
,
526 struct drsuapi_DsGetNCChanges
*r
,
528 struct drsuapi_DsGetNCChangesCtr1
*ctr1
,
529 struct drsuapi_DsGetNCChangesCtr6
*ctr6
);
531 static void dreplsrv_op_pull_source_get_changes_done(struct tevent_req
*subreq
)
533 struct tevent_req
*req
= tevent_req_callback_data(subreq
,
535 struct dreplsrv_op_pull_source_state
*state
= tevent_req_data(req
,
536 struct dreplsrv_op_pull_source_state
);
538 struct drsuapi_DsGetNCChanges
*r
= talloc_get_type(state
->ndr_struct_ptr
,
539 struct drsuapi_DsGetNCChanges
);
540 uint32_t ctr_level
= 0;
541 struct drsuapi_DsGetNCChangesCtr1
*ctr1
= NULL
;
542 struct drsuapi_DsGetNCChangesCtr6
*ctr6
= NULL
;
543 enum drsuapi_DsExtendedError extended_ret
;
544 state
->ndr_struct_ptr
= NULL
;
546 status
= dcerpc_drsuapi_DsGetNCChanges_r_recv(subreq
, r
);
548 if (tevent_req_nterror(req
, status
)) {
552 if (!W_ERROR_IS_OK(r
->out
.result
)) {
553 status
= werror_to_ntstatus(r
->out
.result
);
554 tevent_req_nterror(req
, status
);
558 if (*r
->out
.level_out
== 1) {
560 ctr1
= &r
->out
.ctr
->ctr1
;
561 } else if (*r
->out
.level_out
== 2 &&
562 r
->out
.ctr
->ctr2
.mszip1
.ts
) {
564 ctr1
= &r
->out
.ctr
->ctr2
.mszip1
.ts
->ctr1
;
565 } else if (*r
->out
.level_out
== 6) {
567 ctr6
= &r
->out
.ctr
->ctr6
;
568 } else if (*r
->out
.level_out
== 7 &&
569 r
->out
.ctr
->ctr7
.level
== 6 &&
570 r
->out
.ctr
->ctr7
.type
== DRSUAPI_COMPRESSION_TYPE_MSZIP
&&
571 r
->out
.ctr
->ctr7
.ctr
.mszip6
.ts
) {
573 ctr6
= &r
->out
.ctr
->ctr7
.ctr
.mszip6
.ts
->ctr6
;
574 } else if (*r
->out
.level_out
== 7 &&
575 r
->out
.ctr
->ctr7
.level
== 6 &&
576 r
->out
.ctr
->ctr7
.type
== DRSUAPI_COMPRESSION_TYPE_XPRESS
&&
577 r
->out
.ctr
->ctr7
.ctr
.xpress6
.ts
) {
579 ctr6
= &r
->out
.ctr
->ctr7
.ctr
.xpress6
.ts
->ctr6
;
581 status
= werror_to_ntstatus(WERR_BAD_NET_RESP
);
582 tevent_req_nterror(req
, status
);
586 if (!ctr1
&& !ctr6
) {
587 status
= werror_to_ntstatus(WERR_BAD_NET_RESP
);
588 tevent_req_nterror(req
, status
);
592 if (ctr_level
== 6) {
593 if (!W_ERROR_IS_OK(ctr6
->drs_error
)) {
594 status
= werror_to_ntstatus(ctr6
->drs_error
);
595 tevent_req_nterror(req
, status
);
598 extended_ret
= ctr6
->extended_ret
;
601 if (ctr_level
== 1) {
602 extended_ret
= ctr1
->extended_ret
;
605 if (state
->op
->extended_op
!= DRSUAPI_EXOP_NONE
) {
606 state
->op
->extended_ret
= extended_ret
;
608 if (extended_ret
!= DRSUAPI_EXOP_ERR_SUCCESS
) {
609 status
= NT_STATUS_UNSUCCESSFUL
;
610 tevent_req_nterror(req
, status
);
615 dreplsrv_op_pull_source_apply_changes_trigger(req
, r
, ctr_level
, ctr1
, ctr6
);
618 static void dreplsrv_update_refs_trigger(struct tevent_req
*req
);
620 static void dreplsrv_op_pull_source_apply_changes_trigger(struct tevent_req
*req
,
621 struct drsuapi_DsGetNCChanges
*r
,
623 struct drsuapi_DsGetNCChangesCtr1
*ctr1
,
624 struct drsuapi_DsGetNCChangesCtr6
*ctr6
)
626 struct dreplsrv_op_pull_source_state
*state
= tevent_req_data(req
,
627 struct dreplsrv_op_pull_source_state
);
628 struct repsFromTo1 rf1
= *state
->op
->source_dsa
->repsFrom1
;
629 struct dreplsrv_service
*service
= state
->op
->service
;
630 struct dreplsrv_partition
*partition
= state
->op
->source_dsa
->partition
;
631 struct dreplsrv_drsuapi_connection
*drsuapi
= state
->op
->source_dsa
->conn
->drsuapi
;
632 struct ldb_dn
*schema_dn
= ldb_get_schema_basedn(service
->samdb
);
633 struct dsdb_schema
*schema
;
634 struct dsdb_schema
*working_schema
= NULL
;
635 const struct drsuapi_DsReplicaOIDMapping_Ctr
*mapping_ctr
;
636 uint32_t object_count
;
637 struct drsuapi_DsReplicaObjectListItemEx
*first_object
;
638 uint32_t linked_attributes_count
;
639 struct drsuapi_DsReplicaLinkedAttribute
*linked_attributes
;
640 const struct drsuapi_DsReplicaCursor2CtrEx
*uptodateness_vector
;
641 struct dsdb_extended_replicated_objects
*objects
;
642 bool more_data
= false;
645 uint32_t dsdb_repl_flags
= 0;
649 mapping_ctr
= &ctr1
->mapping_ctr
;
650 object_count
= ctr1
->object_count
;
651 first_object
= ctr1
->first_object
;
652 linked_attributes_count
= 0;
653 linked_attributes
= NULL
;
654 rf1
.source_dsa_obj_guid
= ctr1
->source_dsa_guid
;
655 rf1
.source_dsa_invocation_id
= ctr1
->source_dsa_invocation_id
;
656 rf1
.highwatermark
= ctr1
->new_highwatermark
;
657 uptodateness_vector
= NULL
; /* TODO: map it */
658 more_data
= ctr1
->more_data
;
661 mapping_ctr
= &ctr6
->mapping_ctr
;
662 object_count
= ctr6
->object_count
;
663 first_object
= ctr6
->first_object
;
664 linked_attributes_count
= ctr6
->linked_attributes_count
;
665 linked_attributes
= ctr6
->linked_attributes
;
666 rf1
.source_dsa_obj_guid
= ctr6
->source_dsa_guid
;
667 rf1
.source_dsa_invocation_id
= ctr6
->source_dsa_invocation_id
;
668 rf1
.highwatermark
= ctr6
->new_highwatermark
;
669 uptodateness_vector
= ctr6
->uptodateness_vector
;
670 more_data
= ctr6
->more_data
;
673 nt_status
= werror_to_ntstatus(WERR_BAD_NET_RESP
);
674 tevent_req_nterror(req
, nt_status
);
678 schema
= dsdb_get_schema(service
->samdb
, NULL
);
680 DEBUG(0,(__location__
": Schema is not loaded yet!\n"));
681 tevent_req_nterror(req
, NT_STATUS_INTERNAL_ERROR
);
686 * Decide what working schema to use for object conversion.
687 * We won't need a working schema for empty replicas sent.
690 bool is_schema
= ldb_dn_compare(partition
->dn
, schema_dn
) == 0;
692 /* create working schema to convert objects with */
693 status
= dsdb_repl_make_working_schema(service
->samdb
,
698 &drsuapi
->gensec_skey
,
699 state
, &working_schema
);
700 if (!W_ERROR_IS_OK(status
)) {
701 DEBUG(0,("Failed to create working schema: %s\n",
702 win_errstr(status
)));
703 tevent_req_nterror(req
, NT_STATUS_INTERNAL_ERROR
);
709 if (partition
->partial_replica
|| partition
->rodc_replica
) {
710 dsdb_repl_flags
|= DSDB_REPL_FLAG_PARTIAL_REPLICA
;
712 if (state
->op
->options
& DRSUAPI_DRS_FULL_SYNC_IN_PROGRESS
) {
713 dsdb_repl_flags
|= DSDB_REPL_FLAG_PRIORITISE_INCOMING
;
716 status
= dsdb_replicated_objects_convert(service
->samdb
,
717 working_schema
? working_schema
: schema
,
722 linked_attributes_count
,
726 &drsuapi
->gensec_skey
,
729 if (!W_ERROR_IS_OK(status
)) {
730 nt_status
= werror_to_ntstatus(WERR_BAD_NET_RESP
);
731 DEBUG(0,("Failed to convert objects: %s/%s\n",
732 win_errstr(status
), nt_errstr(nt_status
)));
733 tevent_req_nterror(req
, nt_status
);
737 status
= dsdb_replicated_objects_commit(service
->samdb
,
740 &state
->op
->source_dsa
->notify_uSN
);
741 talloc_free(objects
);
742 if (!W_ERROR_IS_OK(status
)) {
743 nt_status
= werror_to_ntstatus(WERR_BAD_NET_RESP
);
744 DEBUG(0,("Failed to commit objects: %s/%s\n",
745 win_errstr(status
), nt_errstr(nt_status
)));
746 tevent_req_nterror(req
, nt_status
);
750 if (state
->op
->extended_op
== DRSUAPI_EXOP_NONE
) {
751 /* if it applied fine, we need to update the highwatermark */
752 *state
->op
->source_dsa
->repsFrom1
= rf1
;
755 /* we don't need this maybe very large structure anymore */
759 dreplsrv_op_pull_source_get_changes_trigger(req
);
763 if (state
->op
->extended_op
!= DRSUAPI_EXOP_NONE
||
764 state
->op
->service
->am_rodc
) {
766 we don't do the UpdateRefs for extended ops or if we
769 tevent_req_done(req
);
773 /* now we need to update the repsTo record for this partition
774 on the server. These records are initially established when
775 we join the domain, but they quickly expire. We do it here
776 so we can use the already established DRSUAPI pipe
778 dreplsrv_update_refs_trigger(req
);
781 static void dreplsrv_update_refs_done(struct tevent_req
*subreq
);
784 send a UpdateRefs request to refresh our repsTo record on the server
786 static void dreplsrv_update_refs_trigger(struct tevent_req
*req
)
788 struct dreplsrv_op_pull_source_state
*state
= tevent_req_data(req
,
789 struct dreplsrv_op_pull_source_state
);
790 struct dreplsrv_service
*service
= state
->op
->service
;
791 struct dreplsrv_partition
*partition
= state
->op
->source_dsa
->partition
;
792 struct dreplsrv_drsuapi_connection
*drsuapi
= state
->op
->source_dsa
->conn
->drsuapi
;
793 struct drsuapi_DsReplicaUpdateRefs
*r
;
795 struct tevent_req
*subreq
;
797 r
= talloc(state
, struct drsuapi_DsReplicaUpdateRefs
);
798 if (tevent_req_nomem(r
, req
)) {
802 ntds_dns_name
= samdb_ntds_msdcs_dns_name(service
->samdb
, r
, &service
->ntds_guid
);
803 if (tevent_req_nomem(ntds_dns_name
, req
)) {
808 r
->in
.bind_handle
= &drsuapi
->bind_handle
;
810 r
->in
.req
.req1
.naming_context
= &partition
->nc
;
811 r
->in
.req
.req1
.dest_dsa_dns_name
= ntds_dns_name
;
812 r
->in
.req
.req1
.dest_dsa_guid
= service
->ntds_guid
;
813 r
->in
.req
.req1
.options
= DRSUAPI_DRS_ADD_REF
| DRSUAPI_DRS_DEL_REF
;
814 if (!service
->am_rodc
) {
815 r
->in
.req
.req1
.options
|= DRSUAPI_DRS_WRIT_REP
;
818 state
->ndr_struct_ptr
= r
;
819 subreq
= dcerpc_drsuapi_DsReplicaUpdateRefs_r_send(state
,
821 drsuapi
->drsuapi_handle
,
823 if (tevent_req_nomem(subreq
, req
)) {
827 tevent_req_set_callback(subreq
, dreplsrv_update_refs_done
, req
);
831 receive a UpdateRefs reply
833 static void dreplsrv_update_refs_done(struct tevent_req
*subreq
)
835 struct tevent_req
*req
= tevent_req_callback_data(subreq
,
837 struct dreplsrv_op_pull_source_state
*state
= tevent_req_data(req
,
838 struct dreplsrv_op_pull_source_state
);
839 struct drsuapi_DsReplicaUpdateRefs
*r
= talloc_get_type(state
->ndr_struct_ptr
,
840 struct drsuapi_DsReplicaUpdateRefs
);
843 state
->ndr_struct_ptr
= NULL
;
845 status
= dcerpc_drsuapi_DsReplicaUpdateRefs_r_recv(subreq
, r
);
847 if (!NT_STATUS_IS_OK(status
)) {
848 DEBUG(0,("UpdateRefs failed with %s\n",
850 tevent_req_nterror(req
, status
);
854 if (!W_ERROR_IS_OK(r
->out
.result
)) {
855 status
= werror_to_ntstatus(r
->out
.result
);
856 DEBUG(0,("UpdateRefs failed with %s/%s for %s %s\n",
857 win_errstr(r
->out
.result
),
859 r
->in
.req
.req1
.dest_dsa_dns_name
,
860 r
->in
.req
.req1
.naming_context
->dn
));
862 * TODO we are currently not sending the
863 * DsReplicaUpdateRefs at the correct moment,
864 * we do it just after a GetNcChanges which is
865 * not always correct.
866 * Especially when another DC is trying to demote
867 * it will sends us a DsReplicaSync that will trigger a getNcChanges
868 * this call will succeed but the DsRecplicaUpdateRefs that we send
869 * just after will not because the DC is in a demote state and
870 * will reply us a WERR_DS_DRA_BUSY, this error will cause us to
871 * answer to the DsReplicaSync with a non OK status, the other DC
872 * will stop the demote due to this error.
873 * In order to cope with this we will for the moment concider
874 * a DS_DRA_BUSY not as an error.
875 * It's not ideal but it should not have a too huge impact for
876 * running production as this error otherwise never happen and
877 * due to the fact the send a DsReplicaUpdateRefs after each getNcChanges
879 if (!W_ERROR_EQUAL(r
->out
.result
, WERR_DS_DRA_BUSY
)) {
880 tevent_req_nterror(req
, status
);
885 DEBUG(4,("UpdateRefs OK for %s %s\n",
886 r
->in
.req
.req1
.dest_dsa_dns_name
,
887 r
->in
.req
.req1
.naming_context
->dn
));
889 tevent_req_done(req
);
892 WERROR
dreplsrv_op_pull_source_recv(struct tevent_req
*req
)
896 if (tevent_req_is_nterror(req
, &status
)) {
897 tevent_req_received(req
);
898 return ntstatus_to_werror(status
);
901 tevent_req_received(req
);