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