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