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 "lib/ldb/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"
38 struct dreplsrv_out_drsuapi_state
{
39 struct tevent_context
*ev
;
41 struct dreplsrv_out_connection
*conn
;
43 struct dreplsrv_drsuapi_connection
*drsuapi
;
45 struct drsuapi_DsBindInfoCtr bind_info_ctr
;
46 struct drsuapi_DsBind bind_r
;
49 static void dreplsrv_out_drsuapi_connect_done(struct composite_context
*creq
);
51 struct tevent_req
*dreplsrv_out_drsuapi_send(TALLOC_CTX
*mem_ctx
,
52 struct tevent_context
*ev
,
53 struct dreplsrv_out_connection
*conn
)
55 struct tevent_req
*req
;
56 struct dreplsrv_out_drsuapi_state
*state
;
57 struct composite_context
*creq
;
59 req
= tevent_req_create(mem_ctx
, &state
,
60 struct dreplsrv_out_drsuapi_state
);
67 state
->drsuapi
= conn
->drsuapi
;
69 if (state
->drsuapi
&& !state
->drsuapi
->pipe
->conn
->dead
) {
71 return tevent_req_post(req
, ev
);
74 if (state
->drsuapi
&& state
->drsuapi
->pipe
->conn
->dead
) {
75 talloc_free(state
->drsuapi
);
79 state
->drsuapi
= talloc_zero(state
, struct dreplsrv_drsuapi_connection
);
80 if (tevent_req_nomem(state
->drsuapi
, req
)) {
81 return tevent_req_post(req
, ev
);
84 creq
= dcerpc_pipe_connect_b_send(state
, conn
->binding
, &ndr_table_drsuapi
,
85 conn
->service
->system_session_info
->credentials
,
86 ev
, conn
->service
->task
->lp_ctx
);
87 if (tevent_req_nomem(creq
, req
)) {
88 return tevent_req_post(req
, ev
);
90 composite_continue(NULL
, creq
, dreplsrv_out_drsuapi_connect_done
, req
);
95 static void dreplsrv_out_drsuapi_bind_done(struct tevent_req
*subreq
);
97 static void dreplsrv_out_drsuapi_connect_done(struct composite_context
*creq
)
99 struct tevent_req
*req
= talloc_get_type(creq
->async
.private_data
,
101 struct dreplsrv_out_drsuapi_state
*state
= tevent_req_data(req
,
102 struct dreplsrv_out_drsuapi_state
);
104 struct tevent_req
*subreq
;
106 status
= dcerpc_pipe_connect_b_recv(creq
,
108 &state
->drsuapi
->pipe
);
109 if (tevent_req_nterror(req
, status
)) {
113 state
->drsuapi
->drsuapi_handle
= state
->drsuapi
->pipe
->binding_handle
;
115 status
= gensec_session_key(state
->drsuapi
->pipe
->conn
->security_state
.generic_state
,
116 &state
->drsuapi
->gensec_skey
);
117 if (tevent_req_nterror(req
, status
)) {
121 state
->bind_info_ctr
.length
= 28;
122 state
->bind_info_ctr
.info
.info28
= state
->conn
->service
->bind_info28
;
124 state
->bind_r
.in
.bind_guid
= &state
->conn
->service
->ntds_guid
;
125 state
->bind_r
.in
.bind_info
= &state
->bind_info_ctr
;
126 state
->bind_r
.out
.bind_handle
= &state
->drsuapi
->bind_handle
;
128 subreq
= dcerpc_drsuapi_DsBind_r_send(state
,
130 state
->drsuapi
->drsuapi_handle
,
132 if (tevent_req_nomem(subreq
, req
)) {
135 tevent_req_set_callback(subreq
, dreplsrv_out_drsuapi_bind_done
, req
);
138 static void dreplsrv_out_drsuapi_bind_done(struct tevent_req
*subreq
)
140 struct tevent_req
*req
= tevent_req_callback_data(subreq
,
142 struct dreplsrv_out_drsuapi_state
*state
= tevent_req_data(req
,
143 struct dreplsrv_out_drsuapi_state
);
146 status
= dcerpc_drsuapi_DsBind_r_recv(subreq
, state
);
148 if (tevent_req_nterror(req
, status
)) {
152 if (!W_ERROR_IS_OK(state
->bind_r
.out
.result
)) {
153 status
= werror_to_ntstatus(state
->bind_r
.out
.result
);
154 tevent_req_nterror(req
, status
);
158 ZERO_STRUCT(state
->drsuapi
->remote_info28
);
159 if (state
->bind_r
.out
.bind_info
) {
160 struct drsuapi_DsBindInfo28
*info28
;
161 info28
= &state
->drsuapi
->remote_info28
;
163 switch (state
->bind_r
.out
.bind_info
->length
) {
165 struct drsuapi_DsBindInfo24
*info24
;
166 info24
= &state
->bind_r
.out
.bind_info
->info
.info24
;
168 info28
->supported_extensions
= info24
->supported_extensions
;
169 info28
->site_guid
= info24
->site_guid
;
170 info28
->pid
= info24
->pid
;
171 info28
->repl_epoch
= 0;
175 struct drsuapi_DsBindInfo48
*info48
;
176 info48
= &state
->bind_r
.out
.bind_info
->info
.info48
;
178 info28
->supported_extensions
= info48
->supported_extensions
;
179 info28
->site_guid
= info48
->site_guid
;
180 info28
->pid
= info48
->pid
;
181 info28
->repl_epoch
= info48
->repl_epoch
;
185 *info28
= state
->bind_r
.out
.bind_info
->info
.info28
;
190 tevent_req_done(req
);
193 NTSTATUS
dreplsrv_out_drsuapi_recv(struct tevent_req
*req
)
195 struct dreplsrv_out_drsuapi_state
*state
= tevent_req_data(req
,
196 struct dreplsrv_out_drsuapi_state
);
199 if (tevent_req_is_nterror(req
, &status
)) {
200 tevent_req_received(req
);
204 state
->conn
->drsuapi
= talloc_move(state
->conn
, &state
->drsuapi
);
206 tevent_req_received(req
);
210 struct dreplsrv_op_pull_source_state
{
211 struct tevent_context
*ev
;
212 struct dreplsrv_out_operation
*op
;
213 void *ndr_struct_ptr
;
216 static void dreplsrv_op_pull_source_connect_done(struct tevent_req
*subreq
);
218 struct tevent_req
*dreplsrv_op_pull_source_send(TALLOC_CTX
*mem_ctx
,
219 struct tevent_context
*ev
,
220 struct dreplsrv_out_operation
*op
)
222 struct tevent_req
*req
;
223 struct dreplsrv_op_pull_source_state
*state
;
224 struct tevent_req
*subreq
;
226 req
= tevent_req_create(mem_ctx
, &state
,
227 struct dreplsrv_op_pull_source_state
);
234 subreq
= dreplsrv_out_drsuapi_send(state
, ev
, op
->source_dsa
->conn
);
235 if (tevent_req_nomem(subreq
, req
)) {
236 return tevent_req_post(req
, ev
);
238 tevent_req_set_callback(subreq
, dreplsrv_op_pull_source_connect_done
, req
);
243 static void dreplsrv_op_pull_source_get_changes_trigger(struct tevent_req
*req
);
245 static void dreplsrv_op_pull_source_connect_done(struct tevent_req
*subreq
)
247 struct tevent_req
*req
= tevent_req_callback_data(subreq
,
251 status
= dreplsrv_out_drsuapi_recv(subreq
);
253 if (tevent_req_nterror(req
, status
)) {
257 dreplsrv_op_pull_source_get_changes_trigger(req
);
260 static void dreplsrv_op_pull_source_get_changes_done(struct tevent_req
*subreq
);
263 get a partial attribute set for a replication call
265 static NTSTATUS
dreplsrv_get_rodc_partial_attribute_set(struct dreplsrv_service
*service
,
267 struct drsuapi_DsPartialAttributeSet
**_pas
,
270 struct drsuapi_DsPartialAttributeSet
*pas
;
271 struct dsdb_schema
*schema
;
274 pas
= talloc_zero(mem_ctx
, struct drsuapi_DsPartialAttributeSet
);
275 NT_STATUS_HAVE_NO_MEMORY(pas
);
277 schema
= dsdb_get_schema(service
->samdb
, NULL
);
280 pas
->attids
= talloc_array(pas
, enum drsuapi_DsAttributeId
, schema
->num_attributes
);
281 NT_STATUS_HAVE_NO_MEMORY_AND_FREE(pas
->attids
, pas
);
283 for (i
=0; i
<schema
->num_attributes
; i
++) {
284 struct dsdb_attribute
*a
;
285 a
= schema
->attributes_by_attributeID_id
[i
];
286 if (a
->systemFlags
& (DS_FLAG_ATTR_NOT_REPLICATED
| DS_FLAG_ATTR_IS_CONSTRUCTED
)) {
289 if (a
->searchFlags
& SEARCH_FLAG_RODC_ATTRIBUTE
) {
292 pas
->attids
[pas
->num_attids
] = dsdb_attribute_get_attid(a
, for_schema
);
300 convert from one udv format to the other
302 static WERROR
udv_convert(TALLOC_CTX
*mem_ctx
,
303 const struct replUpToDateVectorCtr2
*udv
,
304 struct drsuapi_DsReplicaCursorCtrEx
*udv_ex
)
309 udv_ex
->reserved1
= 0;
310 udv_ex
->reserved2
= 0;
311 udv_ex
->count
= udv
->count
;
312 udv_ex
->cursors
= talloc_array(mem_ctx
, struct drsuapi_DsReplicaCursor
, udv
->count
);
313 W_ERROR_HAVE_NO_MEMORY(udv_ex
->cursors
);
315 for (i
=0; i
<udv
->count
; i
++) {
316 udv_ex
->cursors
[i
].source_dsa_invocation_id
= udv
->cursors
[i
].source_dsa_invocation_id
;
317 udv_ex
->cursors
[i
].highest_usn
= udv
->cursors
[i
].highest_usn
;
324 static void dreplsrv_op_pull_source_get_changes_trigger(struct tevent_req
*req
)
326 struct dreplsrv_op_pull_source_state
*state
= tevent_req_data(req
,
327 struct dreplsrv_op_pull_source_state
);
328 struct repsFromTo1
*rf1
= state
->op
->source_dsa
->repsFrom1
;
329 struct dreplsrv_service
*service
= state
->op
->service
;
330 struct dreplsrv_partition
*partition
= state
->op
->source_dsa
->partition
;
331 struct dreplsrv_drsuapi_connection
*drsuapi
= state
->op
->source_dsa
->conn
->drsuapi
;
332 struct drsuapi_DsGetNCChanges
*r
;
333 struct drsuapi_DsReplicaCursorCtrEx
*uptodateness_vector
;
334 struct tevent_req
*subreq
;
335 struct drsuapi_DsPartialAttributeSet
*pas
= NULL
;
337 uint32_t replica_flags
;
339 r
= talloc(state
, struct drsuapi_DsGetNCChanges
);
340 if (tevent_req_nomem(r
, req
)) {
344 r
->out
.level_out
= talloc(r
, uint32_t);
345 if (tevent_req_nomem(r
->out
.level_out
, req
)) {
348 r
->in
.req
= talloc(r
, union drsuapi_DsGetNCChangesRequest
);
349 if (tevent_req_nomem(r
->in
.req
, req
)) {
352 r
->out
.ctr
= talloc(r
, union drsuapi_DsGetNCChangesCtr
);
353 if (tevent_req_nomem(r
->out
.ctr
, req
)) {
357 if (partition
->uptodatevector
.count
!= 0 &&
358 partition
->uptodatevector_ex
.count
== 0) {
360 werr
= udv_convert(partition
, &partition
->uptodatevector
, &partition
->uptodatevector_ex
);
361 if (!W_ERROR_IS_OK(werr
)) {
362 DEBUG(0,(__location__
": Failed to convert UDV for %s : %s\n",
363 ldb_dn_get_linearized(partition
->dn
), win_errstr(werr
)));
367 if (partition
->uptodatevector_ex
.count
== 0) {
368 uptodateness_vector
= NULL
;
370 uptodateness_vector
= &partition
->uptodatevector_ex
;
373 replica_flags
= rf1
->replica_flags
;
375 if (service
->am_rodc
) {
376 bool for_schema
= false;
377 if (ldb_dn_compare_base(ldb_get_schema_basedn(service
->samdb
), partition
->dn
) == 0) {
381 status
= dreplsrv_get_rodc_partial_attribute_set(service
, r
, &pas
, for_schema
);
382 if (!NT_STATUS_IS_OK(status
)) {
383 DEBUG(0,(__location__
": Failed to construct partial attribute set : %s\n", nt_errstr(status
)));
386 if (state
->op
->extended_op
== DRSUAPI_EXOP_REPL_SECRET
) {
387 replica_flags
&= ~DRSUAPI_DRS_SPECIAL_SECRET_PROCESSING
;
391 r
->in
.bind_handle
= &drsuapi
->bind_handle
;
392 if (drsuapi
->remote_info28
.supported_extensions
& DRSUAPI_SUPPORTED_EXTENSION_GETCHGREQ_V8
) {
394 r
->in
.req
->req8
.destination_dsa_guid
= service
->ntds_guid
;
395 r
->in
.req
->req8
.source_dsa_invocation_id
= rf1
->source_dsa_invocation_id
;
396 r
->in
.req
->req8
.naming_context
= &partition
->nc
;
397 r
->in
.req
->req8
.highwatermark
= rf1
->highwatermark
;
398 r
->in
.req
->req8
.uptodateness_vector
= uptodateness_vector
;
399 r
->in
.req
->req8
.replica_flags
= replica_flags
;
400 r
->in
.req
->req8
.max_object_count
= 133;
401 r
->in
.req
->req8
.max_ndr_size
= 1336811;
402 r
->in
.req
->req8
.extended_op
= state
->op
->extended_op
;
403 r
->in
.req
->req8
.fsmo_info
= state
->op
->fsmo_info
;
404 r
->in
.req
->req8
.partial_attribute_set
= pas
;
405 r
->in
.req
->req8
.partial_attribute_set_ex
= NULL
;
406 r
->in
.req
->req8
.mapping_ctr
.num_mappings
= 0;
407 r
->in
.req
->req8
.mapping_ctr
.mappings
= NULL
;
410 r
->in
.req
->req5
.destination_dsa_guid
= service
->ntds_guid
;
411 r
->in
.req
->req5
.source_dsa_invocation_id
= rf1
->source_dsa_invocation_id
;
412 r
->in
.req
->req5
.naming_context
= &partition
->nc
;
413 r
->in
.req
->req5
.highwatermark
= rf1
->highwatermark
;
414 r
->in
.req
->req5
.uptodateness_vector
= uptodateness_vector
;
415 r
->in
.req
->req5
.replica_flags
= replica_flags
;
416 r
->in
.req
->req5
.max_object_count
= 133;
417 r
->in
.req
->req5
.max_ndr_size
= 1336770;
418 r
->in
.req
->req5
.extended_op
= state
->op
->extended_op
;
419 r
->in
.req
->req5
.fsmo_info
= state
->op
->fsmo_info
;
423 NDR_PRINT_IN_DEBUG(drsuapi_DsGetNCChanges
, r
);
426 state
->ndr_struct_ptr
= r
;
427 subreq
= dcerpc_drsuapi_DsGetNCChanges_r_send(state
,
429 drsuapi
->drsuapi_handle
,
431 if (tevent_req_nomem(subreq
, req
)) {
434 tevent_req_set_callback(subreq
, dreplsrv_op_pull_source_get_changes_done
, req
);
437 static void dreplsrv_op_pull_source_apply_changes_trigger(struct tevent_req
*req
,
438 struct drsuapi_DsGetNCChanges
*r
,
440 struct drsuapi_DsGetNCChangesCtr1
*ctr1
,
441 struct drsuapi_DsGetNCChangesCtr6
*ctr6
);
443 static void dreplsrv_op_pull_source_get_changes_done(struct tevent_req
*subreq
)
445 struct tevent_req
*req
= tevent_req_callback_data(subreq
,
447 struct dreplsrv_op_pull_source_state
*state
= tevent_req_data(req
,
448 struct dreplsrv_op_pull_source_state
);
450 struct drsuapi_DsGetNCChanges
*r
= talloc_get_type(state
->ndr_struct_ptr
,
451 struct drsuapi_DsGetNCChanges
);
452 uint32_t ctr_level
= 0;
453 struct drsuapi_DsGetNCChangesCtr1
*ctr1
= NULL
;
454 struct drsuapi_DsGetNCChangesCtr6
*ctr6
= NULL
;
455 enum drsuapi_DsExtendedError extended_ret
;
456 state
->ndr_struct_ptr
= NULL
;
458 status
= dcerpc_drsuapi_DsGetNCChanges_r_recv(subreq
, r
);
460 if (tevent_req_nterror(req
, status
)) {
464 if (!W_ERROR_IS_OK(r
->out
.result
)) {
465 status
= werror_to_ntstatus(r
->out
.result
);
466 tevent_req_nterror(req
, status
);
470 if (*r
->out
.level_out
== 1) {
472 ctr1
= &r
->out
.ctr
->ctr1
;
473 } else if (*r
->out
.level_out
== 2 &&
474 r
->out
.ctr
->ctr2
.mszip1
.ts
) {
476 ctr1
= &r
->out
.ctr
->ctr2
.mszip1
.ts
->ctr1
;
477 } else if (*r
->out
.level_out
== 6) {
479 ctr6
= &r
->out
.ctr
->ctr6
;
480 } else if (*r
->out
.level_out
== 7 &&
481 r
->out
.ctr
->ctr7
.level
== 6 &&
482 r
->out
.ctr
->ctr7
.type
== DRSUAPI_COMPRESSION_TYPE_MSZIP
&&
483 r
->out
.ctr
->ctr7
.ctr
.mszip6
.ts
) {
485 ctr6
= &r
->out
.ctr
->ctr7
.ctr
.mszip6
.ts
->ctr6
;
486 } else if (*r
->out
.level_out
== 7 &&
487 r
->out
.ctr
->ctr7
.level
== 6 &&
488 r
->out
.ctr
->ctr7
.type
== DRSUAPI_COMPRESSION_TYPE_XPRESS
&&
489 r
->out
.ctr
->ctr7
.ctr
.xpress6
.ts
) {
491 ctr6
= &r
->out
.ctr
->ctr7
.ctr
.xpress6
.ts
->ctr6
;
493 status
= werror_to_ntstatus(WERR_BAD_NET_RESP
);
494 tevent_req_nterror(req
, status
);
498 if (!ctr1
&& !ctr6
) {
499 status
= werror_to_ntstatus(WERR_BAD_NET_RESP
);
500 tevent_req_nterror(req
, status
);
504 if (ctr_level
== 6) {
505 if (!W_ERROR_IS_OK(ctr6
->drs_error
)) {
506 status
= werror_to_ntstatus(ctr6
->drs_error
);
507 tevent_req_nterror(req
, status
);
510 extended_ret
= ctr6
->extended_ret
;
513 if (ctr_level
== 1) {
514 extended_ret
= ctr1
->extended_ret
;
517 if (state
->op
->extended_op
!= DRSUAPI_EXOP_NONE
) {
518 state
->op
->extended_ret
= extended_ret
;
520 if (extended_ret
!= DRSUAPI_EXOP_ERR_SUCCESS
) {
521 status
= NT_STATUS_UNSUCCESSFUL
;
522 tevent_req_nterror(req
, status
);
527 dreplsrv_op_pull_source_apply_changes_trigger(req
, r
, ctr_level
, ctr1
, ctr6
);
530 static void dreplsrv_update_refs_trigger(struct tevent_req
*req
);
532 static void dreplsrv_op_pull_source_apply_changes_trigger(struct tevent_req
*req
,
533 struct drsuapi_DsGetNCChanges
*r
,
535 struct drsuapi_DsGetNCChangesCtr1
*ctr1
,
536 struct drsuapi_DsGetNCChangesCtr6
*ctr6
)
538 struct dreplsrv_op_pull_source_state
*state
= tevent_req_data(req
,
539 struct dreplsrv_op_pull_source_state
);
540 struct repsFromTo1 rf1
= *state
->op
->source_dsa
->repsFrom1
;
541 struct dreplsrv_service
*service
= state
->op
->service
;
542 struct dreplsrv_partition
*partition
= state
->op
->source_dsa
->partition
;
543 struct dreplsrv_drsuapi_connection
*drsuapi
= state
->op
->source_dsa
->conn
->drsuapi
;
544 struct dsdb_schema
*schema
;
545 struct dsdb_schema
*working_schema
;
546 const struct drsuapi_DsReplicaOIDMapping_Ctr
*mapping_ctr
;
547 uint32_t object_count
;
548 struct drsuapi_DsReplicaObjectListItemEx
*first_object
;
549 uint32_t linked_attributes_count
;
550 struct drsuapi_DsReplicaLinkedAttribute
*linked_attributes
;
551 const struct drsuapi_DsReplicaCursor2CtrEx
*uptodateness_vector
;
552 struct dsdb_extended_replicated_objects
*objects
;
553 bool more_data
= false;
559 mapping_ctr
= &ctr1
->mapping_ctr
;
560 object_count
= ctr1
->object_count
;
561 first_object
= ctr1
->first_object
;
562 linked_attributes_count
= 0;
563 linked_attributes
= NULL
;
564 rf1
.highwatermark
= ctr1
->new_highwatermark
;
565 uptodateness_vector
= NULL
; /* TODO: map it */
566 more_data
= ctr1
->more_data
;
569 mapping_ctr
= &ctr6
->mapping_ctr
;
570 object_count
= ctr6
->object_count
;
571 first_object
= ctr6
->first_object
;
572 linked_attributes_count
= ctr6
->linked_attributes_count
;
573 linked_attributes
= ctr6
->linked_attributes
;
574 rf1
.highwatermark
= ctr6
->new_highwatermark
;
575 uptodateness_vector
= ctr6
->uptodateness_vector
;
576 more_data
= ctr6
->more_data
;
579 nt_status
= werror_to_ntstatus(WERR_BAD_NET_RESP
);
580 tevent_req_nterror(req
, nt_status
);
584 schema
= dsdb_get_schema(service
->samdb
, NULL
);
586 DEBUG(0,(__location__
": Schema is not loaded yet!\n"));
587 tevent_req_nterror(req
, NT_STATUS_INTERNAL_ERROR
);
591 /* Decide what working schema to use for object conversion */
592 if (ldb_dn_compare(partition
->dn
, ldb_get_schema_basedn(service
->samdb
)) == 0) {
593 /* create working schema to convert objects with */
594 status
= dsdb_repl_make_working_schema(service
->samdb
,
599 &drsuapi
->gensec_skey
,
600 state
, &working_schema
);
601 if (!W_ERROR_IS_OK(status
)) {
602 DEBUG(0,("Failed to create working schema: %s",
603 win_errstr(status
)));
604 tevent_req_nterror(req
, NT_STATUS_INTERNAL_ERROR
);
608 working_schema
= schema
;
611 status
= dsdb_replicated_objects_convert(service
->samdb
,
617 linked_attributes_count
,
621 &drsuapi
->gensec_skey
,
623 if (!W_ERROR_IS_OK(status
)) {
624 nt_status
= werror_to_ntstatus(WERR_BAD_NET_RESP
);
625 DEBUG(0,("Failed to convert objects: %s/%s\n",
626 win_errstr(status
), nt_errstr(nt_status
)));
627 tevent_req_nterror(req
, nt_status
);
631 status
= dsdb_replicated_objects_commit(service
->samdb
,
634 &state
->op
->source_dsa
->notify_uSN
);
635 talloc_free(objects
);
636 if (!W_ERROR_IS_OK(status
)) {
637 nt_status
= werror_to_ntstatus(WERR_BAD_NET_RESP
);
638 DEBUG(0,("Failed to commit objects: %s/%s\n",
639 win_errstr(status
), nt_errstr(nt_status
)));
640 tevent_req_nterror(req
, nt_status
);
644 if (state
->op
->extended_op
== DRSUAPI_EXOP_NONE
) {
645 /* if it applied fine, we need to update the highwatermark */
646 *state
->op
->source_dsa
->repsFrom1
= rf1
;
649 * TODO: update our uptodatevector!
652 /* we don't need this maybe very large structure anymore */
656 dreplsrv_op_pull_source_get_changes_trigger(req
);
660 if (state
->op
->extended_op
!= DRSUAPI_EXOP_NONE
||
661 state
->op
->service
->am_rodc
) {
663 we don't do the UpdateRefs for extended ops or if we
666 tevent_req_done(req
);
670 /* now we need to update the repsTo record for this partition
671 on the server. These records are initially established when
672 we join the domain, but they quickly expire. We do it here
673 so we can use the already established DRSUAPI pipe
675 dreplsrv_update_refs_trigger(req
);
678 static void dreplsrv_update_refs_done(struct tevent_req
*subreq
);
681 send a UpdateRefs request to refresh our repsTo record on the server
683 static void dreplsrv_update_refs_trigger(struct tevent_req
*req
)
685 struct dreplsrv_op_pull_source_state
*state
= tevent_req_data(req
,
686 struct dreplsrv_op_pull_source_state
);
687 struct dreplsrv_service
*service
= state
->op
->service
;
688 struct dreplsrv_partition
*partition
= state
->op
->source_dsa
->partition
;
689 struct dreplsrv_drsuapi_connection
*drsuapi
= state
->op
->source_dsa
->conn
->drsuapi
;
690 struct drsuapi_DsReplicaUpdateRefs
*r
;
693 struct tevent_req
*subreq
;
695 r
= talloc(state
, struct drsuapi_DsReplicaUpdateRefs
);
696 if (tevent_req_nomem(r
, req
)) {
700 ntds_guid_str
= GUID_string(r
, &service
->ntds_guid
);
701 if (tevent_req_nomem(ntds_guid_str
, req
)) {
705 ntds_dns_name
= talloc_asprintf(r
, "%s._msdcs.%s",
707 lpcfg_dnsdomain(service
->task
->lp_ctx
));
708 if (tevent_req_nomem(ntds_dns_name
, req
)) {
712 r
->in
.bind_handle
= &drsuapi
->bind_handle
;
714 r
->in
.req
.req1
.naming_context
= &partition
->nc
;
715 r
->in
.req
.req1
.dest_dsa_dns_name
= ntds_dns_name
;
716 r
->in
.req
.req1
.dest_dsa_guid
= service
->ntds_guid
;
717 r
->in
.req
.req1
.options
= DRSUAPI_DRS_ADD_REF
| DRSUAPI_DRS_DEL_REF
;
718 if (!service
->am_rodc
) {
719 r
->in
.req
.req1
.options
|= DRSUAPI_DRS_WRIT_REP
;
722 state
->ndr_struct_ptr
= r
;
723 subreq
= dcerpc_drsuapi_DsReplicaUpdateRefs_r_send(state
,
725 drsuapi
->drsuapi_handle
,
727 if (tevent_req_nomem(subreq
, req
)) {
730 tevent_req_set_callback(subreq
, dreplsrv_update_refs_done
, req
);
734 receive a UpdateRefs reply
736 static void dreplsrv_update_refs_done(struct tevent_req
*subreq
)
738 struct tevent_req
*req
= tevent_req_callback_data(subreq
,
740 struct dreplsrv_op_pull_source_state
*state
= tevent_req_data(req
,
741 struct dreplsrv_op_pull_source_state
);
742 struct drsuapi_DsReplicaUpdateRefs
*r
= talloc_get_type(state
->ndr_struct_ptr
,
743 struct drsuapi_DsReplicaUpdateRefs
);
746 state
->ndr_struct_ptr
= NULL
;
748 status
= dcerpc_drsuapi_DsReplicaUpdateRefs_r_recv(subreq
, r
);
750 if (!NT_STATUS_IS_OK(status
)) {
751 DEBUG(0,("UpdateRefs failed with %s\n",
753 tevent_req_nterror(req
, status
);
757 if (!W_ERROR_IS_OK(r
->out
.result
)) {
758 status
= werror_to_ntstatus(r
->out
.result
);
759 DEBUG(0,("UpdateRefs failed with %s/%s for %s %s\n",
760 win_errstr(r
->out
.result
),
762 r
->in
.req
.req1
.dest_dsa_dns_name
,
763 r
->in
.req
.req1
.naming_context
->dn
));
764 tevent_req_nterror(req
, status
);
768 DEBUG(4,("UpdateRefs OK for %s %s\n",
769 r
->in
.req
.req1
.dest_dsa_dns_name
,
770 r
->in
.req
.req1
.naming_context
->dn
));
772 tevent_req_done(req
);
775 WERROR
dreplsrv_op_pull_source_recv(struct tevent_req
*req
)
779 if (tevent_req_is_nterror(req
, &status
)) {
780 tevent_req_received(req
);
781 return ntstatus_to_werror(status
);
784 tevent_req_received(req
);