s4:drepl_out_helpers.c - fix a counter type
[samba.git] / source4 / dsdb / repl / drepl_out_helpers.c
1 /* 
2    Unix SMB/CIFS mplementation.
3    DSDB replication service helper function for outgoing traffic
4    
5    Copyright (C) Stefan Metzmacher 2007
6     
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.
11    
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.
16    
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/>.
19    
20 */
21
22 #include "includes.h"
23 #include "dsdb/samdb/samdb.h"
24 #include "auth/auth.h"
25 #include "smbd/service.h"
26 #include "lib/events/events.h"
27 #include "lib/messaging/irpc.h"
28 #include "dsdb/repl/drepl_service.h"
29 #include "lib/ldb/include/ldb_errors.h"
30 #include "../lib/util/dlinklist.h"
31 #include "librpc/gen_ndr/ndr_misc.h"
32 #include "librpc/gen_ndr/ndr_drsuapi.h"
33 #include "librpc/gen_ndr/ndr_drsblobs.h"
34 #include "libcli/composite/composite.h"
35 #include "auth/gensec/gensec.h"
36 #include "param/param.h"
37 #include "../lib/util/tevent_ntstatus.h"
38
39 struct dreplsrv_out_drsuapi_state {
40         struct tevent_context *ev;
41
42         struct dreplsrv_out_connection *conn;
43
44         struct dreplsrv_drsuapi_connection *drsuapi;
45
46         struct drsuapi_DsBindInfoCtr bind_info_ctr;
47         struct drsuapi_DsBind bind_r;
48 };
49
50 static void dreplsrv_out_drsuapi_connect_done(struct composite_context *creq);
51
52 struct tevent_req *dreplsrv_out_drsuapi_send(TALLOC_CTX *mem_ctx,
53                                              struct tevent_context *ev,
54                                              struct dreplsrv_out_connection *conn)
55 {
56         struct tevent_req *req;
57         struct dreplsrv_out_drsuapi_state *state;
58         struct composite_context *creq;
59
60         req = tevent_req_create(mem_ctx, &state,
61                                 struct dreplsrv_out_drsuapi_state);
62         if (req == NULL) {
63                 return NULL;
64         }
65
66         state->ev       = ev;
67         state->conn     = conn;
68         state->drsuapi  = conn->drsuapi;
69
70         if (state->drsuapi && !state->drsuapi->pipe->conn->dead) {
71                 tevent_req_done(req);
72                 return tevent_req_post(req, ev);
73         }
74
75         if (state->drsuapi && state->drsuapi->pipe->conn->dead) {
76                 talloc_free(state->drsuapi);
77                 conn->drsuapi = NULL;
78         }
79
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);
83         }
84
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);
90         }
91         composite_continue(NULL, creq, dreplsrv_out_drsuapi_connect_done, req);
92
93         return req;
94 }
95
96 static void dreplsrv_out_drsuapi_bind_done(struct tevent_req *subreq);
97
98 static void dreplsrv_out_drsuapi_connect_done(struct composite_context *creq)
99 {
100         struct tevent_req *req = talloc_get_type(creq->async.private_data,
101                                                  struct tevent_req);
102         struct dreplsrv_out_drsuapi_state *state = tevent_req_data(req,
103                                                    struct dreplsrv_out_drsuapi_state);
104         NTSTATUS status;
105         struct tevent_req *subreq;
106
107         status = dcerpc_pipe_connect_b_recv(creq,
108                                             state->drsuapi,
109                                             &state->drsuapi->pipe);
110         if (tevent_req_nterror(req, status)) {
111                 return;
112         }
113
114         state->drsuapi->drsuapi_handle = state->drsuapi->pipe->binding_handle;
115
116         status = gensec_session_key(state->drsuapi->pipe->conn->security_state.generic_state,
117                                     &state->drsuapi->gensec_skey);
118         if (tevent_req_nterror(req, status)) {
119                 return;
120         }
121
122         state->bind_info_ctr.length             = 28;
123         state->bind_info_ctr.info.info28        = state->conn->service->bind_info28;
124
125         state->bind_r.in.bind_guid = &state->conn->service->ntds_guid;
126         state->bind_r.in.bind_info = &state->bind_info_ctr;
127         state->bind_r.out.bind_handle = &state->drsuapi->bind_handle;
128
129         subreq = dcerpc_drsuapi_DsBind_r_send(state,
130                                               state->ev,
131                                               state->drsuapi->drsuapi_handle,
132                                               &state->bind_r);
133         if (tevent_req_nomem(subreq, req)) {
134                 return;
135         }
136         tevent_req_set_callback(subreq, dreplsrv_out_drsuapi_bind_done, req);
137 }
138
139 static void dreplsrv_out_drsuapi_bind_done(struct tevent_req *subreq)
140 {
141         struct tevent_req *req = tevent_req_callback_data(subreq,
142                                  struct tevent_req);
143         struct dreplsrv_out_drsuapi_state *state = tevent_req_data(req,
144                                                    struct dreplsrv_out_drsuapi_state);
145         NTSTATUS status;
146
147         status = dcerpc_drsuapi_DsBind_r_recv(subreq, state);
148         TALLOC_FREE(subreq);
149         if (tevent_req_nterror(req, status)) {
150                 return;
151         }
152
153         if (!W_ERROR_IS_OK(state->bind_r.out.result)) {
154                 status = werror_to_ntstatus(state->bind_r.out.result);
155                 tevent_req_nterror(req, status);
156                 return;
157         }
158
159         ZERO_STRUCT(state->drsuapi->remote_info28);
160         if (state->bind_r.out.bind_info) {
161                 struct drsuapi_DsBindInfo28 *info28;
162                 info28 = &state->drsuapi->remote_info28;
163
164                 switch (state->bind_r.out.bind_info->length) {
165                 case 24: {
166                         struct drsuapi_DsBindInfo24 *info24;
167                         info24 = &state->bind_r.out.bind_info->info.info24;
168
169                         info28->supported_extensions    = info24->supported_extensions;
170                         info28->site_guid               = info24->site_guid;
171                         info28->pid                     = info24->pid;
172                         info28->repl_epoch              = 0;
173                         break;
174                 }
175                 case 48: {
176                         struct drsuapi_DsBindInfo48 *info48;
177                         info48 = &state->bind_r.out.bind_info->info.info48;
178
179                         info28->supported_extensions    = info48->supported_extensions;
180                         info28->site_guid               = info48->site_guid;
181                         info28->pid                     = info48->pid;
182                         info28->repl_epoch              = info48->repl_epoch;
183                         break;
184                 }
185                 case 28:
186                         *info28 = state->bind_r.out.bind_info->info.info28;
187                         break;
188                 }
189         }
190
191         tevent_req_done(req);
192 }
193
194 NTSTATUS dreplsrv_out_drsuapi_recv(struct tevent_req *req)
195 {
196         struct dreplsrv_out_drsuapi_state *state = tevent_req_data(req,
197                                                    struct dreplsrv_out_drsuapi_state);
198         NTSTATUS status;
199
200         if (tevent_req_is_nterror(req, &status)) {
201                 tevent_req_received(req);
202                 return status;
203         }
204
205         state->conn->drsuapi = talloc_move(state->conn, &state->drsuapi);
206
207         tevent_req_received(req);
208         return NT_STATUS_OK;
209 }
210
211 struct dreplsrv_op_pull_source_state {
212         struct tevent_context *ev;
213         struct dreplsrv_out_operation *op;
214         void *ndr_struct_ptr;
215 };
216
217 static void dreplsrv_op_pull_source_connect_done(struct tevent_req *subreq);
218
219 struct tevent_req *dreplsrv_op_pull_source_send(TALLOC_CTX *mem_ctx,
220                                                 struct tevent_context *ev,
221                                                 struct dreplsrv_out_operation *op)
222 {
223         struct tevent_req *req;
224         struct dreplsrv_op_pull_source_state *state;
225         struct tevent_req *subreq;
226
227         req = tevent_req_create(mem_ctx, &state,
228                                 struct dreplsrv_op_pull_source_state);
229         if (req == NULL) {
230                 return NULL;
231         }
232         state->ev = ev;
233         state->op = op;
234
235         subreq = dreplsrv_out_drsuapi_send(state, ev, op->source_dsa->conn);
236         if (tevent_req_nomem(subreq, req)) {
237                 return tevent_req_post(req, ev);
238         }
239         tevent_req_set_callback(subreq, dreplsrv_op_pull_source_connect_done, req);
240
241         return req;
242 }
243
244 static void dreplsrv_op_pull_source_get_changes_trigger(struct tevent_req *req);
245
246 static void dreplsrv_op_pull_source_connect_done(struct tevent_req *subreq)
247 {
248         struct tevent_req *req = tevent_req_callback_data(subreq,
249                                  struct tevent_req);
250         NTSTATUS status;
251
252         status = dreplsrv_out_drsuapi_recv(subreq);
253         TALLOC_FREE(subreq);
254         if (tevent_req_nterror(req, status)) {
255                 return;
256         }
257
258         dreplsrv_op_pull_source_get_changes_trigger(req);
259 }
260
261 static void dreplsrv_op_pull_source_get_changes_done(struct tevent_req *subreq);
262
263 /*
264   get a partial attribute set for a replication call
265  */
266 static NTSTATUS dreplsrv_get_rodc_partial_attribute_set(struct dreplsrv_service *service,
267                                                         TALLOC_CTX *mem_ctx,
268                                                         struct drsuapi_DsPartialAttributeSet **_pas,
269                                                         bool for_schema)
270 {
271         struct drsuapi_DsPartialAttributeSet *pas;
272         struct dsdb_schema *schema;
273         uint32_t i;
274
275         pas = talloc_zero(mem_ctx, struct drsuapi_DsPartialAttributeSet);
276         NT_STATUS_HAVE_NO_MEMORY(pas);
277
278         schema = dsdb_get_schema(service->samdb, NULL);
279
280         pas->version = 1;
281         pas->attids = talloc_array(pas, enum drsuapi_DsAttributeId, schema->num_attributes);
282         NT_STATUS_HAVE_NO_MEMORY_AND_FREE(pas->attids, pas);
283
284         for (i=0; i<schema->num_attributes; i++) {
285                 struct dsdb_attribute *a;
286                 a = schema->attributes_by_attributeID_id[i];
287                 if (a->systemFlags & (DS_FLAG_ATTR_NOT_REPLICATED | DS_FLAG_ATTR_IS_CONSTRUCTED)) {
288                         continue;
289                 }
290                 if (a->searchFlags & SEARCH_FLAG_RODC_ATTRIBUTE) {
291                         continue;
292                 }
293                 pas->attids[pas->num_attids] = dsdb_attribute_get_attid(a, for_schema);
294                 pas->num_attids++;
295         }
296         *_pas = pas;
297         return NT_STATUS_OK;
298 }
299
300 /*
301   convert from one udv format to the other
302  */
303 static WERROR udv_convert(TALLOC_CTX *mem_ctx,
304                           const struct replUpToDateVectorCtr2 *udv,
305                           struct drsuapi_DsReplicaCursorCtrEx *udv_ex)
306 {
307         uint32_t i;
308
309         udv_ex->version = 2;
310         udv_ex->reserved1 = 0;
311         udv_ex->reserved2 = 0;
312         udv_ex->count = udv->count;
313         udv_ex->cursors = talloc_array(mem_ctx, struct drsuapi_DsReplicaCursor, udv->count);
314         W_ERROR_HAVE_NO_MEMORY(udv_ex->cursors);
315
316         for (i=0; i<udv->count; i++) {
317                 udv_ex->cursors[i].source_dsa_invocation_id = udv->cursors[i].source_dsa_invocation_id;
318                 udv_ex->cursors[i].highest_usn = udv->cursors[i].highest_usn;
319         }
320
321         return WERR_OK;
322 }
323
324
325 static void dreplsrv_op_pull_source_get_changes_trigger(struct tevent_req *req)
326 {
327         struct dreplsrv_op_pull_source_state *state = tevent_req_data(req,
328                                                       struct dreplsrv_op_pull_source_state);
329         struct repsFromTo1 *rf1 = state->op->source_dsa->repsFrom1;
330         struct dreplsrv_service *service = state->op->service;
331         struct dreplsrv_partition *partition = state->op->source_dsa->partition;
332         struct dreplsrv_drsuapi_connection *drsuapi = state->op->source_dsa->conn->drsuapi;
333         struct drsuapi_DsGetNCChanges *r;
334         struct drsuapi_DsReplicaCursorCtrEx *uptodateness_vector;
335         struct tevent_req *subreq;
336         struct drsuapi_DsPartialAttributeSet *pas = NULL;
337         NTSTATUS status;
338         uint32_t replica_flags;
339
340         if ((rf1->replica_flags & DRSUAPI_DRS_WRIT_REP) == 0 &&
341             state->op->extended_op == DRSUAPI_EXOP_NONE) {
342                 return;
343         }
344
345         r = talloc(state, struct drsuapi_DsGetNCChanges);
346         if (tevent_req_nomem(r, req)) {
347                 return;
348         }
349
350         r->out.level_out = talloc(r, uint32_t);
351         if (tevent_req_nomem(r->out.level_out, req)) {
352                 return;
353         }
354         r->in.req = talloc(r, union drsuapi_DsGetNCChangesRequest);
355         if (tevent_req_nomem(r->in.req, req)) {
356                 return;
357         }
358         r->out.ctr = talloc(r, union drsuapi_DsGetNCChangesCtr);
359         if (tevent_req_nomem(r->out.ctr, req)) {
360                 return;
361         }
362
363         if (partition->uptodatevector.count != 0 &&
364             partition->uptodatevector_ex.count == 0) {
365                 WERROR werr;
366                 werr = udv_convert(partition, &partition->uptodatevector, &partition->uptodatevector_ex);
367                 if (!W_ERROR_IS_OK(werr)) {
368                         DEBUG(0,(__location__ ": Failed to convert UDV for %s : %s\n",
369                                  ldb_dn_get_linearized(partition->dn), nt_errstr(status)));
370                 }
371         }
372
373         if (partition->uptodatevector_ex.count == 0) {
374                 uptodateness_vector = NULL;
375         } else {
376                 uptodateness_vector = &partition->uptodatevector_ex;
377         }
378
379         replica_flags = rf1->replica_flags;
380
381         if (service->am_rodc) {
382                 bool for_schema = false;
383                 if (ldb_dn_compare_base(ldb_get_schema_basedn(service->samdb), partition->dn) == 0) {
384                         for_schema = true;
385                 }
386
387                 status = dreplsrv_get_rodc_partial_attribute_set(service, r, &pas, for_schema);
388                 if (!NT_STATUS_IS_OK(status)) {
389                         DEBUG(0,(__location__ ": Failed to construct partial attribute set : %s\n", nt_errstr(status)));
390                         return;
391                 }
392
393                 replica_flags &= ~DRSUAPI_DRS_WRIT_REP;
394         }
395
396         r->in.bind_handle       = &drsuapi->bind_handle;
397         if (drsuapi->remote_info28.supported_extensions & DRSUAPI_SUPPORTED_EXTENSION_GETCHGREQ_V8) {
398                 r->in.level                             = 8;
399                 r->in.req->req8.destination_dsa_guid    = service->ntds_guid;
400                 r->in.req->req8.source_dsa_invocation_id= rf1->source_dsa_invocation_id;
401                 r->in.req->req8.naming_context          = &partition->nc;
402                 r->in.req->req8.highwatermark           = rf1->highwatermark;
403                 r->in.req->req8.uptodateness_vector     = uptodateness_vector;
404                 r->in.req->req8.replica_flags           = replica_flags;
405                 r->in.req->req8.max_object_count        = 133;
406                 r->in.req->req8.max_ndr_size            = 1336811;
407                 r->in.req->req8.extended_op             = state->op->extended_op;
408                 r->in.req->req8.fsmo_info               = state->op->fsmo_info;
409                 r->in.req->req8.partial_attribute_set   = pas;
410                 r->in.req->req8.partial_attribute_set_ex= NULL;
411                 r->in.req->req8.mapping_ctr.num_mappings= 0;
412                 r->in.req->req8.mapping_ctr.mappings    = NULL;
413         } else {
414                 r->in.level                             = 5;
415                 r->in.req->req5.destination_dsa_guid    = service->ntds_guid;
416                 r->in.req->req5.source_dsa_invocation_id= rf1->source_dsa_invocation_id;
417                 r->in.req->req5.naming_context          = &partition->nc;
418                 r->in.req->req5.highwatermark           = rf1->highwatermark;
419                 r->in.req->req5.uptodateness_vector     = uptodateness_vector;
420                 r->in.req->req5.replica_flags           = replica_flags;
421                 r->in.req->req5.max_object_count        = 133;
422                 r->in.req->req5.max_ndr_size            = 1336770;
423                 r->in.req->req5.extended_op             = state->op->extended_op;
424                 r->in.req->req5.fsmo_info               = state->op->fsmo_info;
425         }
426
427 #if 0
428         NDR_PRINT_IN_DEBUG(drsuapi_DsGetNCChanges, r);
429 #endif
430
431         state->ndr_struct_ptr = r;
432         subreq = dcerpc_drsuapi_DsGetNCChanges_r_send(state,
433                                                       state->ev,
434                                                       drsuapi->drsuapi_handle,
435                                                       r);
436         if (tevent_req_nomem(subreq, req)) {
437                 return;
438         }
439         tevent_req_set_callback(subreq, dreplsrv_op_pull_source_get_changes_done, req);
440 }
441
442 static void dreplsrv_op_pull_source_apply_changes_trigger(struct tevent_req *req,
443                                                           struct drsuapi_DsGetNCChanges *r,
444                                                           uint32_t ctr_level,
445                                                           struct drsuapi_DsGetNCChangesCtr1 *ctr1,
446                                                           struct drsuapi_DsGetNCChangesCtr6 *ctr6);
447
448 static void dreplsrv_op_pull_source_get_changes_done(struct tevent_req *subreq)
449 {
450         struct tevent_req *req = tevent_req_callback_data(subreq,
451                                  struct tevent_req);
452         struct dreplsrv_op_pull_source_state *state = tevent_req_data(req,
453                                                       struct dreplsrv_op_pull_source_state);
454         NTSTATUS status;
455         struct drsuapi_DsGetNCChanges *r = talloc_get_type(state->ndr_struct_ptr,
456                                            struct drsuapi_DsGetNCChanges);
457         uint32_t ctr_level = 0;
458         struct drsuapi_DsGetNCChangesCtr1 *ctr1 = NULL;
459         struct drsuapi_DsGetNCChangesCtr6 *ctr6 = NULL;
460         enum drsuapi_DsExtendedError extended_ret;
461         state->ndr_struct_ptr = NULL;
462
463         status = dcerpc_drsuapi_DsGetNCChanges_r_recv(subreq, r);
464         TALLOC_FREE(subreq);
465         if (tevent_req_nterror(req, status)) {
466                 return;
467         }
468
469         if (!W_ERROR_IS_OK(r->out.result)) {
470                 status = werror_to_ntstatus(r->out.result);
471                 tevent_req_nterror(req, status);
472                 return;
473         }
474
475         if (*r->out.level_out == 1) {
476                 ctr_level = 1;
477                 ctr1 = &r->out.ctr->ctr1;
478         } else if (*r->out.level_out == 2 &&
479                    r->out.ctr->ctr2.mszip1.ts) {
480                 ctr_level = 1;
481                 ctr1 = &r->out.ctr->ctr2.mszip1.ts->ctr1;
482         } else if (*r->out.level_out == 6) {
483                 ctr_level = 6;
484                 ctr6 = &r->out.ctr->ctr6;
485         } else if (*r->out.level_out == 7 &&
486                    r->out.ctr->ctr7.level == 6 &&
487                    r->out.ctr->ctr7.type == DRSUAPI_COMPRESSION_TYPE_MSZIP &&
488                    r->out.ctr->ctr7.ctr.mszip6.ts) {
489                 ctr_level = 6;
490                 ctr6 = &r->out.ctr->ctr7.ctr.mszip6.ts->ctr6;
491         } else if (*r->out.level_out == 7 &&
492                    r->out.ctr->ctr7.level == 6 &&
493                    r->out.ctr->ctr7.type == DRSUAPI_COMPRESSION_TYPE_XPRESS &&
494                    r->out.ctr->ctr7.ctr.xpress6.ts) {
495                 ctr_level = 6;
496                 ctr6 = &r->out.ctr->ctr7.ctr.xpress6.ts->ctr6;
497         } else {
498                 status = werror_to_ntstatus(WERR_BAD_NET_RESP);
499                 tevent_req_nterror(req, status);
500                 return;
501         }
502
503         if (!ctr1 && !ctr6) {
504                 status = werror_to_ntstatus(WERR_BAD_NET_RESP);
505                 tevent_req_nterror(req, status);
506                 return;
507         }
508
509         if (ctr_level == 6) {
510                 if (!W_ERROR_IS_OK(ctr6->drs_error)) {
511                         status = werror_to_ntstatus(ctr6->drs_error);
512                         tevent_req_nterror(req, status);
513                         return;
514                 }
515                 extended_ret = ctr6->extended_ret;
516         }
517
518         if (ctr_level == 1) {
519                 extended_ret = ctr1->extended_ret;
520         }
521
522         if (state->op->extended_op != DRSUAPI_EXOP_NONE) {
523                 state->op->extended_ret = extended_ret;
524
525                 if (extended_ret != DRSUAPI_EXOP_ERR_SUCCESS) {
526                         status = NT_STATUS_UNSUCCESSFUL;
527                         tevent_req_nterror(req, status);
528                         return;
529                 }
530         }
531
532         dreplsrv_op_pull_source_apply_changes_trigger(req, r, ctr_level, ctr1, ctr6);
533 }
534
535 static void dreplsrv_update_refs_trigger(struct tevent_req *req);
536
537 static void dreplsrv_op_pull_source_apply_changes_trigger(struct tevent_req *req,
538                                                           struct drsuapi_DsGetNCChanges *r,
539                                                           uint32_t ctr_level,
540                                                           struct drsuapi_DsGetNCChangesCtr1 *ctr1,
541                                                            struct drsuapi_DsGetNCChangesCtr6 *ctr6)
542 {
543         struct dreplsrv_op_pull_source_state *state = tevent_req_data(req,
544                                                       struct dreplsrv_op_pull_source_state);
545         struct repsFromTo1 rf1 = *state->op->source_dsa->repsFrom1;
546         struct dreplsrv_service *service = state->op->service;
547         struct dreplsrv_partition *partition = state->op->source_dsa->partition;
548         struct dreplsrv_drsuapi_connection *drsuapi = state->op->source_dsa->conn->drsuapi;
549         const struct drsuapi_DsReplicaOIDMapping_Ctr *mapping_ctr;
550         uint32_t object_count;
551         struct drsuapi_DsReplicaObjectListItemEx *first_object;
552         uint32_t linked_attributes_count;
553         struct drsuapi_DsReplicaLinkedAttribute *linked_attributes;
554         const struct drsuapi_DsReplicaCursor2CtrEx *uptodateness_vector;
555         struct dsdb_extended_replicated_objects *objects;
556         bool more_data = false;
557         WERROR status;
558         NTSTATUS nt_status;
559
560         switch (ctr_level) {
561         case 1:
562                 mapping_ctr                     = &ctr1->mapping_ctr;
563                 object_count                    = ctr1->object_count;
564                 first_object                    = ctr1->first_object;
565                 linked_attributes_count         = 0;
566                 linked_attributes               = NULL;
567                 rf1.highwatermark               = ctr1->new_highwatermark;
568                 uptodateness_vector             = NULL; /* TODO: map it */
569                 more_data                       = ctr1->more_data;
570                 break;
571         case 6:
572                 mapping_ctr                     = &ctr6->mapping_ctr;
573                 object_count                    = ctr6->object_count;
574                 first_object                    = ctr6->first_object;
575                 linked_attributes_count         = ctr6->linked_attributes_count;
576                 linked_attributes               = ctr6->linked_attributes;
577                 rf1.highwatermark               = ctr6->new_highwatermark;
578                 uptodateness_vector             = ctr6->uptodateness_vector;
579                 more_data                       = ctr6->more_data;
580                 break;
581         default:
582                 nt_status = werror_to_ntstatus(WERR_BAD_NET_RESP);
583                 tevent_req_nterror(req, nt_status);
584                 return;
585         }
586
587         status = dsdb_extended_replicated_objects_convert(service->samdb,
588                                                           partition->nc.dn,
589                                                           mapping_ctr,
590                                                           object_count,
591                                                           first_object,
592                                                           linked_attributes_count,
593                                                           linked_attributes,
594                                                           &rf1,
595                                                           uptodateness_vector,
596                                                           &drsuapi->gensec_skey,
597                                                           state, &objects);
598         if (!W_ERROR_IS_OK(status)) {
599                 nt_status = werror_to_ntstatus(WERR_BAD_NET_RESP);
600                 DEBUG(0,("Failed to convert objects: %s/%s\n",
601                           win_errstr(status), nt_errstr(nt_status)));
602                 tevent_req_nterror(req, nt_status);
603                 return;
604         }
605
606         status = dsdb_extended_replicated_objects_commit(service->samdb,
607                                                          objects, 
608                                                          &state->op->source_dsa->notify_uSN);
609         talloc_free(objects);
610         if (!W_ERROR_IS_OK(status)) {
611                 nt_status = werror_to_ntstatus(WERR_BAD_NET_RESP);
612                 DEBUG(0,("Failed to commit objects: %s/%s\n",
613                           win_errstr(status), nt_errstr(nt_status)));
614                 tevent_req_nterror(req, nt_status);
615                 return;
616         }
617         if (state->op->extended_op == DRSUAPI_EXOP_NONE) {
618                 /* if it applied fine, we need to update the highwatermark */
619                 *state->op->source_dsa->repsFrom1 = rf1;
620         }
621         /*
622          * TODO: update our uptodatevector!
623          */
624
625         /* we don't need this maybe very large structure anymore */
626         TALLOC_FREE(r);
627
628         if (more_data) {
629                 dreplsrv_op_pull_source_get_changes_trigger(req);
630                 return;
631         }
632
633         /* now we need to update the repsTo record for this partition
634            on the server. These records are initially established when
635            we join the domain, but they quickly expire.  We do it here
636            so we can use the already established DRSUAPI pipe
637         */
638         if (state->op->extended_op == DRSUAPI_EXOP_NONE) {
639                 dreplsrv_update_refs_trigger(req);
640         } else {
641                 tevent_req_done(req);
642         }
643 }
644
645 static void dreplsrv_update_refs_done(struct tevent_req *subreq);
646
647 /*
648   send a UpdateRefs request to refresh our repsTo record on the server
649  */
650 static void dreplsrv_update_refs_trigger(struct tevent_req *req)
651 {
652         struct dreplsrv_op_pull_source_state *state = tevent_req_data(req,
653                                                       struct dreplsrv_op_pull_source_state);
654         struct dreplsrv_service *service = state->op->service;
655         struct dreplsrv_partition *partition = state->op->source_dsa->partition;
656         struct dreplsrv_drsuapi_connection *drsuapi = state->op->source_dsa->conn->drsuapi;
657         struct drsuapi_DsReplicaUpdateRefs *r;
658         char *ntds_guid_str;
659         char *ntds_dns_name;
660         struct tevent_req *subreq;
661
662         r = talloc(state, struct drsuapi_DsReplicaUpdateRefs);
663         if (tevent_req_nomem(r, req)) {
664                 return;
665         }
666
667         ntds_guid_str = GUID_string(r, &service->ntds_guid);
668         if (tevent_req_nomem(ntds_guid_str, req)) {
669                 return;
670         }
671
672         ntds_dns_name = talloc_asprintf(r, "%s._msdcs.%s",
673                                         ntds_guid_str,
674                                         lpcfg_dnsdomain(service->task->lp_ctx));
675         if (tevent_req_nomem(ntds_dns_name, req)) {
676                 return;
677         }
678
679         r->in.bind_handle       = &drsuapi->bind_handle;
680         r->in.level             = 1;
681         r->in.req.req1.naming_context     = &partition->nc;
682         r->in.req.req1.dest_dsa_dns_name  = ntds_dns_name;
683         r->in.req.req1.dest_dsa_guid      = service->ntds_guid;
684         r->in.req.req1.options            = DRSUAPI_DRS_ADD_REF | DRSUAPI_DRS_DEL_REF;
685         if (!service->am_rodc) {
686                 r->in.req.req1.options |= DRSUAPI_DRS_WRIT_REP;
687         }
688
689         state->ndr_struct_ptr = r;
690         subreq = dcerpc_drsuapi_DsReplicaUpdateRefs_r_send(state,
691                                                            state->ev,
692                                                            drsuapi->drsuapi_handle,
693                                                            r);
694         if (tevent_req_nomem(subreq, req)) {
695                 return;
696         }
697         tevent_req_set_callback(subreq, dreplsrv_update_refs_done, req);
698 }
699
700 /*
701   receive a UpdateRefs reply
702  */
703 static void dreplsrv_update_refs_done(struct tevent_req *subreq)
704 {
705         struct tevent_req *req = tevent_req_callback_data(subreq,
706                                  struct tevent_req);
707         struct dreplsrv_op_pull_source_state *state = tevent_req_data(req,
708                                                       struct dreplsrv_op_pull_source_state);
709         struct drsuapi_DsReplicaUpdateRefs *r = talloc_get_type(state->ndr_struct_ptr,
710                                                                 struct drsuapi_DsReplicaUpdateRefs);
711         NTSTATUS status;
712
713         state->ndr_struct_ptr = NULL;
714
715         status = dcerpc_drsuapi_DsReplicaUpdateRefs_r_recv(subreq, r);
716         TALLOC_FREE(subreq);
717         if (!NT_STATUS_IS_OK(status)) {
718                 DEBUG(0,("UpdateRefs failed with %s\n", 
719                          nt_errstr(status)));
720                 tevent_req_nterror(req, status);
721                 return;
722         }
723
724         if (!W_ERROR_IS_OK(r->out.result)) {
725                 status = werror_to_ntstatus(r->out.result);
726                 DEBUG(0,("UpdateRefs failed with %s/%s for %s %s\n",
727                          win_errstr(r->out.result),
728                          nt_errstr(status),
729                          r->in.req.req1.dest_dsa_dns_name,
730                          r->in.req.req1.naming_context->dn));
731                 tevent_req_nterror(req, status);
732                 return;
733         }
734
735         DEBUG(4,("UpdateRefs OK for %s %s\n", 
736                  r->in.req.req1.dest_dsa_dns_name,
737                  r->in.req.req1.naming_context->dn));
738
739         tevent_req_done(req);
740 }
741
742 WERROR dreplsrv_op_pull_source_recv(struct tevent_req *req)
743 {
744         NTSTATUS status;
745
746         if (tevent_req_is_nterror(req, &status)) {
747                 tevent_req_received(req);
748                 return ntstatus_to_werror(status);
749         }
750
751         tevent_req_received(req);
752         return WERR_OK;
753 }
754