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