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