s4-drepl: don't call UpdateRefs on a RODC
[mat/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 "lib/messaging/irpc.h"
28 #include "dsdb/repl/drepl_service.h"
29 #include "lib/ldb/include/ldb_errors.h"
30 #include "../lib/util/dlinklist.h"
31 #include "librpc/gen_ndr/ndr_misc.h"
32 #include "librpc/gen_ndr/ndr_drsuapi.h"
33 #include "librpc/gen_ndr/ndr_drsblobs.h"
34 #include "libcli/composite/composite.h"
35 #include "auth/gensec/gensec.h"
36 #include "param/param.h"
37 #include "../lib/util/tevent_ntstatus.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), nt_errstr(status)));
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         }
388
389         r->in.bind_handle       = &drsuapi->bind_handle;
390         if (drsuapi->remote_info28.supported_extensions & DRSUAPI_SUPPORTED_EXTENSION_GETCHGREQ_V8) {
391                 r->in.level                             = 8;
392                 r->in.req->req8.destination_dsa_guid    = service->ntds_guid;
393                 r->in.req->req8.source_dsa_invocation_id= rf1->source_dsa_invocation_id;
394                 r->in.req->req8.naming_context          = &partition->nc;
395                 r->in.req->req8.highwatermark           = rf1->highwatermark;
396                 r->in.req->req8.uptodateness_vector     = uptodateness_vector;
397                 r->in.req->req8.replica_flags           = replica_flags;
398                 r->in.req->req8.max_object_count        = 133;
399                 r->in.req->req8.max_ndr_size            = 1336811;
400                 r->in.req->req8.extended_op             = state->op->extended_op;
401                 r->in.req->req8.fsmo_info               = state->op->fsmo_info;
402                 r->in.req->req8.partial_attribute_set   = pas;
403                 r->in.req->req8.partial_attribute_set_ex= NULL;
404                 r->in.req->req8.mapping_ctr.num_mappings= 0;
405                 r->in.req->req8.mapping_ctr.mappings    = NULL;
406         } else {
407                 r->in.level                             = 5;
408                 r->in.req->req5.destination_dsa_guid    = service->ntds_guid;
409                 r->in.req->req5.source_dsa_invocation_id= rf1->source_dsa_invocation_id;
410                 r->in.req->req5.naming_context          = &partition->nc;
411                 r->in.req->req5.highwatermark           = rf1->highwatermark;
412                 r->in.req->req5.uptodateness_vector     = uptodateness_vector;
413                 r->in.req->req5.replica_flags           = replica_flags;
414                 r->in.req->req5.max_object_count        = 133;
415                 r->in.req->req5.max_ndr_size            = 1336770;
416                 r->in.req->req5.extended_op             = state->op->extended_op;
417                 r->in.req->req5.fsmo_info               = state->op->fsmo_info;
418         }
419
420 #if 0
421         NDR_PRINT_IN_DEBUG(drsuapi_DsGetNCChanges, r);
422 #endif
423
424         state->ndr_struct_ptr = r;
425         subreq = dcerpc_drsuapi_DsGetNCChanges_r_send(state,
426                                                       state->ev,
427                                                       drsuapi->drsuapi_handle,
428                                                       r);
429         if (tevent_req_nomem(subreq, req)) {
430                 return;
431         }
432         tevent_req_set_callback(subreq, dreplsrv_op_pull_source_get_changes_done, req);
433 }
434
435 static void dreplsrv_op_pull_source_apply_changes_trigger(struct tevent_req *req,
436                                                           struct drsuapi_DsGetNCChanges *r,
437                                                           uint32_t ctr_level,
438                                                           struct drsuapi_DsGetNCChangesCtr1 *ctr1,
439                                                           struct drsuapi_DsGetNCChangesCtr6 *ctr6);
440
441 static void dreplsrv_op_pull_source_get_changes_done(struct tevent_req *subreq)
442 {
443         struct tevent_req *req = tevent_req_callback_data(subreq,
444                                  struct tevent_req);
445         struct dreplsrv_op_pull_source_state *state = tevent_req_data(req,
446                                                       struct dreplsrv_op_pull_source_state);
447         NTSTATUS status;
448         struct drsuapi_DsGetNCChanges *r = talloc_get_type(state->ndr_struct_ptr,
449                                            struct drsuapi_DsGetNCChanges);
450         uint32_t ctr_level = 0;
451         struct drsuapi_DsGetNCChangesCtr1 *ctr1 = NULL;
452         struct drsuapi_DsGetNCChangesCtr6 *ctr6 = NULL;
453         enum drsuapi_DsExtendedError extended_ret;
454         state->ndr_struct_ptr = NULL;
455
456         status = dcerpc_drsuapi_DsGetNCChanges_r_recv(subreq, r);
457         TALLOC_FREE(subreq);
458         if (tevent_req_nterror(req, status)) {
459                 return;
460         }
461
462         if (!W_ERROR_IS_OK(r->out.result)) {
463                 status = werror_to_ntstatus(r->out.result);
464                 tevent_req_nterror(req, status);
465                 return;
466         }
467
468         if (*r->out.level_out == 1) {
469                 ctr_level = 1;
470                 ctr1 = &r->out.ctr->ctr1;
471         } else if (*r->out.level_out == 2 &&
472                    r->out.ctr->ctr2.mszip1.ts) {
473                 ctr_level = 1;
474                 ctr1 = &r->out.ctr->ctr2.mszip1.ts->ctr1;
475         } else if (*r->out.level_out == 6) {
476                 ctr_level = 6;
477                 ctr6 = &r->out.ctr->ctr6;
478         } else if (*r->out.level_out == 7 &&
479                    r->out.ctr->ctr7.level == 6 &&
480                    r->out.ctr->ctr7.type == DRSUAPI_COMPRESSION_TYPE_MSZIP &&
481                    r->out.ctr->ctr7.ctr.mszip6.ts) {
482                 ctr_level = 6;
483                 ctr6 = &r->out.ctr->ctr7.ctr.mszip6.ts->ctr6;
484         } else if (*r->out.level_out == 7 &&
485                    r->out.ctr->ctr7.level == 6 &&
486                    r->out.ctr->ctr7.type == DRSUAPI_COMPRESSION_TYPE_XPRESS &&
487                    r->out.ctr->ctr7.ctr.xpress6.ts) {
488                 ctr_level = 6;
489                 ctr6 = &r->out.ctr->ctr7.ctr.xpress6.ts->ctr6;
490         } else {
491                 status = werror_to_ntstatus(WERR_BAD_NET_RESP);
492                 tevent_req_nterror(req, status);
493                 return;
494         }
495
496         if (!ctr1 && !ctr6) {
497                 status = werror_to_ntstatus(WERR_BAD_NET_RESP);
498                 tevent_req_nterror(req, status);
499                 return;
500         }
501
502         if (ctr_level == 6) {
503                 if (!W_ERROR_IS_OK(ctr6->drs_error)) {
504                         status = werror_to_ntstatus(ctr6->drs_error);
505                         tevent_req_nterror(req, status);
506                         return;
507                 }
508                 extended_ret = ctr6->extended_ret;
509         }
510
511         if (ctr_level == 1) {
512                 extended_ret = ctr1->extended_ret;
513         }
514
515         if (state->op->extended_op != DRSUAPI_EXOP_NONE) {
516                 state->op->extended_ret = extended_ret;
517
518                 if (extended_ret != DRSUAPI_EXOP_ERR_SUCCESS) {
519                         status = NT_STATUS_UNSUCCESSFUL;
520                         tevent_req_nterror(req, status);
521                         return;
522                 }
523         }
524
525         dreplsrv_op_pull_source_apply_changes_trigger(req, r, ctr_level, ctr1, ctr6);
526 }
527
528 static void dreplsrv_update_refs_trigger(struct tevent_req *req);
529
530 static void dreplsrv_op_pull_source_apply_changes_trigger(struct tevent_req *req,
531                                                           struct drsuapi_DsGetNCChanges *r,
532                                                           uint32_t ctr_level,
533                                                           struct drsuapi_DsGetNCChangesCtr1 *ctr1,
534                                                            struct drsuapi_DsGetNCChangesCtr6 *ctr6)
535 {
536         struct dreplsrv_op_pull_source_state *state = tevent_req_data(req,
537                                                       struct dreplsrv_op_pull_source_state);
538         struct repsFromTo1 rf1 = *state->op->source_dsa->repsFrom1;
539         struct dreplsrv_service *service = state->op->service;
540         struct dreplsrv_partition *partition = state->op->source_dsa->partition;
541         struct dreplsrv_drsuapi_connection *drsuapi = state->op->source_dsa->conn->drsuapi;
542         const struct drsuapi_DsReplicaOIDMapping_Ctr *mapping_ctr;
543         uint32_t object_count;
544         struct drsuapi_DsReplicaObjectListItemEx *first_object;
545         uint32_t linked_attributes_count;
546         struct drsuapi_DsReplicaLinkedAttribute *linked_attributes;
547         const struct drsuapi_DsReplicaCursor2CtrEx *uptodateness_vector;
548         struct dsdb_extended_replicated_objects *objects;
549         bool more_data = false;
550         WERROR status;
551         NTSTATUS nt_status;
552
553         switch (ctr_level) {
554         case 1:
555                 mapping_ctr                     = &ctr1->mapping_ctr;
556                 object_count                    = ctr1->object_count;
557                 first_object                    = ctr1->first_object;
558                 linked_attributes_count         = 0;
559                 linked_attributes               = NULL;
560                 rf1.highwatermark               = ctr1->new_highwatermark;
561                 uptodateness_vector             = NULL; /* TODO: map it */
562                 more_data                       = ctr1->more_data;
563                 break;
564         case 6:
565                 mapping_ctr                     = &ctr6->mapping_ctr;
566                 object_count                    = ctr6->object_count;
567                 first_object                    = ctr6->first_object;
568                 linked_attributes_count         = ctr6->linked_attributes_count;
569                 linked_attributes               = ctr6->linked_attributes;
570                 rf1.highwatermark               = ctr6->new_highwatermark;
571                 uptodateness_vector             = ctr6->uptodateness_vector;
572                 more_data                       = ctr6->more_data;
573                 break;
574         default:
575                 nt_status = werror_to_ntstatus(WERR_BAD_NET_RESP);
576                 tevent_req_nterror(req, nt_status);
577                 return;
578         }
579
580         status = dsdb_extended_replicated_objects_convert(service->samdb,
581                                                           partition->nc.dn,
582                                                           mapping_ctr,
583                                                           object_count,
584                                                           first_object,
585                                                           linked_attributes_count,
586                                                           linked_attributes,
587                                                           &rf1,
588                                                           uptodateness_vector,
589                                                           &drsuapi->gensec_skey,
590                                                           state, &objects);
591         if (!W_ERROR_IS_OK(status)) {
592                 nt_status = werror_to_ntstatus(WERR_BAD_NET_RESP);
593                 DEBUG(0,("Failed to convert objects: %s/%s\n",
594                           win_errstr(status), nt_errstr(nt_status)));
595                 tevent_req_nterror(req, nt_status);
596                 return;
597         }
598
599         status = dsdb_extended_replicated_objects_commit(service->samdb,
600                                                          objects, 
601                                                          &state->op->source_dsa->notify_uSN);
602         talloc_free(objects);
603         if (!W_ERROR_IS_OK(status)) {
604                 nt_status = werror_to_ntstatus(WERR_BAD_NET_RESP);
605                 DEBUG(0,("Failed to commit objects: %s/%s\n",
606                           win_errstr(status), nt_errstr(nt_status)));
607                 tevent_req_nterror(req, nt_status);
608                 return;
609         }
610         if (state->op->extended_op == DRSUAPI_EXOP_NONE) {
611                 /* if it applied fine, we need to update the highwatermark */
612                 *state->op->source_dsa->repsFrom1 = rf1;
613         }
614         /*
615          * TODO: update our uptodatevector!
616          */
617
618         /* we don't need this maybe very large structure anymore */
619         TALLOC_FREE(r);
620
621         if (more_data) {
622                 dreplsrv_op_pull_source_get_changes_trigger(req);
623                 return;
624         }
625
626         if (state->op->extended_op != DRSUAPI_EXOP_NONE ||
627             state->op->service->am_rodc) {
628                 /*
629                   we don't do the UpdateRefs for extended ops or if we
630                   are a RODC
631                  */
632                 tevent_req_done(req);
633                 return;
634         }
635
636         /* now we need to update the repsTo record for this partition
637            on the server. These records are initially established when
638            we join the domain, but they quickly expire.  We do it here
639            so we can use the already established DRSUAPI pipe
640         */
641         dreplsrv_update_refs_trigger(req);
642 }
643
644 static void dreplsrv_update_refs_done(struct tevent_req *subreq);
645
646 /*
647   send a UpdateRefs request to refresh our repsTo record on the server
648  */
649 static void dreplsrv_update_refs_trigger(struct tevent_req *req)
650 {
651         struct dreplsrv_op_pull_source_state *state = tevent_req_data(req,
652                                                       struct dreplsrv_op_pull_source_state);
653         struct dreplsrv_service *service = state->op->service;
654         struct dreplsrv_partition *partition = state->op->source_dsa->partition;
655         struct dreplsrv_drsuapi_connection *drsuapi = state->op->source_dsa->conn->drsuapi;
656         struct drsuapi_DsReplicaUpdateRefs *r;
657         char *ntds_guid_str;
658         char *ntds_dns_name;
659         struct tevent_req *subreq;
660
661         r = talloc(state, struct drsuapi_DsReplicaUpdateRefs);
662         if (tevent_req_nomem(r, req)) {
663                 return;
664         }
665
666         ntds_guid_str = GUID_string(r, &service->ntds_guid);
667         if (tevent_req_nomem(ntds_guid_str, req)) {
668                 return;
669         }
670
671         ntds_dns_name = talloc_asprintf(r, "%s._msdcs.%s",
672                                         ntds_guid_str,
673                                         lpcfg_dnsdomain(service->task->lp_ctx));
674         if (tevent_req_nomem(ntds_dns_name, req)) {
675                 return;
676         }
677
678         r->in.bind_handle       = &drsuapi->bind_handle;
679         r->in.level             = 1;
680         r->in.req.req1.naming_context     = &partition->nc;
681         r->in.req.req1.dest_dsa_dns_name  = ntds_dns_name;
682         r->in.req.req1.dest_dsa_guid      = service->ntds_guid;
683         r->in.req.req1.options            = DRSUAPI_DRS_ADD_REF | DRSUAPI_DRS_DEL_REF;
684         if (!service->am_rodc) {
685                 r->in.req.req1.options |= DRSUAPI_DRS_WRIT_REP;
686         }
687
688         state->ndr_struct_ptr = r;
689         subreq = dcerpc_drsuapi_DsReplicaUpdateRefs_r_send(state,
690                                                            state->ev,
691                                                            drsuapi->drsuapi_handle,
692                                                            r);
693         if (tevent_req_nomem(subreq, req)) {
694                 return;
695         }
696         tevent_req_set_callback(subreq, dreplsrv_update_refs_done, req);
697 }
698
699 /*
700   receive a UpdateRefs reply
701  */
702 static void dreplsrv_update_refs_done(struct tevent_req *subreq)
703 {
704         struct tevent_req *req = tevent_req_callback_data(subreq,
705                                  struct tevent_req);
706         struct dreplsrv_op_pull_source_state *state = tevent_req_data(req,
707                                                       struct dreplsrv_op_pull_source_state);
708         struct drsuapi_DsReplicaUpdateRefs *r = talloc_get_type(state->ndr_struct_ptr,
709                                                                 struct drsuapi_DsReplicaUpdateRefs);
710         NTSTATUS status;
711
712         state->ndr_struct_ptr = NULL;
713
714         status = dcerpc_drsuapi_DsReplicaUpdateRefs_r_recv(subreq, r);
715         TALLOC_FREE(subreq);
716         if (!NT_STATUS_IS_OK(status)) {
717                 DEBUG(0,("UpdateRefs failed with %s\n", 
718                          nt_errstr(status)));
719                 tevent_req_nterror(req, status);
720                 return;
721         }
722
723         if (!W_ERROR_IS_OK(r->out.result)) {
724                 status = werror_to_ntstatus(r->out.result);
725                 DEBUG(0,("UpdateRefs failed with %s/%s for %s %s\n",
726                          win_errstr(r->out.result),
727                          nt_errstr(status),
728                          r->in.req.req1.dest_dsa_dns_name,
729                          r->in.req.req1.naming_context->dn));
730                 tevent_req_nterror(req, status);
731                 return;
732         }
733
734         DEBUG(4,("UpdateRefs OK for %s %s\n", 
735                  r->in.req.req1.dest_dsa_dns_name,
736                  r->in.req.req1.naming_context->dn));
737
738         tevent_req_done(req);
739 }
740
741 WERROR dreplsrv_op_pull_source_recv(struct tevent_req *req)
742 {
743         NTSTATUS status;
744
745         if (tevent_req_is_nterror(req, &status)) {
746                 tevent_req_received(req);
747                 return ntstatus_to_werror(status);
748         }
749
750         tevent_req_received(req);
751         return WERR_OK;
752 }
753