f02fae951017bc8fb39a10ec6640a09c9b6ef39e
[kai/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 "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         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;
554         WERROR status;
555         NTSTATUS nt_status;
556
557         switch (ctr_level) {
558         case 1:
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;
567                 break;
568         case 6:
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;
577                 break;
578         default:
579                 nt_status = werror_to_ntstatus(WERR_BAD_NET_RESP);
580                 tevent_req_nterror(req, nt_status);
581                 return;
582         }
583
584         schema = dsdb_get_schema(service->samdb, NULL);
585         if (!schema) {
586                 DEBUG(0,(__location__ ": Schema is not loaded yet!\n"));
587                 tevent_req_nterror(req, NT_STATUS_INTERNAL_ERROR);
588                 return;
589         }
590
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,
595                                                        schema,
596                                                        mapping_ctr,
597                                                        object_count,
598                                                        first_object,
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);
605                         return;
606                 }
607         } else {
608                 working_schema = schema;
609         }
610
611         status = dsdb_replicated_objects_convert(service->samdb,
612                                                  working_schema,
613                                                  partition->nc.dn,
614                                                  mapping_ctr,
615                                                  object_count,
616                                                  first_object,
617                                                  linked_attributes_count,
618                                                  linked_attributes,
619                                                  &rf1,
620                                                  uptodateness_vector,
621                                                  &drsuapi->gensec_skey,
622                                                  state, &objects);
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);
628                 return;
629         }
630
631         status = dsdb_replicated_objects_commit(service->samdb,
632                                                 objects,
633                                                 &state->op->source_dsa->notify_uSN);
634         talloc_free(objects);
635         if (!W_ERROR_IS_OK(status)) {
636                 nt_status = werror_to_ntstatus(WERR_BAD_NET_RESP);
637                 DEBUG(0,("Failed to commit objects: %s/%s\n",
638                           win_errstr(status), nt_errstr(nt_status)));
639                 tevent_req_nterror(req, nt_status);
640                 return;
641         }
642         if (state->op->extended_op == DRSUAPI_EXOP_NONE) {
643                 /* if it applied fine, we need to update the highwatermark */
644                 *state->op->source_dsa->repsFrom1 = rf1;
645         }
646         /*
647          * TODO: update our uptodatevector!
648          */
649
650         /* we don't need this maybe very large structure anymore */
651         TALLOC_FREE(r);
652
653         if (more_data) {
654                 dreplsrv_op_pull_source_get_changes_trigger(req);
655                 return;
656         }
657
658         if (state->op->extended_op != DRSUAPI_EXOP_NONE ||
659             state->op->service->am_rodc) {
660                 /*
661                   we don't do the UpdateRefs for extended ops or if we
662                   are a RODC
663                  */
664                 tevent_req_done(req);
665                 return;
666         }
667
668         /* now we need to update the repsTo record for this partition
669            on the server. These records are initially established when
670            we join the domain, but they quickly expire.  We do it here
671            so we can use the already established DRSUAPI pipe
672         */
673         dreplsrv_update_refs_trigger(req);
674 }
675
676 static void dreplsrv_update_refs_done(struct tevent_req *subreq);
677
678 /*
679   send a UpdateRefs request to refresh our repsTo record on the server
680  */
681 static void dreplsrv_update_refs_trigger(struct tevent_req *req)
682 {
683         struct dreplsrv_op_pull_source_state *state = tevent_req_data(req,
684                                                       struct dreplsrv_op_pull_source_state);
685         struct dreplsrv_service *service = state->op->service;
686         struct dreplsrv_partition *partition = state->op->source_dsa->partition;
687         struct dreplsrv_drsuapi_connection *drsuapi = state->op->source_dsa->conn->drsuapi;
688         struct drsuapi_DsReplicaUpdateRefs *r;
689         char *ntds_guid_str;
690         char *ntds_dns_name;
691         struct tevent_req *subreq;
692
693         r = talloc(state, struct drsuapi_DsReplicaUpdateRefs);
694         if (tevent_req_nomem(r, req)) {
695                 return;
696         }
697
698         ntds_guid_str = GUID_string(r, &service->ntds_guid);
699         if (tevent_req_nomem(ntds_guid_str, req)) {
700                 return;
701         }
702
703         ntds_dns_name = talloc_asprintf(r, "%s._msdcs.%s",
704                                         ntds_guid_str,
705                                         lpcfg_dnsdomain(service->task->lp_ctx));
706         if (tevent_req_nomem(ntds_dns_name, req)) {
707                 return;
708         }
709
710         r->in.bind_handle       = &drsuapi->bind_handle;
711         r->in.level             = 1;
712         r->in.req.req1.naming_context     = &partition->nc;
713         r->in.req.req1.dest_dsa_dns_name  = ntds_dns_name;
714         r->in.req.req1.dest_dsa_guid      = service->ntds_guid;
715         r->in.req.req1.options            = DRSUAPI_DRS_ADD_REF | DRSUAPI_DRS_DEL_REF;
716         if (!service->am_rodc) {
717                 r->in.req.req1.options |= DRSUAPI_DRS_WRIT_REP;
718         }
719
720         state->ndr_struct_ptr = r;
721         subreq = dcerpc_drsuapi_DsReplicaUpdateRefs_r_send(state,
722                                                            state->ev,
723                                                            drsuapi->drsuapi_handle,
724                                                            r);
725         if (tevent_req_nomem(subreq, req)) {
726                 return;
727         }
728         tevent_req_set_callback(subreq, dreplsrv_update_refs_done, req);
729 }
730
731 /*
732   receive a UpdateRefs reply
733  */
734 static void dreplsrv_update_refs_done(struct tevent_req *subreq)
735 {
736         struct tevent_req *req = tevent_req_callback_data(subreq,
737                                  struct tevent_req);
738         struct dreplsrv_op_pull_source_state *state = tevent_req_data(req,
739                                                       struct dreplsrv_op_pull_source_state);
740         struct drsuapi_DsReplicaUpdateRefs *r = talloc_get_type(state->ndr_struct_ptr,
741                                                                 struct drsuapi_DsReplicaUpdateRefs);
742         NTSTATUS status;
743
744         state->ndr_struct_ptr = NULL;
745
746         status = dcerpc_drsuapi_DsReplicaUpdateRefs_r_recv(subreq, r);
747         TALLOC_FREE(subreq);
748         if (!NT_STATUS_IS_OK(status)) {
749                 DEBUG(0,("UpdateRefs failed with %s\n", 
750                          nt_errstr(status)));
751                 tevent_req_nterror(req, status);
752                 return;
753         }
754
755         if (!W_ERROR_IS_OK(r->out.result)) {
756                 status = werror_to_ntstatus(r->out.result);
757                 DEBUG(0,("UpdateRefs failed with %s/%s for %s %s\n",
758                          win_errstr(r->out.result),
759                          nt_errstr(status),
760                          r->in.req.req1.dest_dsa_dns_name,
761                          r->in.req.req1.naming_context->dn));
762                 tevent_req_nterror(req, status);
763                 return;
764         }
765
766         DEBUG(4,("UpdateRefs OK for %s %s\n", 
767                  r->in.req.req1.dest_dsa_dns_name,
768                  r->in.req.req1.naming_context->dn));
769
770         tevent_req_done(req);
771 }
772
773 WERROR dreplsrv_op_pull_source_recv(struct tevent_req *req)
774 {
775         NTSTATUS status;
776
777         if (tevent_req_is_nterror(req, &status)) {
778                 tevent_req_received(req);
779                 return ntstatus_to_werror(status);
780         }
781
782         tevent_req_received(req);
783         return WERR_OK;
784 }
785