2 Unix SMB/CIFS mplementation.
3 DSDB replication service outgoing Pull-Replication
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 "libcli/security/security.h"
37 update repsFrom/repsTo error information
39 void drepl_reps_update(struct dreplsrv_service
*s
, const char *reps_attr
,
41 struct GUID
*source_dsa_obj_guid
, WERROR status
)
43 struct repsFromToBlob
*reps
;
46 TALLOC_CTX
*tmp_ctx
= talloc_new(s
);
51 unix_to_nt_time(&now
, t
);
53 werr
= dsdb_loadreps(s
->samdb
, tmp_ctx
, dn
, reps_attr
, &reps
, &count
);
54 if (!W_ERROR_IS_OK(werr
)) {
59 for (i
=0; i
<count
; i
++) {
60 if (GUID_compare(source_dsa_obj_guid
,
61 &reps
[i
].ctr
.ctr1
.source_dsa_obj_guid
) == 0) {
67 /* no record to update */
72 /* only update the status fields */
73 reps
[i
].ctr
.ctr1
.last_attempt
= now
;
74 reps
[i
].ctr
.ctr1
.result_last_attempt
= status
;
75 if (W_ERROR_IS_OK(status
)) {
76 reps
[i
].ctr
.ctr1
.last_success
= now
;
77 reps
[i
].ctr
.ctr1
.consecutive_sync_failures
= 0;
79 reps
[i
].ctr
.ctr1
.consecutive_sync_failures
++;
82 werr
= dsdb_savereps(s
->samdb
, tmp_ctx
, dn
, reps_attr
, reps
, count
);
83 if (!W_ERROR_IS_OK(werr
)) {
84 DEBUG(2,("drepl_reps_update: Failed to save %s for %s: %s\n",
85 reps_attr
, ldb_dn_get_linearized(dn
), win_errstr(werr
)));
90 WERROR
dreplsrv_schedule_partition_pull_source(struct dreplsrv_service
*s
,
91 struct dreplsrv_partition_source_dsa
*source
,
93 enum drsuapi_DsExtendedOperation extended_op
,
95 dreplsrv_extended_callback_t callback
,
98 struct dreplsrv_out_operation
*op
;
100 op
= talloc_zero(s
, struct dreplsrv_out_operation
);
101 W_ERROR_HAVE_NO_MEMORY(op
);
105 * source may either be the long-term list of partners, or
106 * from dreplsrv_partition_source_dsa_temporary(). Because it
107 * can be either, we can't talloc_steal() it here, so we
108 * instead we reference it.
110 * We never talloc_free() the p->sources pointers - indeed we
111 * never remove them - and the temp source will otherwise go
112 * away with the msg it is allocated on.
114 * Finally the pointer created in drepl_request_extended_op()
115 * is removed with talloc_unlink().
118 op
->source_dsa
= talloc_reference(op
, source
);
119 if (!op
->source_dsa
) {
123 op
->options
= options
;
124 op
->extended_op
= extended_op
;
125 op
->fsmo_info
= fsmo_info
;
126 op
->callback
= callback
;
127 op
->cb_data
= cb_data
;
128 op
->schedule_time
= time(NULL
);
130 DLIST_ADD_END(s
->ops
.pending
, op
, struct dreplsrv_out_operation
*);
135 static WERROR
dreplsrv_schedule_partition_pull(struct dreplsrv_service
*s
,
136 struct dreplsrv_partition
*p
,
140 struct dreplsrv_partition_source_dsa
*cur
;
142 for (cur
= p
->sources
; cur
; cur
= cur
->next
) {
143 status
= dreplsrv_schedule_partition_pull_source(s
, cur
,
144 0, DRSUAPI_EXOP_NONE
, 0,
146 W_ERROR_NOT_OK_RETURN(status
);
152 WERROR
dreplsrv_schedule_pull_replication(struct dreplsrv_service
*s
, TALLOC_CTX
*mem_ctx
)
155 struct dreplsrv_partition
*p
;
157 for (p
= s
->partitions
; p
; p
= p
->next
) {
158 status
= dreplsrv_schedule_partition_pull(s
, p
, mem_ctx
);
159 W_ERROR_NOT_OK_RETURN(status
);
166 static void dreplsrv_pending_op_callback(struct tevent_req
*subreq
)
168 struct dreplsrv_out_operation
*op
= tevent_req_callback_data(subreq
,
169 struct dreplsrv_out_operation
);
170 struct repsFromTo1
*rf
= op
->source_dsa
->repsFrom1
;
171 struct dreplsrv_service
*s
= op
->service
;
174 werr
= dreplsrv_op_pull_source_recv(subreq
);
177 DEBUG(4,("dreplsrv_op_pull_source(%s) for %s\n", win_errstr(werr
),
178 ldb_dn_get_linearized(op
->source_dsa
->partition
->dn
)));
180 if (op
->extended_op
== DRSUAPI_EXOP_NONE
) {
181 drepl_reps_update(s
, "repsFrom", op
->source_dsa
->partition
->dn
,
182 &rf
->source_dsa_obj_guid
, werr
);
186 op
->callback(s
, werr
, op
->extended_ret
, op
->cb_data
);
189 s
->ops
.current
= NULL
;
190 dreplsrv_run_pending_ops(s
);
193 void dreplsrv_run_pull_ops(struct dreplsrv_service
*s
)
195 struct dreplsrv_out_operation
*op
;
198 struct tevent_req
*subreq
;
201 if (s
->ops
.current
) {
202 /* if there's still one running, we're done */
206 if (!s
->ops
.pending
) {
207 /* if there're no pending operations, we're done */
212 unix_to_nt_time(&now
, t
);
216 DLIST_REMOVE(s
->ops
.pending
, op
);
218 op
->source_dsa
->repsFrom1
->last_attempt
= now
;
220 /* check if inbound replication is enabled */
221 if (!(op
->options
& DRSUAPI_DRS_SYNC_FORCED
)) {
222 uint32_t rep_options
;
223 if (samdb_ntds_options(op
->service
->samdb
, &rep_options
) != LDB_SUCCESS
) {
224 werr
= WERR_DS_DRA_INTERNAL_ERROR
;
228 if ((rep_options
& DS_NTDSDSA_OPT_DISABLE_INBOUND_REPL
)) {
229 werr
= WERR_DS_DRA_SINK_DISABLED
;
234 subreq
= dreplsrv_op_pull_source_send(op
, s
->task
->event_ctx
, op
);
240 tevent_req_set_callback(subreq
, dreplsrv_pending_op_callback
, op
);
244 if (op
->extended_op
== DRSUAPI_EXOP_NONE
) {
245 drepl_reps_update(s
, "repsFrom", op
->source_dsa
->partition
->dn
,
246 &op
->source_dsa
->repsFrom1
->source_dsa_obj_guid
, werr
);
248 /* unblock queue processing */
249 s
->ops
.current
= NULL
;
251 * let the callback do its job just like in any other failure situation
254 op
->callback(s
, werr
, op
->extended_ret
, op
->cb_data
);