Remove a number of NT_STATUS_HAVE_NO_MEMORY_AND_FREE macros from the codebase.
[bbaumbach/samba-autobuild/.git] / source4 / dsdb / repl / drepl_out_helpers.c
1 /* 
2    Unix SMB/CIFS mplementation.
3    DSDB replication service helper function for outgoing traffic
4    
5    Copyright (C) Stefan Metzmacher 2007
6     
7    This program is free software; you can redistribute it and/or modify
8    it under the terms of the GNU General Public License as published by
9    the Free Software Foundation; either version 3 of the License, or
10    (at your option) any later version.
11    
12    This program is distributed in the hope that it will be useful,
13    but WITHOUT ANY WARRANTY; without even the implied warranty of
14    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15    GNU General Public License for more details.
16    
17    You should have received a copy of the GNU General Public License
18    along with this program.  If not, see <http://www.gnu.org/licenses/>.
19    
20 */
21
22 #include "includes.h"
23 #include "dsdb/samdb/samdb.h"
24 #include "auth/auth.h"
25 #include "smbd/service.h"
26 #include "lib/events/events.h"
27 #include "dsdb/repl/drepl_service.h"
28 #include <ldb_errors.h>
29 #include "../lib/util/dlinklist.h"
30 #include "librpc/gen_ndr/ndr_misc.h"
31 #include "librpc/gen_ndr/ndr_drsuapi.h"
32 #include "librpc/gen_ndr/ndr_drsblobs.h"
33 #include "libcli/composite/composite.h"
34 #include "auth/gensec/gensec.h"
35 #include "param/param.h"
36 #include "../lib/util/tevent_ntstatus.h"
37 #include "libcli/security/security.h"
38
39 struct dreplsrv_out_drsuapi_state {
40         struct tevent_context *ev;
41
42         struct dreplsrv_out_connection *conn;
43
44         struct dreplsrv_drsuapi_connection *drsuapi;
45
46         struct drsuapi_DsBindInfoCtr bind_info_ctr;
47         struct drsuapi_DsBind bind_r;
48 };
49
50 static void dreplsrv_out_drsuapi_connect_done(struct composite_context *creq);
51
52 struct tevent_req *dreplsrv_out_drsuapi_send(TALLOC_CTX *mem_ctx,
53                                              struct tevent_context *ev,
54                                              struct dreplsrv_out_connection *conn)
55 {
56         struct tevent_req *req;
57         struct dreplsrv_out_drsuapi_state *state;
58         struct composite_context *creq;
59
60         req = tevent_req_create(mem_ctx, &state,
61                                 struct dreplsrv_out_drsuapi_state);
62         if (req == NULL) {
63                 return NULL;
64         }
65
66         state->ev       = ev;
67         state->conn     = conn;
68         state->drsuapi  = conn->drsuapi;
69
70         if (state->drsuapi && !state->drsuapi->pipe->conn->dead) {
71                 tevent_req_done(req);
72                 return tevent_req_post(req, ev);
73         }
74
75         if (state->drsuapi && state->drsuapi->pipe->conn->dead) {
76                 talloc_free(state->drsuapi);
77                 conn->drsuapi = NULL;
78         }
79
80         state->drsuapi = talloc_zero(state, struct dreplsrv_drsuapi_connection);
81         if (tevent_req_nomem(state->drsuapi, req)) {
82                 return tevent_req_post(req, ev);
83         }
84
85         creq = dcerpc_pipe_connect_b_send(state, conn->binding, &ndr_table_drsuapi,
86                                           conn->service->system_session_info->credentials,
87                                           ev, conn->service->task->lp_ctx);
88         if (tevent_req_nomem(creq, req)) {
89                 return tevent_req_post(req, ev);
90         }
91         composite_continue(NULL, creq, dreplsrv_out_drsuapi_connect_done, req);
92
93         return req;
94 }
95
96 static void dreplsrv_out_drsuapi_bind_done(struct tevent_req *subreq);
97
98 static void dreplsrv_out_drsuapi_connect_done(struct composite_context *creq)
99 {
100         struct tevent_req *req = talloc_get_type(creq->async.private_data,
101                                                  struct tevent_req);
102         struct dreplsrv_out_drsuapi_state *state = tevent_req_data(req,
103                                                    struct dreplsrv_out_drsuapi_state);
104         NTSTATUS status;
105         struct tevent_req *subreq;
106
107         status = dcerpc_pipe_connect_b_recv(creq,
108                                             state->drsuapi,
109                                             &state->drsuapi->pipe);
110         if (tevent_req_nterror(req, status)) {
111                 return;
112         }
113
114         state->drsuapi->drsuapi_handle = state->drsuapi->pipe->binding_handle;
115
116         status = gensec_session_key(state->drsuapi->pipe->conn->security_state.generic_state,
117                                     state->drsuapi,
118                                     &state->drsuapi->gensec_skey);
119         if (tevent_req_nterror(req, status)) {
120                 return;
121         }
122
123         state->bind_info_ctr.length             = 28;
124         state->bind_info_ctr.info.info28        = state->conn->service->bind_info28;
125
126         state->bind_r.in.bind_guid = &state->conn->service->ntds_guid;
127         state->bind_r.in.bind_info = &state->bind_info_ctr;
128         state->bind_r.out.bind_handle = &state->drsuapi->bind_handle;
129
130         subreq = dcerpc_drsuapi_DsBind_r_send(state,
131                                               state->ev,
132                                               state->drsuapi->drsuapi_handle,
133                                               &state->bind_r);
134         if (tevent_req_nomem(subreq, req)) {
135                 return;
136         }
137         tevent_req_set_callback(subreq, dreplsrv_out_drsuapi_bind_done, req);
138 }
139
140 static void dreplsrv_out_drsuapi_bind_done(struct tevent_req *subreq)
141 {
142         struct tevent_req *req = tevent_req_callback_data(subreq,
143                                  struct tevent_req);
144         struct dreplsrv_out_drsuapi_state *state = tevent_req_data(req,
145                                                    struct dreplsrv_out_drsuapi_state);
146         NTSTATUS status;
147
148         status = dcerpc_drsuapi_DsBind_r_recv(subreq, state);
149         TALLOC_FREE(subreq);
150         if (tevent_req_nterror(req, status)) {
151                 return;
152         }
153
154         if (!W_ERROR_IS_OK(state->bind_r.out.result)) {
155                 status = werror_to_ntstatus(state->bind_r.out.result);
156                 tevent_req_nterror(req, status);
157                 return;
158         }
159
160         ZERO_STRUCT(state->drsuapi->remote_info28);
161         if (state->bind_r.out.bind_info) {
162                 struct drsuapi_DsBindInfo28 *info28;
163                 info28 = &state->drsuapi->remote_info28;
164
165                 switch (state->bind_r.out.bind_info->length) {
166                 case 24: {
167                         struct drsuapi_DsBindInfo24 *info24;
168                         info24 = &state->bind_r.out.bind_info->info.info24;
169
170                         info28->supported_extensions    = info24->supported_extensions;
171                         info28->site_guid               = info24->site_guid;
172                         info28->pid                     = info24->pid;
173                         info28->repl_epoch              = 0;
174                         break;
175                 }
176                 case 48: {
177                         struct drsuapi_DsBindInfo48 *info48;
178                         info48 = &state->bind_r.out.bind_info->info.info48;
179
180                         info28->supported_extensions    = info48->supported_extensions;
181                         info28->site_guid               = info48->site_guid;
182                         info28->pid                     = info48->pid;
183                         info28->repl_epoch              = info48->repl_epoch;
184                         break;
185                 }
186                 case 28:
187                         *info28 = state->bind_r.out.bind_info->info.info28;
188                         break;
189                 }
190         }
191
192         tevent_req_done(req);
193 }
194
195 NTSTATUS dreplsrv_out_drsuapi_recv(struct tevent_req *req)
196 {
197         struct dreplsrv_out_drsuapi_state *state = tevent_req_data(req,
198                                                    struct dreplsrv_out_drsuapi_state);
199         NTSTATUS status;
200
201         if (tevent_req_is_nterror(req, &status)) {
202                 tevent_req_received(req);
203                 return status;
204         }
205
206         state->conn->drsuapi = talloc_move(state->conn, &state->drsuapi);
207
208         tevent_req_received(req);
209         return NT_STATUS_OK;
210 }
211
212 struct dreplsrv_op_pull_source_state {
213         struct tevent_context *ev;
214         struct dreplsrv_out_operation *op;
215         void *ndr_struct_ptr;
216 };
217
218 static void dreplsrv_op_pull_source_connect_done(struct tevent_req *subreq);
219
220 struct tevent_req *dreplsrv_op_pull_source_send(TALLOC_CTX *mem_ctx,
221                                                 struct tevent_context *ev,
222                                                 struct dreplsrv_out_operation *op)
223 {
224         struct tevent_req *req;
225         struct dreplsrv_op_pull_source_state *state;
226         struct tevent_req *subreq;
227
228         req = tevent_req_create(mem_ctx, &state,
229                                 struct dreplsrv_op_pull_source_state);
230         if (req == NULL) {
231                 return NULL;
232         }
233         state->ev = ev;
234         state->op = op;
235
236         subreq = dreplsrv_out_drsuapi_send(state, ev, op->source_dsa->conn);
237         if (tevent_req_nomem(subreq, req)) {
238                 return tevent_req_post(req, ev);
239         }
240         tevent_req_set_callback(subreq, dreplsrv_op_pull_source_connect_done, req);
241
242         return req;
243 }
244
245 static void dreplsrv_op_pull_source_get_changes_trigger(struct tevent_req *req);
246
247 static void dreplsrv_op_pull_source_connect_done(struct tevent_req *subreq)
248 {
249         struct tevent_req *req = tevent_req_callback_data(subreq,
250                                  struct tevent_req);
251         NTSTATUS status;
252
253         status = dreplsrv_out_drsuapi_recv(subreq);
254         TALLOC_FREE(subreq);
255         if (tevent_req_nterror(req, status)) {
256                 return;
257         }
258
259         dreplsrv_op_pull_source_get_changes_trigger(req);
260 }
261
262 static void dreplsrv_op_pull_source_get_changes_done(struct tevent_req *subreq);
263
264 /*
265   get a RODC partial attribute set for a replication call
266  */
267 static NTSTATUS dreplsrv_get_rodc_partial_attribute_set(struct dreplsrv_service *service,
268                                                         TALLOC_CTX *mem_ctx,
269                                                         struct drsuapi_DsPartialAttributeSet **_pas,
270                                                         bool for_schema)
271 {
272         struct drsuapi_DsPartialAttributeSet *pas;
273         struct dsdb_schema *schema;
274         uint32_t i;
275
276         pas = talloc_zero(mem_ctx, struct drsuapi_DsPartialAttributeSet);
277         NT_STATUS_HAVE_NO_MEMORY(pas);
278
279         schema = dsdb_get_schema(service->samdb, NULL);
280
281         pas->version = 1;
282         pas->attids = talloc_array(pas, enum drsuapi_DsAttributeId, schema->num_attributes);
283         if (pas->attids == NULL) {
284                 TALLOC_FREE(pas);
285                 return NT_STATUS_NO_MEMORY;
286         }
287
288         for (i=0; i<schema->num_attributes; i++) {
289                 struct dsdb_attribute *a;
290                 a = schema->attributes_by_attributeID_id[i];
291                 if (a->systemFlags & (DS_FLAG_ATTR_NOT_REPLICATED | DS_FLAG_ATTR_IS_CONSTRUCTED)) {
292                         continue;
293                 }
294                 if (a->searchFlags & SEARCH_FLAG_RODC_ATTRIBUTE) {
295                         continue;
296                 }
297                 pas->attids[pas->num_attids] = dsdb_attribute_get_attid(a, for_schema);
298                 pas->num_attids++;
299         }
300
301         pas->attids = talloc_realloc(pas, pas->attids, enum drsuapi_DsAttributeId, pas->num_attids);
302         if (pas->attids == NULL) {
303                 TALLOC_FREE(pas);
304                 return NT_STATUS_NO_MEMORY;
305         }
306
307         *_pas = pas;
308         return NT_STATUS_OK;
309 }
310
311
312 /*
313   get a GC partial attribute set for a replication call
314  */
315 static NTSTATUS dreplsrv_get_gc_partial_attribute_set(struct dreplsrv_service *service,
316                                                       TALLOC_CTX *mem_ctx,
317                                                       struct drsuapi_DsPartialAttributeSet **_pas)
318 {
319         struct drsuapi_DsPartialAttributeSet *pas;
320         struct dsdb_schema *schema;
321         uint32_t i;
322
323         pas = talloc_zero(mem_ctx, struct drsuapi_DsPartialAttributeSet);
324         NT_STATUS_HAVE_NO_MEMORY(pas);
325
326         schema = dsdb_get_schema(service->samdb, NULL);
327
328         pas->version = 1;
329         pas->attids = talloc_array(pas, enum drsuapi_DsAttributeId, schema->num_attributes);
330         if (pas->attids == NULL) {
331                 TALLOC_FREE(pas);
332                 return NT_STATUS_NO_MEMORY;
333         }
334
335         for (i=0; i<schema->num_attributes; i++) {
336                 struct dsdb_attribute *a;
337                 a = schema->attributes_by_attributeID_id[i];
338                 if (a->isMemberOfPartialAttributeSet) {
339                         pas->attids[pas->num_attids] = dsdb_attribute_get_attid(a, false);
340                         pas->num_attids++;
341                 }
342         }
343
344         pas->attids = talloc_realloc(pas, pas->attids, enum drsuapi_DsAttributeId, pas->num_attids);
345         if (pas->attids == NULL) {
346                 TALLOC_FREE(pas);
347                 return NT_STATUS_NO_MEMORY;
348         }
349
350         *_pas = pas;
351         return NT_STATUS_OK;
352 }
353
354 /*
355   convert from one udv format to the other
356  */
357 static WERROR udv_convert(TALLOC_CTX *mem_ctx,
358                           const struct replUpToDateVectorCtr2 *udv,
359                           struct drsuapi_DsReplicaCursorCtrEx *udv_ex)
360 {
361         uint32_t i;
362
363         udv_ex->version = 2;
364         udv_ex->reserved1 = 0;
365         udv_ex->reserved2 = 0;
366         udv_ex->count = udv->count;
367         udv_ex->cursors = talloc_array(mem_ctx, struct drsuapi_DsReplicaCursor, udv->count);
368         W_ERROR_HAVE_NO_MEMORY(udv_ex->cursors);
369
370         for (i=0; i<udv->count; i++) {
371                 udv_ex->cursors[i].source_dsa_invocation_id = udv->cursors[i].source_dsa_invocation_id;
372                 udv_ex->cursors[i].highest_usn = udv->cursors[i].highest_usn;
373         }
374
375         return WERR_OK;
376 }
377
378
379 static void dreplsrv_op_pull_source_get_changes_trigger(struct tevent_req *req)
380 {
381         struct dreplsrv_op_pull_source_state *state = tevent_req_data(req,
382                                                       struct dreplsrv_op_pull_source_state);
383         struct repsFromTo1 *rf1 = state->op->source_dsa->repsFrom1;
384         struct dreplsrv_service *service = state->op->service;
385         struct dreplsrv_partition *partition = state->op->source_dsa->partition;
386         struct dreplsrv_drsuapi_connection *drsuapi = state->op->source_dsa->conn->drsuapi;
387         struct drsuapi_DsGetNCChanges *r;
388         struct drsuapi_DsReplicaCursorCtrEx *uptodateness_vector;
389         struct tevent_req *subreq;
390         struct drsuapi_DsPartialAttributeSet *pas = NULL;
391         NTSTATUS status;
392         uint32_t replica_flags;
393         struct drsuapi_DsReplicaHighWaterMark highwatermark;
394
395         r = talloc(state, struct drsuapi_DsGetNCChanges);
396         if (tevent_req_nomem(r, req)) {
397                 return;
398         }
399
400         r->out.level_out = talloc(r, uint32_t);
401         if (tevent_req_nomem(r->out.level_out, req)) {
402                 return;
403         }
404         r->in.req = talloc(r, union drsuapi_DsGetNCChangesRequest);
405         if (tevent_req_nomem(r->in.req, req)) {
406                 return;
407         }
408         r->out.ctr = talloc(r, union drsuapi_DsGetNCChangesCtr);
409         if (tevent_req_nomem(r->out.ctr, req)) {
410                 return;
411         }
412
413         if (partition->uptodatevector.count != 0 &&
414             partition->uptodatevector_ex.count == 0) {
415                 WERROR werr;
416                 werr = udv_convert(partition, &partition->uptodatevector, &partition->uptodatevector_ex);
417                 if (!W_ERROR_IS_OK(werr)) {
418                         DEBUG(0,(__location__ ": Failed to convert UDV for %s : %s\n",
419                                  ldb_dn_get_linearized(partition->dn), win_errstr(werr)));
420                 }
421         }
422
423         if (partition->uptodatevector_ex.count == 0) {
424                 uptodateness_vector = NULL;
425         } else {
426                 uptodateness_vector = &partition->uptodatevector_ex;
427         }
428
429         replica_flags = rf1->replica_flags;
430         highwatermark = rf1->highwatermark;
431
432         if (partition->partial_replica) {
433                 status = dreplsrv_get_gc_partial_attribute_set(service, r, &pas);
434                 if (!NT_STATUS_IS_OK(status)) {
435                         DEBUG(0,(__location__ ": Failed to construct GC partial attribute set : %s\n", nt_errstr(status)));
436                         return;
437                 }
438                 replica_flags &= ~DRSUAPI_DRS_WRIT_REP;
439         } else if (partition->rodc_replica) {
440                 bool for_schema = false;
441                 if (ldb_dn_compare_base(ldb_get_schema_basedn(service->samdb), partition->dn) == 0) {
442                         for_schema = true;
443                 }
444
445                 status = dreplsrv_get_rodc_partial_attribute_set(service, r, &pas, for_schema);
446                 if (!NT_STATUS_IS_OK(status)) {
447                         DEBUG(0,(__location__ ": Failed to construct RODC partial attribute set : %s\n", nt_errstr(status)));
448                         return;
449                 }
450                 if (state->op->extended_op == DRSUAPI_EXOP_REPL_SECRET) {
451                         replica_flags &= ~DRSUAPI_DRS_SPECIAL_SECRET_PROCESSING;
452                 }
453         }
454         if (state->op->extended_op != DRSUAPI_EXOP_NONE) {
455                 /*
456                  * If it's an exop never set the ADD_REF even if it's in
457                  * repsFrom flags.
458                  */
459                 replica_flags &= ~DRSUAPI_DRS_ADD_REF;
460         }
461
462         /* is this a full resync of all objects? */
463         if (state->op->options & DRSUAPI_DRS_FULL_SYNC_NOW) {
464                 ZERO_STRUCT(highwatermark);
465                 /* clear the FULL_SYNC_NOW option for subsequent
466                    stages of the replication cycle */
467                 state->op->options &= ~DRSUAPI_DRS_FULL_SYNC_NOW;
468                 state->op->options |= DRSUAPI_DRS_FULL_SYNC_IN_PROGRESS;
469                 replica_flags |= DRSUAPI_DRS_NEVER_SYNCED;
470         }
471         if (state->op->options & DRSUAPI_DRS_FULL_SYNC_IN_PROGRESS) {
472                 uptodateness_vector = NULL;
473         }
474
475         r->in.bind_handle       = &drsuapi->bind_handle;
476         if (drsuapi->remote_info28.supported_extensions & DRSUAPI_SUPPORTED_EXTENSION_GETCHGREQ_V8) {
477                 r->in.level                             = 8;
478                 r->in.req->req8.destination_dsa_guid    = service->ntds_guid;
479                 r->in.req->req8.source_dsa_invocation_id= rf1->source_dsa_invocation_id;
480                 r->in.req->req8.naming_context          = &partition->nc;
481                 r->in.req->req8.highwatermark           = highwatermark;
482                 r->in.req->req8.uptodateness_vector     = uptodateness_vector;
483                 r->in.req->req8.replica_flags           = replica_flags;
484                 r->in.req->req8.max_object_count        = 133;
485                 r->in.req->req8.max_ndr_size            = 1336811;
486                 r->in.req->req8.extended_op             = state->op->extended_op;
487                 r->in.req->req8.fsmo_info               = state->op->fsmo_info;
488                 r->in.req->req8.partial_attribute_set   = pas;
489                 r->in.req->req8.partial_attribute_set_ex= NULL;
490                 r->in.req->req8.mapping_ctr.num_mappings= 0;
491                 r->in.req->req8.mapping_ctr.mappings    = NULL;
492         } else {
493                 r->in.level                             = 5;
494                 r->in.req->req5.destination_dsa_guid    = service->ntds_guid;
495                 r->in.req->req5.source_dsa_invocation_id= rf1->source_dsa_invocation_id;
496                 r->in.req->req5.naming_context          = &partition->nc;
497                 r->in.req->req5.highwatermark           = highwatermark;
498                 r->in.req->req5.uptodateness_vector     = uptodateness_vector;
499                 r->in.req->req5.replica_flags           = replica_flags;
500                 r->in.req->req5.max_object_count        = 133;
501                 r->in.req->req5.max_ndr_size            = 1336770;
502                 r->in.req->req5.extended_op             = state->op->extended_op;
503                 r->in.req->req5.fsmo_info               = state->op->fsmo_info;
504         }
505
506 #if 0
507         NDR_PRINT_IN_DEBUG(drsuapi_DsGetNCChanges, r);
508 #endif
509
510         state->ndr_struct_ptr = r;
511         subreq = dcerpc_drsuapi_DsGetNCChanges_r_send(state,
512                                                       state->ev,
513                                                       drsuapi->drsuapi_handle,
514                                                       r);
515         if (tevent_req_nomem(subreq, req)) {
516                 return;
517         }
518         tevent_req_set_callback(subreq, dreplsrv_op_pull_source_get_changes_done, req);
519 }
520
521 static void dreplsrv_op_pull_source_apply_changes_trigger(struct tevent_req *req,
522                                                           struct drsuapi_DsGetNCChanges *r,
523                                                           uint32_t ctr_level,
524                                                           struct drsuapi_DsGetNCChangesCtr1 *ctr1,
525                                                           struct drsuapi_DsGetNCChangesCtr6 *ctr6);
526
527 static void dreplsrv_op_pull_source_get_changes_done(struct tevent_req *subreq)
528 {
529         struct tevent_req *req = tevent_req_callback_data(subreq,
530                                  struct tevent_req);
531         struct dreplsrv_op_pull_source_state *state = tevent_req_data(req,
532                                                       struct dreplsrv_op_pull_source_state);
533         NTSTATUS status;
534         struct drsuapi_DsGetNCChanges *r = talloc_get_type(state->ndr_struct_ptr,
535                                            struct drsuapi_DsGetNCChanges);
536         uint32_t ctr_level = 0;
537         struct drsuapi_DsGetNCChangesCtr1 *ctr1 = NULL;
538         struct drsuapi_DsGetNCChangesCtr6 *ctr6 = NULL;
539         enum drsuapi_DsExtendedError extended_ret;
540         state->ndr_struct_ptr = NULL;
541
542         status = dcerpc_drsuapi_DsGetNCChanges_r_recv(subreq, r);
543         TALLOC_FREE(subreq);
544         if (tevent_req_nterror(req, status)) {
545                 return;
546         }
547
548         if (!W_ERROR_IS_OK(r->out.result)) {
549                 status = werror_to_ntstatus(r->out.result);
550                 tevent_req_nterror(req, status);
551                 return;
552         }
553
554         if (*r->out.level_out == 1) {
555                 ctr_level = 1;
556                 ctr1 = &r->out.ctr->ctr1;
557         } else if (*r->out.level_out == 2 &&
558                    r->out.ctr->ctr2.mszip1.ts) {
559                 ctr_level = 1;
560                 ctr1 = &r->out.ctr->ctr2.mszip1.ts->ctr1;
561         } else if (*r->out.level_out == 6) {
562                 ctr_level = 6;
563                 ctr6 = &r->out.ctr->ctr6;
564         } else if (*r->out.level_out == 7 &&
565                    r->out.ctr->ctr7.level == 6 &&
566                    r->out.ctr->ctr7.type == DRSUAPI_COMPRESSION_TYPE_MSZIP &&
567                    r->out.ctr->ctr7.ctr.mszip6.ts) {
568                 ctr_level = 6;
569                 ctr6 = &r->out.ctr->ctr7.ctr.mszip6.ts->ctr6;
570         } else if (*r->out.level_out == 7 &&
571                    r->out.ctr->ctr7.level == 6 &&
572                    r->out.ctr->ctr7.type == DRSUAPI_COMPRESSION_TYPE_XPRESS &&
573                    r->out.ctr->ctr7.ctr.xpress6.ts) {
574                 ctr_level = 6;
575                 ctr6 = &r->out.ctr->ctr7.ctr.xpress6.ts->ctr6;
576         } else {
577                 status = werror_to_ntstatus(WERR_BAD_NET_RESP);
578                 tevent_req_nterror(req, status);
579                 return;
580         }
581
582         if (!ctr1 && !ctr6) {
583                 status = werror_to_ntstatus(WERR_BAD_NET_RESP);
584                 tevent_req_nterror(req, status);
585                 return;
586         }
587
588         if (ctr_level == 6) {
589                 if (!W_ERROR_IS_OK(ctr6->drs_error)) {
590                         status = werror_to_ntstatus(ctr6->drs_error);
591                         tevent_req_nterror(req, status);
592                         return;
593                 }
594                 extended_ret = ctr6->extended_ret;
595         }
596
597         if (ctr_level == 1) {
598                 extended_ret = ctr1->extended_ret;
599         }
600
601         if (state->op->extended_op != DRSUAPI_EXOP_NONE) {
602                 state->op->extended_ret = extended_ret;
603
604                 if (extended_ret != DRSUAPI_EXOP_ERR_SUCCESS) {
605                         status = NT_STATUS_UNSUCCESSFUL;
606                         tevent_req_nterror(req, status);
607                         return;
608                 }
609         }
610
611         dreplsrv_op_pull_source_apply_changes_trigger(req, r, ctr_level, ctr1, ctr6);
612 }
613
614 static void dreplsrv_update_refs_trigger(struct tevent_req *req);
615
616 static void dreplsrv_op_pull_source_apply_changes_trigger(struct tevent_req *req,
617                                                           struct drsuapi_DsGetNCChanges *r,
618                                                           uint32_t ctr_level,
619                                                           struct drsuapi_DsGetNCChangesCtr1 *ctr1,
620                                                            struct drsuapi_DsGetNCChangesCtr6 *ctr6)
621 {
622         struct dreplsrv_op_pull_source_state *state = tevent_req_data(req,
623                                                       struct dreplsrv_op_pull_source_state);
624         struct repsFromTo1 rf1 = *state->op->source_dsa->repsFrom1;
625         struct dreplsrv_service *service = state->op->service;
626         struct dreplsrv_partition *partition = state->op->source_dsa->partition;
627         struct dreplsrv_drsuapi_connection *drsuapi = state->op->source_dsa->conn->drsuapi;
628         struct dsdb_schema *schema;
629         struct dsdb_schema *working_schema = NULL;
630         const struct drsuapi_DsReplicaOIDMapping_Ctr *mapping_ctr;
631         uint32_t object_count;
632         struct drsuapi_DsReplicaObjectListItemEx *first_object;
633         uint32_t linked_attributes_count;
634         struct drsuapi_DsReplicaLinkedAttribute *linked_attributes;
635         const struct drsuapi_DsReplicaCursor2CtrEx *uptodateness_vector;
636         struct dsdb_extended_replicated_objects *objects;
637         bool more_data = false;
638         WERROR status;
639         NTSTATUS nt_status;
640         uint32_t dsdb_repl_flags = 0;
641
642         switch (ctr_level) {
643         case 1:
644                 mapping_ctr                     = &ctr1->mapping_ctr;
645                 object_count                    = ctr1->object_count;
646                 first_object                    = ctr1->first_object;
647                 linked_attributes_count         = 0;
648                 linked_attributes               = NULL;
649                 rf1.source_dsa_obj_guid         = ctr1->source_dsa_guid;
650                 rf1.source_dsa_invocation_id    = ctr1->source_dsa_invocation_id;
651                 rf1.highwatermark               = ctr1->new_highwatermark;
652                 uptodateness_vector             = NULL; /* TODO: map it */
653                 more_data                       = ctr1->more_data;
654                 break;
655         case 6:
656                 mapping_ctr                     = &ctr6->mapping_ctr;
657                 object_count                    = ctr6->object_count;
658                 first_object                    = ctr6->first_object;
659                 linked_attributes_count         = ctr6->linked_attributes_count;
660                 linked_attributes               = ctr6->linked_attributes;
661                 rf1.source_dsa_obj_guid         = ctr6->source_dsa_guid;
662                 rf1.source_dsa_invocation_id    = ctr6->source_dsa_invocation_id;
663                 rf1.highwatermark               = ctr6->new_highwatermark;
664                 uptodateness_vector             = ctr6->uptodateness_vector;
665                 more_data                       = ctr6->more_data;
666                 break;
667         default:
668                 nt_status = werror_to_ntstatus(WERR_BAD_NET_RESP);
669                 tevent_req_nterror(req, nt_status);
670                 return;
671         }
672
673         schema = dsdb_get_schema(service->samdb, NULL);
674         if (!schema) {
675                 DEBUG(0,(__location__ ": Schema is not loaded yet!\n"));
676                 tevent_req_nterror(req, NT_STATUS_INTERNAL_ERROR);
677                 return;
678         }
679
680         /*
681          * Decide what working schema to use for object conversion.
682          * We won't need a working schema for empty replicas sent.
683          */
684         if (first_object && ldb_dn_compare(partition->dn, schema->base_dn) == 0) {
685                 /* create working schema to convert objects with */
686                 status = dsdb_repl_make_working_schema(service->samdb,
687                                                        schema,
688                                                        mapping_ctr,
689                                                        object_count,
690                                                        first_object,
691                                                        &drsuapi->gensec_skey,
692                                                        state, &working_schema);
693                 if (!W_ERROR_IS_OK(status)) {
694                         DEBUG(0,("Failed to create working schema: %s\n",
695                                  win_errstr(status)));
696                         tevent_req_nterror(req, NT_STATUS_INTERNAL_ERROR);
697                         return;
698                 }
699         }
700
701         if (partition->partial_replica || partition->rodc_replica) {
702                 dsdb_repl_flags |= DSDB_REPL_FLAG_PARTIAL_REPLICA;
703         }
704         if (state->op->options & DRSUAPI_DRS_FULL_SYNC_IN_PROGRESS) {
705                 dsdb_repl_flags |= DSDB_REPL_FLAG_PRIORITISE_INCOMING;
706         }
707
708         status = dsdb_replicated_objects_convert(service->samdb,
709                                                  working_schema ? working_schema : schema,
710                                                  partition->nc.dn,
711                                                  mapping_ctr,
712                                                  object_count,
713                                                  first_object,
714                                                  linked_attributes_count,
715                                                  linked_attributes,
716                                                  &rf1,
717                                                  uptodateness_vector,
718                                                  &drsuapi->gensec_skey,
719                                                  dsdb_repl_flags,
720                                                  state, &objects);
721         if (!W_ERROR_IS_OK(status)) {
722                 nt_status = werror_to_ntstatus(WERR_BAD_NET_RESP);
723                 DEBUG(0,("Failed to convert objects: %s/%s\n",
724                           win_errstr(status), nt_errstr(nt_status)));
725                 tevent_req_nterror(req, nt_status);
726                 return;
727         }
728
729         status = dsdb_replicated_objects_commit(service->samdb,
730                                                 working_schema,
731                                                 objects,
732                                                 &state->op->source_dsa->notify_uSN);
733         talloc_free(objects);
734         if (!W_ERROR_IS_OK(status)) {
735                 nt_status = werror_to_ntstatus(WERR_BAD_NET_RESP);
736                 DEBUG(0,("Failed to commit objects: %s/%s\n",
737                           win_errstr(status), nt_errstr(nt_status)));
738                 tevent_req_nterror(req, nt_status);
739                 return;
740         }
741
742         if (state->op->extended_op == DRSUAPI_EXOP_NONE) {
743                 /* if it applied fine, we need to update the highwatermark */
744                 *state->op->source_dsa->repsFrom1 = rf1;
745         }
746
747         /* we don't need this maybe very large structure anymore */
748         TALLOC_FREE(r);
749
750         if (more_data) {
751                 dreplsrv_op_pull_source_get_changes_trigger(req);
752                 return;
753         }
754
755         if (state->op->extended_op != DRSUAPI_EXOP_NONE ||
756             state->op->service->am_rodc) {
757                 /*
758                   we don't do the UpdateRefs for extended ops or if we
759                   are a RODC
760                  */
761                 tevent_req_done(req);
762                 return;
763         }
764
765         /* now we need to update the repsTo record for this partition
766            on the server. These records are initially established when
767            we join the domain, but they quickly expire.  We do it here
768            so we can use the already established DRSUAPI pipe
769         */
770         dreplsrv_update_refs_trigger(req);
771 }
772
773 static void dreplsrv_update_refs_done(struct tevent_req *subreq);
774
775 /*
776   send a UpdateRefs request to refresh our repsTo record on the server
777  */
778 static void dreplsrv_update_refs_trigger(struct tevent_req *req)
779 {
780         struct dreplsrv_op_pull_source_state *state = tevent_req_data(req,
781                                                       struct dreplsrv_op_pull_source_state);
782         struct dreplsrv_service *service = state->op->service;
783         struct dreplsrv_partition *partition = state->op->source_dsa->partition;
784         struct dreplsrv_drsuapi_connection *drsuapi = state->op->source_dsa->conn->drsuapi;
785         struct drsuapi_DsReplicaUpdateRefs *r;
786         char *ntds_dns_name;
787         struct tevent_req *subreq;
788
789         r = talloc(state, struct drsuapi_DsReplicaUpdateRefs);
790         if (tevent_req_nomem(r, req)) {
791                 return;
792         }
793
794         ntds_dns_name = samdb_ntds_msdcs_dns_name(service->samdb, r, &service->ntds_guid);
795         if (tevent_req_nomem(ntds_dns_name, req)) {
796                 talloc_free(r);
797                 return;
798         }
799
800         r->in.bind_handle       = &drsuapi->bind_handle;
801         r->in.level             = 1;
802         r->in.req.req1.naming_context     = &partition->nc;
803         r->in.req.req1.dest_dsa_dns_name  = ntds_dns_name;
804         r->in.req.req1.dest_dsa_guid      = service->ntds_guid;
805         r->in.req.req1.options            = DRSUAPI_DRS_ADD_REF | DRSUAPI_DRS_DEL_REF;
806         if (!service->am_rodc) {
807                 r->in.req.req1.options |= DRSUAPI_DRS_WRIT_REP;
808         }
809
810         state->ndr_struct_ptr = r;
811         subreq = dcerpc_drsuapi_DsReplicaUpdateRefs_r_send(state,
812                                                            state->ev,
813                                                            drsuapi->drsuapi_handle,
814                                                            r);
815         if (tevent_req_nomem(subreq, req)) {
816                 talloc_free(r);
817                 return;
818         }
819         tevent_req_set_callback(subreq, dreplsrv_update_refs_done, req);
820 }
821
822 /*
823   receive a UpdateRefs reply
824  */
825 static void dreplsrv_update_refs_done(struct tevent_req *subreq)
826 {
827         struct tevent_req *req = tevent_req_callback_data(subreq,
828                                  struct tevent_req);
829         struct dreplsrv_op_pull_source_state *state = tevent_req_data(req,
830                                                       struct dreplsrv_op_pull_source_state);
831         struct drsuapi_DsReplicaUpdateRefs *r = talloc_get_type(state->ndr_struct_ptr,
832                                                                 struct drsuapi_DsReplicaUpdateRefs);
833         NTSTATUS status;
834
835         state->ndr_struct_ptr = NULL;
836
837         status = dcerpc_drsuapi_DsReplicaUpdateRefs_r_recv(subreq, r);
838         TALLOC_FREE(subreq);
839         if (!NT_STATUS_IS_OK(status)) {
840                 DEBUG(0,("UpdateRefs failed with %s\n", 
841                          nt_errstr(status)));
842                 tevent_req_nterror(req, status);
843                 return;
844         }
845
846         if (!W_ERROR_IS_OK(r->out.result)) {
847                 status = werror_to_ntstatus(r->out.result);
848                 DEBUG(0,("UpdateRefs failed with %s/%s for %s %s\n",
849                          win_errstr(r->out.result),
850                          nt_errstr(status),
851                          r->in.req.req1.dest_dsa_dns_name,
852                          r->in.req.req1.naming_context->dn));
853                 /*
854                  * TODO we are currently not sending the
855                  * DsReplicaUpdateRefs at the correct moment,
856                  * we do it just after a GetNcChanges which is
857                  * not always correct.
858                  * Especially when another DC is trying to demote
859                  * it will sends us a DsReplicaSync that will trigger a getNcChanges
860                  * this call will succeed but the DsRecplicaUpdateRefs that we send
861                  * just after will not because the DC is in a demote state and
862                  * will reply us a WERR_DS_DRA_BUSY, this error will cause us to
863                  * answer to the DsReplicaSync with a non OK status, the other DC
864                  * will stop the demote due to this error.
865                  * In order to cope with this we will for the moment concider
866                  * a DS_DRA_BUSY not as an error.
867                  * It's not ideal but it should not have a too huge impact for
868                  * running production as this error otherwise never happen and
869                  * due to the fact the send a DsReplicaUpdateRefs after each getNcChanges
870                  */
871                 if (!W_ERROR_EQUAL(r->out.result, WERR_DS_DRA_BUSY)) {
872                         tevent_req_nterror(req, status);
873                         return;
874                 }
875         }
876
877         DEBUG(4,("UpdateRefs OK for %s %s\n", 
878                  r->in.req.req1.dest_dsa_dns_name,
879                  r->in.req.req1.naming_context->dn));
880
881         tevent_req_done(req);
882 }
883
884 WERROR dreplsrv_op_pull_source_recv(struct tevent_req *req)
885 {
886         NTSTATUS status;
887
888         if (tevent_req_is_nterror(req, &status)) {
889                 tevent_req_received(req);
890                 return ntstatus_to_werror(status);
891         }
892
893         tevent_req_received(req);
894         return WERR_OK;
895 }
896