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