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
&& !state
->drsuapi
->pipe
->conn
->dead
) {
72 return tevent_req_post(req
, ev
);
75 if (state
->drsuapi
&& state
->drsuapi
->pipe
->conn
->dead
) {
76 talloc_free(state
->drsuapi
);
80 state
->drsuapi
= talloc_zero(state
, struct dreplsrv_drsuapi_connection
);
81 if (tevent_req_nomem(state
->drsuapi
, req
)) {
82 return tevent_req_post(req
, ev
);
85 creq
= dcerpc_pipe_connect_b_send(state
, conn
->binding
, &ndr_table_drsuapi
,
86 conn
->service
->system_session_info
->credentials
,
87 ev
, conn
->service
->task
->lp_ctx
);
88 if (tevent_req_nomem(creq
, req
)) {
89 return tevent_req_post(req
, ev
);
91 composite_continue(NULL
, creq
, dreplsrv_out_drsuapi_connect_done
, req
);
96 static void dreplsrv_out_drsuapi_bind_done(struct tevent_req
*subreq
);
98 static void dreplsrv_out_drsuapi_connect_done(struct composite_context
*creq
)
100 struct tevent_req
*req
= talloc_get_type(creq
->async
.private_data
,
102 struct dreplsrv_out_drsuapi_state
*state
= tevent_req_data(req
,
103 struct dreplsrv_out_drsuapi_state
);
105 struct tevent_req
*subreq
;
107 status
= dcerpc_pipe_connect_b_recv(creq
,
109 &state
->drsuapi
->pipe
);
110 if (tevent_req_nterror(req
, status
)) {
114 state
->drsuapi
->drsuapi_handle
= state
->drsuapi
->pipe
->binding_handle
;
116 status
= gensec_session_key(state
->drsuapi
->pipe
->conn
->security_state
.generic_state
,
118 &state
->drsuapi
->gensec_skey
);
119 if (tevent_req_nterror(req
, status
)) {
123 state
->bind_info_ctr
.length
= 28;
124 state
->bind_info_ctr
.info
.info28
= state
->conn
->service
->bind_info28
;
126 state
->bind_r
.in
.bind_guid
= &state
->conn
->service
->ntds_guid
;
127 state
->bind_r
.in
.bind_info
= &state
->bind_info_ctr
;
128 state
->bind_r
.out
.bind_handle
= &state
->drsuapi
->bind_handle
;
130 subreq
= dcerpc_drsuapi_DsBind_r_send(state
,
132 state
->drsuapi
->drsuapi_handle
,
134 if (tevent_req_nomem(subreq
, req
)) {
137 tevent_req_set_callback(subreq
, dreplsrv_out_drsuapi_bind_done
, req
);
140 static void dreplsrv_out_drsuapi_bind_done(struct tevent_req
*subreq
)
142 struct tevent_req
*req
= tevent_req_callback_data(subreq
,
144 struct dreplsrv_out_drsuapi_state
*state
= tevent_req_data(req
,
145 struct dreplsrv_out_drsuapi_state
);
148 status
= dcerpc_drsuapi_DsBind_r_recv(subreq
, state
);
150 if (tevent_req_nterror(req
, status
)) {
154 if (!W_ERROR_IS_OK(state
->bind_r
.out
.result
)) {
155 status
= werror_to_ntstatus(state
->bind_r
.out
.result
);
156 tevent_req_nterror(req
, status
);
160 ZERO_STRUCT(state
->drsuapi
->remote_info28
);
161 if (state
->bind_r
.out
.bind_info
) {
162 struct drsuapi_DsBindInfo28
*info28
;
163 info28
= &state
->drsuapi
->remote_info28
;
165 switch (state
->bind_r
.out
.bind_info
->length
) {
167 struct drsuapi_DsBindInfo24
*info24
;
168 info24
= &state
->bind_r
.out
.bind_info
->info
.info24
;
170 info28
->supported_extensions
= info24
->supported_extensions
;
171 info28
->site_guid
= info24
->site_guid
;
172 info28
->pid
= info24
->pid
;
173 info28
->repl_epoch
= 0;
177 struct drsuapi_DsBindInfo48
*info48
;
178 info48
= &state
->bind_r
.out
.bind_info
->info
.info48
;
180 info28
->supported_extensions
= info48
->supported_extensions
;
181 info28
->site_guid
= info48
->site_guid
;
182 info28
->pid
= info48
->pid
;
183 info28
->repl_epoch
= info48
->repl_epoch
;
187 *info28
= state
->bind_r
.out
.bind_info
->info
.info28
;
192 tevent_req_done(req
);
195 NTSTATUS
dreplsrv_out_drsuapi_recv(struct tevent_req
*req
)
197 struct dreplsrv_out_drsuapi_state
*state
= tevent_req_data(req
,
198 struct dreplsrv_out_drsuapi_state
);
201 if (tevent_req_is_nterror(req
, &status
)) {
202 tevent_req_received(req
);
206 state
->conn
->drsuapi
= talloc_move(state
->conn
, &state
->drsuapi
);
208 tevent_req_received(req
);
212 struct dreplsrv_op_pull_source_state
{
213 struct tevent_context
*ev
;
214 struct dreplsrv_out_operation
*op
;
215 void *ndr_struct_ptr
;
218 static void dreplsrv_op_pull_source_connect_done(struct tevent_req
*subreq
);
220 struct tevent_req
*dreplsrv_op_pull_source_send(TALLOC_CTX
*mem_ctx
,
221 struct tevent_context
*ev
,
222 struct dreplsrv_out_operation
*op
)
224 struct tevent_req
*req
;
225 struct dreplsrv_op_pull_source_state
*state
;
226 struct tevent_req
*subreq
;
228 req
= tevent_req_create(mem_ctx
, &state
,
229 struct dreplsrv_op_pull_source_state
);
236 subreq
= dreplsrv_out_drsuapi_send(state
, ev
, op
->source_dsa
->conn
);
237 if (tevent_req_nomem(subreq
, req
)) {
238 return tevent_req_post(req
, ev
);
240 tevent_req_set_callback(subreq
, dreplsrv_op_pull_source_connect_done
, req
);
245 static void dreplsrv_op_pull_source_get_changes_trigger(struct tevent_req
*req
);
247 static void dreplsrv_op_pull_source_connect_done(struct tevent_req
*subreq
)
249 struct tevent_req
*req
= tevent_req_callback_data(subreq
,
253 status
= dreplsrv_out_drsuapi_recv(subreq
);
255 if (tevent_req_nterror(req
, status
)) {
259 dreplsrv_op_pull_source_get_changes_trigger(req
);
262 static void dreplsrv_op_pull_source_get_changes_done(struct tevent_req
*subreq
);
265 get a RODC partial attribute set for a replication call
267 static NTSTATUS
dreplsrv_get_rodc_partial_attribute_set(struct dreplsrv_service
*service
,
269 struct drsuapi_DsPartialAttributeSet
**_pas
,
272 struct drsuapi_DsPartialAttributeSet
*pas
;
273 struct dsdb_schema
*schema
;
276 pas
= talloc_zero(mem_ctx
, struct drsuapi_DsPartialAttributeSet
);
277 NT_STATUS_HAVE_NO_MEMORY(pas
);
279 schema
= dsdb_get_schema(service
->samdb
, NULL
);
282 pas
->attids
= talloc_array(pas
, enum drsuapi_DsAttributeId
, schema
->num_attributes
);
283 NT_STATUS_HAVE_NO_MEMORY_AND_FREE(pas
->attids
, pas
);
285 for (i
=0; i
<schema
->num_attributes
; i
++) {
286 struct dsdb_attribute
*a
;
287 a
= schema
->attributes_by_attributeID_id
[i
];
288 if (a
->systemFlags
& (DS_FLAG_ATTR_NOT_REPLICATED
| DS_FLAG_ATTR_IS_CONSTRUCTED
)) {
291 if (a
->searchFlags
& SEARCH_FLAG_RODC_ATTRIBUTE
) {
294 pas
->attids
[pas
->num_attids
] = dsdb_attribute_get_attid(a
, for_schema
);
298 pas
->attids
= talloc_realloc(pas
, pas
->attids
, enum drsuapi_DsAttributeId
, pas
->num_attids
);
299 NT_STATUS_HAVE_NO_MEMORY_AND_FREE(pas
->attids
, pas
);
307 get a GC partial attribute set for a replication call
309 static NTSTATUS
dreplsrv_get_gc_partial_attribute_set(struct dreplsrv_service
*service
,
311 struct drsuapi_DsPartialAttributeSet
**_pas
)
313 struct drsuapi_DsPartialAttributeSet
*pas
;
314 struct dsdb_schema
*schema
;
317 pas
= talloc_zero(mem_ctx
, struct drsuapi_DsPartialAttributeSet
);
318 NT_STATUS_HAVE_NO_MEMORY(pas
);
320 schema
= dsdb_get_schema(service
->samdb
, NULL
);
323 pas
->attids
= talloc_array(pas
, enum drsuapi_DsAttributeId
, schema
->num_attributes
);
324 NT_STATUS_HAVE_NO_MEMORY_AND_FREE(pas
->attids
, pas
);
326 for (i
=0; i
<schema
->num_attributes
; i
++) {
327 struct dsdb_attribute
*a
;
328 a
= schema
->attributes_by_attributeID_id
[i
];
329 if (a
->isMemberOfPartialAttributeSet
) {
330 pas
->attids
[pas
->num_attids
] = dsdb_attribute_get_attid(a
, false);
335 pas
->attids
= talloc_realloc(pas
, pas
->attids
, enum drsuapi_DsAttributeId
, pas
->num_attids
);
336 NT_STATUS_HAVE_NO_MEMORY_AND_FREE(pas
->attids
, pas
);
343 convert from one udv format to the other
345 static WERROR
udv_convert(TALLOC_CTX
*mem_ctx
,
346 const struct replUpToDateVectorCtr2
*udv
,
347 struct drsuapi_DsReplicaCursorCtrEx
*udv_ex
)
352 udv_ex
->reserved1
= 0;
353 udv_ex
->reserved2
= 0;
354 udv_ex
->count
= udv
->count
;
355 udv_ex
->cursors
= talloc_array(mem_ctx
, struct drsuapi_DsReplicaCursor
, udv
->count
);
356 W_ERROR_HAVE_NO_MEMORY(udv_ex
->cursors
);
358 for (i
=0; i
<udv
->count
; i
++) {
359 udv_ex
->cursors
[i
].source_dsa_invocation_id
= udv
->cursors
[i
].source_dsa_invocation_id
;
360 udv_ex
->cursors
[i
].highest_usn
= udv
->cursors
[i
].highest_usn
;
367 static void dreplsrv_op_pull_source_get_changes_trigger(struct tevent_req
*req
)
369 struct dreplsrv_op_pull_source_state
*state
= tevent_req_data(req
,
370 struct dreplsrv_op_pull_source_state
);
371 struct repsFromTo1
*rf1
= state
->op
->source_dsa
->repsFrom1
;
372 struct dreplsrv_service
*service
= state
->op
->service
;
373 struct dreplsrv_partition
*partition
= state
->op
->source_dsa
->partition
;
374 struct dreplsrv_drsuapi_connection
*drsuapi
= state
->op
->source_dsa
->conn
->drsuapi
;
375 struct drsuapi_DsGetNCChanges
*r
;
376 struct drsuapi_DsReplicaCursorCtrEx
*uptodateness_vector
;
377 struct tevent_req
*subreq
;
378 struct drsuapi_DsPartialAttributeSet
*pas
= NULL
;
380 uint32_t replica_flags
;
381 struct drsuapi_DsReplicaHighWaterMark highwatermark
;
383 r
= talloc(state
, struct drsuapi_DsGetNCChanges
);
384 if (tevent_req_nomem(r
, req
)) {
388 r
->out
.level_out
= talloc(r
, uint32_t);
389 if (tevent_req_nomem(r
->out
.level_out
, req
)) {
392 r
->in
.req
= talloc(r
, union drsuapi_DsGetNCChangesRequest
);
393 if (tevent_req_nomem(r
->in
.req
, req
)) {
396 r
->out
.ctr
= talloc(r
, union drsuapi_DsGetNCChangesCtr
);
397 if (tevent_req_nomem(r
->out
.ctr
, req
)) {
401 if (partition
->uptodatevector
.count
!= 0 &&
402 partition
->uptodatevector_ex
.count
== 0) {
404 werr
= udv_convert(partition
, &partition
->uptodatevector
, &partition
->uptodatevector_ex
);
405 if (!W_ERROR_IS_OK(werr
)) {
406 DEBUG(0,(__location__
": Failed to convert UDV for %s : %s\n",
407 ldb_dn_get_linearized(partition
->dn
), win_errstr(werr
)));
411 if (partition
->uptodatevector_ex
.count
== 0) {
412 uptodateness_vector
= NULL
;
414 uptodateness_vector
= &partition
->uptodatevector_ex
;
417 replica_flags
= rf1
->replica_flags
;
418 highwatermark
= rf1
->highwatermark
;
420 if (partition
->partial_replica
) {
421 status
= dreplsrv_get_gc_partial_attribute_set(service
, r
, &pas
);
422 if (!NT_STATUS_IS_OK(status
)) {
423 DEBUG(0,(__location__
": Failed to construct GC partial attribute set : %s\n", nt_errstr(status
)));
426 replica_flags
&= ~DRSUAPI_DRS_WRIT_REP
;
427 } else if (partition
->rodc_replica
) {
428 bool for_schema
= false;
429 if (ldb_dn_compare_base(ldb_get_schema_basedn(service
->samdb
), partition
->dn
) == 0) {
433 status
= dreplsrv_get_rodc_partial_attribute_set(service
, r
, &pas
, for_schema
);
434 if (!NT_STATUS_IS_OK(status
)) {
435 DEBUG(0,(__location__
": Failed to construct RODC partial attribute set : %s\n", nt_errstr(status
)));
438 if (state
->op
->extended_op
== DRSUAPI_EXOP_REPL_SECRET
) {
439 replica_flags
&= ~DRSUAPI_DRS_SPECIAL_SECRET_PROCESSING
;
442 if (state
->op
->extended_op
!= DRSUAPI_EXOP_NONE
) {
444 * If it's an exop never set the ADD_REF even if it's in
447 replica_flags
&= ~DRSUAPI_DRS_ADD_REF
;
450 /* is this a full resync of all objects? */
451 if (state
->op
->options
& DRSUAPI_DRS_FULL_SYNC_NOW
) {
452 ZERO_STRUCT(highwatermark
);
453 /* clear the FULL_SYNC_NOW option for subsequent
454 stages of the replication cycle */
455 state
->op
->options
&= ~DRSUAPI_DRS_FULL_SYNC_NOW
;
456 state
->op
->options
|= DRSUAPI_DRS_FULL_SYNC_IN_PROGRESS
;
457 replica_flags
|= DRSUAPI_DRS_NEVER_SYNCED
;
459 if (state
->op
->options
& DRSUAPI_DRS_FULL_SYNC_IN_PROGRESS
) {
460 uptodateness_vector
= NULL
;
463 r
->in
.bind_handle
= &drsuapi
->bind_handle
;
464 if (drsuapi
->remote_info28
.supported_extensions
& DRSUAPI_SUPPORTED_EXTENSION_GETCHGREQ_V8
) {
466 r
->in
.req
->req8
.destination_dsa_guid
= service
->ntds_guid
;
467 r
->in
.req
->req8
.source_dsa_invocation_id
= rf1
->source_dsa_invocation_id
;
468 r
->in
.req
->req8
.naming_context
= &partition
->nc
;
469 r
->in
.req
->req8
.highwatermark
= highwatermark
;
470 r
->in
.req
->req8
.uptodateness_vector
= uptodateness_vector
;
471 r
->in
.req
->req8
.replica_flags
= replica_flags
;
472 r
->in
.req
->req8
.max_object_count
= 133;
473 r
->in
.req
->req8
.max_ndr_size
= 1336811;
474 r
->in
.req
->req8
.extended_op
= state
->op
->extended_op
;
475 r
->in
.req
->req8
.fsmo_info
= state
->op
->fsmo_info
;
476 r
->in
.req
->req8
.partial_attribute_set
= pas
;
477 r
->in
.req
->req8
.partial_attribute_set_ex
= NULL
;
478 r
->in
.req
->req8
.mapping_ctr
.num_mappings
= 0;
479 r
->in
.req
->req8
.mapping_ctr
.mappings
= NULL
;
482 r
->in
.req
->req5
.destination_dsa_guid
= service
->ntds_guid
;
483 r
->in
.req
->req5
.source_dsa_invocation_id
= rf1
->source_dsa_invocation_id
;
484 r
->in
.req
->req5
.naming_context
= &partition
->nc
;
485 r
->in
.req
->req5
.highwatermark
= highwatermark
;
486 r
->in
.req
->req5
.uptodateness_vector
= uptodateness_vector
;
487 r
->in
.req
->req5
.replica_flags
= replica_flags
;
488 r
->in
.req
->req5
.max_object_count
= 133;
489 r
->in
.req
->req5
.max_ndr_size
= 1336770;
490 r
->in
.req
->req5
.extended_op
= state
->op
->extended_op
;
491 r
->in
.req
->req5
.fsmo_info
= state
->op
->fsmo_info
;
495 NDR_PRINT_IN_DEBUG(drsuapi_DsGetNCChanges
, r
);
498 state
->ndr_struct_ptr
= r
;
499 subreq
= dcerpc_drsuapi_DsGetNCChanges_r_send(state
,
501 drsuapi
->drsuapi_handle
,
503 if (tevent_req_nomem(subreq
, req
)) {
506 tevent_req_set_callback(subreq
, dreplsrv_op_pull_source_get_changes_done
, req
);
509 static void dreplsrv_op_pull_source_apply_changes_trigger(struct tevent_req
*req
,
510 struct drsuapi_DsGetNCChanges
*r
,
512 struct drsuapi_DsGetNCChangesCtr1
*ctr1
,
513 struct drsuapi_DsGetNCChangesCtr6
*ctr6
);
515 static void dreplsrv_op_pull_source_get_changes_done(struct tevent_req
*subreq
)
517 struct tevent_req
*req
= tevent_req_callback_data(subreq
,
519 struct dreplsrv_op_pull_source_state
*state
= tevent_req_data(req
,
520 struct dreplsrv_op_pull_source_state
);
522 struct drsuapi_DsGetNCChanges
*r
= talloc_get_type(state
->ndr_struct_ptr
,
523 struct drsuapi_DsGetNCChanges
);
524 uint32_t ctr_level
= 0;
525 struct drsuapi_DsGetNCChangesCtr1
*ctr1
= NULL
;
526 struct drsuapi_DsGetNCChangesCtr6
*ctr6
= NULL
;
527 enum drsuapi_DsExtendedError extended_ret
;
528 state
->ndr_struct_ptr
= NULL
;
530 status
= dcerpc_drsuapi_DsGetNCChanges_r_recv(subreq
, r
);
532 if (tevent_req_nterror(req
, status
)) {
536 if (!W_ERROR_IS_OK(r
->out
.result
)) {
537 status
= werror_to_ntstatus(r
->out
.result
);
538 tevent_req_nterror(req
, status
);
542 if (*r
->out
.level_out
== 1) {
544 ctr1
= &r
->out
.ctr
->ctr1
;
545 } else if (*r
->out
.level_out
== 2 &&
546 r
->out
.ctr
->ctr2
.mszip1
.ts
) {
548 ctr1
= &r
->out
.ctr
->ctr2
.mszip1
.ts
->ctr1
;
549 } else if (*r
->out
.level_out
== 6) {
551 ctr6
= &r
->out
.ctr
->ctr6
;
552 } else if (*r
->out
.level_out
== 7 &&
553 r
->out
.ctr
->ctr7
.level
== 6 &&
554 r
->out
.ctr
->ctr7
.type
== DRSUAPI_COMPRESSION_TYPE_MSZIP
&&
555 r
->out
.ctr
->ctr7
.ctr
.mszip6
.ts
) {
557 ctr6
= &r
->out
.ctr
->ctr7
.ctr
.mszip6
.ts
->ctr6
;
558 } else if (*r
->out
.level_out
== 7 &&
559 r
->out
.ctr
->ctr7
.level
== 6 &&
560 r
->out
.ctr
->ctr7
.type
== DRSUAPI_COMPRESSION_TYPE_XPRESS
&&
561 r
->out
.ctr
->ctr7
.ctr
.xpress6
.ts
) {
563 ctr6
= &r
->out
.ctr
->ctr7
.ctr
.xpress6
.ts
->ctr6
;
565 status
= werror_to_ntstatus(WERR_BAD_NET_RESP
);
566 tevent_req_nterror(req
, status
);
570 if (!ctr1
&& !ctr6
) {
571 status
= werror_to_ntstatus(WERR_BAD_NET_RESP
);
572 tevent_req_nterror(req
, status
);
576 if (ctr_level
== 6) {
577 if (!W_ERROR_IS_OK(ctr6
->drs_error
)) {
578 status
= werror_to_ntstatus(ctr6
->drs_error
);
579 tevent_req_nterror(req
, status
);
582 extended_ret
= ctr6
->extended_ret
;
585 if (ctr_level
== 1) {
586 extended_ret
= ctr1
->extended_ret
;
589 if (state
->op
->extended_op
!= DRSUAPI_EXOP_NONE
) {
590 state
->op
->extended_ret
= extended_ret
;
592 if (extended_ret
!= DRSUAPI_EXOP_ERR_SUCCESS
) {
593 status
= NT_STATUS_UNSUCCESSFUL
;
594 tevent_req_nterror(req
, status
);
599 dreplsrv_op_pull_source_apply_changes_trigger(req
, r
, ctr_level
, ctr1
, ctr6
);
602 static void dreplsrv_update_refs_trigger(struct tevent_req
*req
);
604 static void dreplsrv_op_pull_source_apply_changes_trigger(struct tevent_req
*req
,
605 struct drsuapi_DsGetNCChanges
*r
,
607 struct drsuapi_DsGetNCChangesCtr1
*ctr1
,
608 struct drsuapi_DsGetNCChangesCtr6
*ctr6
)
610 struct dreplsrv_op_pull_source_state
*state
= tevent_req_data(req
,
611 struct dreplsrv_op_pull_source_state
);
612 struct repsFromTo1 rf1
= *state
->op
->source_dsa
->repsFrom1
;
613 struct dreplsrv_service
*service
= state
->op
->service
;
614 struct dreplsrv_partition
*partition
= state
->op
->source_dsa
->partition
;
615 struct dreplsrv_drsuapi_connection
*drsuapi
= state
->op
->source_dsa
->conn
->drsuapi
;
616 struct dsdb_schema
*schema
;
617 struct dsdb_schema
*working_schema
= NULL
;
618 const struct drsuapi_DsReplicaOIDMapping_Ctr
*mapping_ctr
;
619 uint32_t object_count
;
620 struct drsuapi_DsReplicaObjectListItemEx
*first_object
;
621 uint32_t linked_attributes_count
;
622 struct drsuapi_DsReplicaLinkedAttribute
*linked_attributes
;
623 const struct drsuapi_DsReplicaCursor2CtrEx
*uptodateness_vector
;
624 struct dsdb_extended_replicated_objects
*objects
;
625 bool more_data
= false;
628 uint32_t dsdb_repl_flags
= 0;
632 mapping_ctr
= &ctr1
->mapping_ctr
;
633 object_count
= ctr1
->object_count
;
634 first_object
= ctr1
->first_object
;
635 linked_attributes_count
= 0;
636 linked_attributes
= NULL
;
637 rf1
.source_dsa_obj_guid
= ctr1
->source_dsa_guid
;
638 rf1
.source_dsa_invocation_id
= ctr1
->source_dsa_invocation_id
;
639 rf1
.highwatermark
= ctr1
->new_highwatermark
;
640 uptodateness_vector
= NULL
; /* TODO: map it */
641 more_data
= ctr1
->more_data
;
644 mapping_ctr
= &ctr6
->mapping_ctr
;
645 object_count
= ctr6
->object_count
;
646 first_object
= ctr6
->first_object
;
647 linked_attributes_count
= ctr6
->linked_attributes_count
;
648 linked_attributes
= ctr6
->linked_attributes
;
649 rf1
.source_dsa_obj_guid
= ctr6
->source_dsa_guid
;
650 rf1
.source_dsa_invocation_id
= ctr6
->source_dsa_invocation_id
;
651 rf1
.highwatermark
= ctr6
->new_highwatermark
;
652 uptodateness_vector
= ctr6
->uptodateness_vector
;
653 more_data
= ctr6
->more_data
;
656 nt_status
= werror_to_ntstatus(WERR_BAD_NET_RESP
);
657 tevent_req_nterror(req
, nt_status
);
661 schema
= dsdb_get_schema(service
->samdb
, NULL
);
663 DEBUG(0,(__location__
": Schema is not loaded yet!\n"));
664 tevent_req_nterror(req
, NT_STATUS_INTERNAL_ERROR
);
669 * Decide what working schema to use for object conversion.
670 * We won't need a working schema for empty replicas sent.
672 if (first_object
&& ldb_dn_compare(partition
->dn
, schema
->base_dn
) == 0) {
673 /* create working schema to convert objects with */
674 status
= dsdb_repl_make_working_schema(service
->samdb
,
679 &drsuapi
->gensec_skey
,
680 state
, &working_schema
);
681 if (!W_ERROR_IS_OK(status
)) {
682 DEBUG(0,("Failed to create working schema: %s\n",
683 win_errstr(status
)));
684 tevent_req_nterror(req
, NT_STATUS_INTERNAL_ERROR
);
689 if (partition
->partial_replica
|| partition
->rodc_replica
) {
690 dsdb_repl_flags
|= DSDB_REPL_FLAG_PARTIAL_REPLICA
;
692 if (state
->op
->options
& DRSUAPI_DRS_FULL_SYNC_IN_PROGRESS
) {
693 dsdb_repl_flags
|= DSDB_REPL_FLAG_PRIORITISE_INCOMING
;
696 status
= dsdb_replicated_objects_convert(service
->samdb
,
697 working_schema
? working_schema
: schema
,
702 linked_attributes_count
,
706 &drsuapi
->gensec_skey
,
709 if (!W_ERROR_IS_OK(status
)) {
710 nt_status
= werror_to_ntstatus(WERR_BAD_NET_RESP
);
711 DEBUG(0,("Failed to convert objects: %s/%s\n",
712 win_errstr(status
), nt_errstr(nt_status
)));
713 tevent_req_nterror(req
, nt_status
);
717 status
= dsdb_replicated_objects_commit(service
->samdb
,
720 &state
->op
->source_dsa
->notify_uSN
);
721 talloc_free(objects
);
722 if (!W_ERROR_IS_OK(status
)) {
723 nt_status
= werror_to_ntstatus(WERR_BAD_NET_RESP
);
724 DEBUG(0,("Failed to commit objects: %s/%s\n",
725 win_errstr(status
), nt_errstr(nt_status
)));
726 tevent_req_nterror(req
, nt_status
);
730 if (state
->op
->extended_op
== DRSUAPI_EXOP_NONE
) {
731 /* if it applied fine, we need to update the highwatermark */
732 *state
->op
->source_dsa
->repsFrom1
= rf1
;
735 /* we don't need this maybe very large structure anymore */
739 dreplsrv_op_pull_source_get_changes_trigger(req
);
743 if (state
->op
->extended_op
!= DRSUAPI_EXOP_NONE
||
744 state
->op
->service
->am_rodc
) {
746 we don't do the UpdateRefs for extended ops or if we
749 tevent_req_done(req
);
753 /* now we need to update the repsTo record for this partition
754 on the server. These records are initially established when
755 we join the domain, but they quickly expire. We do it here
756 so we can use the already established DRSUAPI pipe
758 dreplsrv_update_refs_trigger(req
);
761 static void dreplsrv_update_refs_done(struct tevent_req
*subreq
);
764 send a UpdateRefs request to refresh our repsTo record on the server
766 static void dreplsrv_update_refs_trigger(struct tevent_req
*req
)
768 struct dreplsrv_op_pull_source_state
*state
= tevent_req_data(req
,
769 struct dreplsrv_op_pull_source_state
);
770 struct dreplsrv_service
*service
= state
->op
->service
;
771 struct dreplsrv_partition
*partition
= state
->op
->source_dsa
->partition
;
772 struct dreplsrv_drsuapi_connection
*drsuapi
= state
->op
->source_dsa
->conn
->drsuapi
;
773 struct drsuapi_DsReplicaUpdateRefs
*r
;
775 struct tevent_req
*subreq
;
777 r
= talloc(state
, struct drsuapi_DsReplicaUpdateRefs
);
778 if (tevent_req_nomem(r
, req
)) {
782 ntds_dns_name
= samdb_ntds_msdcs_dns_name(service
->samdb
, r
, &service
->ntds_guid
);
783 if (tevent_req_nomem(ntds_dns_name
, req
)) {
788 r
->in
.bind_handle
= &drsuapi
->bind_handle
;
790 r
->in
.req
.req1
.naming_context
= &partition
->nc
;
791 r
->in
.req
.req1
.dest_dsa_dns_name
= ntds_dns_name
;
792 r
->in
.req
.req1
.dest_dsa_guid
= service
->ntds_guid
;
793 r
->in
.req
.req1
.options
= DRSUAPI_DRS_ADD_REF
| DRSUAPI_DRS_DEL_REF
;
794 if (!service
->am_rodc
) {
795 r
->in
.req
.req1
.options
|= DRSUAPI_DRS_WRIT_REP
;
798 state
->ndr_struct_ptr
= r
;
799 subreq
= dcerpc_drsuapi_DsReplicaUpdateRefs_r_send(state
,
801 drsuapi
->drsuapi_handle
,
803 if (tevent_req_nomem(subreq
, req
)) {
807 tevent_req_set_callback(subreq
, dreplsrv_update_refs_done
, req
);
811 receive a UpdateRefs reply
813 static void dreplsrv_update_refs_done(struct tevent_req
*subreq
)
815 struct tevent_req
*req
= tevent_req_callback_data(subreq
,
817 struct dreplsrv_op_pull_source_state
*state
= tevent_req_data(req
,
818 struct dreplsrv_op_pull_source_state
);
819 struct drsuapi_DsReplicaUpdateRefs
*r
= talloc_get_type(state
->ndr_struct_ptr
,
820 struct drsuapi_DsReplicaUpdateRefs
);
823 state
->ndr_struct_ptr
= NULL
;
825 status
= dcerpc_drsuapi_DsReplicaUpdateRefs_r_recv(subreq
, r
);
827 if (!NT_STATUS_IS_OK(status
)) {
828 DEBUG(0,("UpdateRefs failed with %s\n",
830 tevent_req_nterror(req
, status
);
834 if (!W_ERROR_IS_OK(r
->out
.result
)) {
835 status
= werror_to_ntstatus(r
->out
.result
);
836 DEBUG(0,("UpdateRefs failed with %s/%s for %s %s\n",
837 win_errstr(r
->out
.result
),
839 r
->in
.req
.req1
.dest_dsa_dns_name
,
840 r
->in
.req
.req1
.naming_context
->dn
));
842 * TODO we are currently not sending the
843 * DsReplicaUpdateRefs at the correct moment,
844 * we do it just after a GetNcChanges which is
845 * not always correct.
846 * Especially when another DC is trying to demote
847 * it will sends us a DsReplicaSync that will trigger a getNcChanges
848 * this call will succeed but the DsRecplicaUpdateRefs that we send
849 * just after will not because the DC is in a demote state and
850 * will reply us a WERR_DS_DRA_BUSY, this error will cause us to
851 * answer to the DsReplicaSync with a non OK status, the other DC
852 * will stop the demote due to this error.
853 * In order to cope with this we will for the moment concider
854 * a DS_DRA_BUSY not as an error.
855 * It's not ideal but it should not have a too huge impact for
856 * running production as this error otherwise never happen and
857 * due to the fact the send a DsReplicaUpdateRefs after each getNcChanges
859 if (!W_ERROR_EQUAL(r
->out
.result
, WERR_DS_DRA_BUSY
)) {
860 tevent_req_nterror(req
, status
);
865 DEBUG(4,("UpdateRefs OK for %s %s\n",
866 r
->in
.req
.req1
.dest_dsa_dns_name
,
867 r
->in
.req
.req1
.naming_context
->dn
));
869 tevent_req_done(req
);
872 WERROR
dreplsrv_op_pull_source_recv(struct tevent_req
*req
)
876 if (tevent_req_is_nterror(req
, &status
)) {
877 tevent_req_received(req
);
878 return ntstatus_to_werror(status
);
881 tevent_req_received(req
);