idl:drsuapi: Manage all possible lengths of drsuapi_DsBindInfo
[samba.git] / source4 / dsdb / repl / drepl_out_helpers.c
1 /* 
2    Unix SMB/CIFS mplementation.
3    DSDB replication service helper function for outgoing traffic
4    
5    Copyright (C) Stefan Metzmacher 2007
6     
7    This program is free software; you can redistribute it and/or modify
8    it under the terms of the GNU General Public License as published by
9    the Free Software Foundation; either version 3 of the License, or
10    (at your option) any later version.
11    
12    This program is distributed in the hope that it will be useful,
13    but WITHOUT ANY WARRANTY; without even the implied warranty of
14    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15    GNU General Public License for more details.
16    
17    You should have received a copy of the GNU General Public License
18    along with this program.  If not, see <http://www.gnu.org/licenses/>.
19    
20 */
21
22 #include "includes.h"
23 #include "dsdb/samdb/samdb.h"
24 #include "auth/auth.h"
25 #include "smbd/service.h"
26 #include "lib/events/events.h"
27 #include "dsdb/repl/drepl_service.h"
28 #include <ldb_errors.h>
29 #include "../lib/util/dlinklist.h"
30 #include "librpc/gen_ndr/ndr_misc.h"
31 #include "librpc/gen_ndr/ndr_drsuapi.h"
32 #include "librpc/gen_ndr/ndr_drsblobs.h"
33 #include "libcli/composite/composite.h"
34 #include "auth/gensec/gensec.h"
35 #include "param/param.h"
36 #include "../lib/util/tevent_ntstatus.h"
37 #include "libcli/security/security.h"
38
39 struct dreplsrv_out_drsuapi_state {
40         struct tevent_context *ev;
41
42         struct dreplsrv_out_connection *conn;
43
44         struct dreplsrv_drsuapi_connection *drsuapi;
45
46         struct drsuapi_DsBindInfoCtr bind_info_ctr;
47         struct drsuapi_DsBind bind_r;
48 };
49
50 static void dreplsrv_out_drsuapi_connect_done(struct composite_context *creq);
51
52 struct tevent_req *dreplsrv_out_drsuapi_send(TALLOC_CTX *mem_ctx,
53                                              struct tevent_context *ev,
54                                              struct dreplsrv_out_connection *conn)
55 {
56         struct tevent_req *req;
57         struct dreplsrv_out_drsuapi_state *state;
58         struct composite_context *creq;
59
60         req = tevent_req_create(mem_ctx, &state,
61                                 struct dreplsrv_out_drsuapi_state);
62         if (req == NULL) {
63                 return NULL;
64         }
65
66         state->ev       = ev;
67         state->conn     = conn;
68         state->drsuapi  = conn->drsuapi;
69
70         if (state->drsuapi != 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 48: {
180                         struct drsuapi_DsBindInfo48 *info48;
181                         info48 = &state->bind_r.out.bind_info->info.info48;
182
183                         info28->supported_extensions    = info48->supported_extensions;
184                         info28->site_guid               = info48->site_guid;
185                         info28->pid                     = info48->pid;
186                         info28->repl_epoch              = info48->repl_epoch;
187                         break;
188                 }
189                 case 28: {
190                         *info28 = state->bind_r.out.bind_info->info.info28;
191                         break;
192                 }
193                 case 32: {
194                         struct drsuapi_DsBindInfo32 *info32;
195                         info32 = &state->bind_r.out.bind_info->info.info32;
196
197                         info28->supported_extensions    = info32->supported_extensions;
198                         info28->site_guid               = info32->site_guid;
199                         info28->pid                     = info32->pid;
200                         info28->repl_epoch              = info32->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                 if (state->op->extended_op == DRSUAPI_EXOP_REPL_SECRET) {
480                         replica_flags &= ~DRSUAPI_DRS_SPECIAL_SECRET_PROCESSING;
481                 }
482         }
483         if (state->op->extended_op != DRSUAPI_EXOP_NONE) {
484                 /*
485                  * If it's an exop never set the ADD_REF even if it's in
486                  * repsFrom flags.
487                  */
488                 replica_flags &= ~DRSUAPI_DRS_ADD_REF;
489         }
490
491         /* is this a full resync of all objects? */
492         if (state->op->options & DRSUAPI_DRS_FULL_SYNC_NOW) {
493                 ZERO_STRUCT(highwatermark);
494                 /* clear the FULL_SYNC_NOW option for subsequent
495                    stages of the replication cycle */
496                 state->op->options &= ~DRSUAPI_DRS_FULL_SYNC_NOW;
497                 state->op->options |= DRSUAPI_DRS_FULL_SYNC_IN_PROGRESS;
498                 replica_flags |= DRSUAPI_DRS_NEVER_SYNCED;
499         }
500         if (state->op->options & DRSUAPI_DRS_FULL_SYNC_IN_PROGRESS) {
501                 uptodateness_vector = NULL;
502         }
503
504         r->in.bind_handle       = &drsuapi->bind_handle;
505         if (drsuapi->remote_info28.supported_extensions & DRSUAPI_SUPPORTED_EXTENSION_GETCHGREQ_V8) {
506                 r->in.level                             = 8;
507                 r->in.req->req8.destination_dsa_guid    = service->ntds_guid;
508                 r->in.req->req8.source_dsa_invocation_id= rf1->source_dsa_invocation_id;
509                 r->in.req->req8.naming_context          = &partition->nc;
510                 r->in.req->req8.highwatermark           = highwatermark;
511                 r->in.req->req8.uptodateness_vector     = uptodateness_vector;
512                 r->in.req->req8.replica_flags           = replica_flags;
513                 r->in.req->req8.max_object_count        = 133;
514                 r->in.req->req8.max_ndr_size            = 1336811;
515                 r->in.req->req8.extended_op             = state->op->extended_op;
516                 r->in.req->req8.fsmo_info               = state->op->fsmo_info;
517                 r->in.req->req8.partial_attribute_set   = pas;
518                 r->in.req->req8.partial_attribute_set_ex= NULL;
519                 r->in.req->req8.mapping_ctr.num_mappings= 0;
520                 r->in.req->req8.mapping_ctr.mappings    = NULL;
521         } else {
522                 r->in.level                             = 5;
523                 r->in.req->req5.destination_dsa_guid    = service->ntds_guid;
524                 r->in.req->req5.source_dsa_invocation_id= rf1->source_dsa_invocation_id;
525                 r->in.req->req5.naming_context          = &partition->nc;
526                 r->in.req->req5.highwatermark           = highwatermark;
527                 r->in.req->req5.uptodateness_vector     = uptodateness_vector;
528                 r->in.req->req5.replica_flags           = replica_flags;
529                 r->in.req->req5.max_object_count        = 133;
530                 r->in.req->req5.max_ndr_size            = 1336770;
531                 r->in.req->req5.extended_op             = state->op->extended_op;
532                 r->in.req->req5.fsmo_info               = state->op->fsmo_info;
533         }
534
535 #if 0
536         NDR_PRINT_IN_DEBUG(drsuapi_DsGetNCChanges, r);
537 #endif
538
539         state->ndr_struct_ptr = r;
540         subreq = dcerpc_drsuapi_DsGetNCChanges_r_send(state,
541                                                       state->ev,
542                                                       drsuapi->drsuapi_handle,
543                                                       r);
544         if (tevent_req_nomem(subreq, req)) {
545                 return;
546         }
547         tevent_req_set_callback(subreq, dreplsrv_op_pull_source_get_changes_done, req);
548 }
549
550 static void dreplsrv_op_pull_source_apply_changes_trigger(struct tevent_req *req,
551                                                           struct drsuapi_DsGetNCChanges *r,
552                                                           uint32_t ctr_level,
553                                                           struct drsuapi_DsGetNCChangesCtr1 *ctr1,
554                                                           struct drsuapi_DsGetNCChangesCtr6 *ctr6);
555
556 static void dreplsrv_op_pull_source_get_changes_done(struct tevent_req *subreq)
557 {
558         struct tevent_req *req = tevent_req_callback_data(subreq,
559                                  struct tevent_req);
560         struct dreplsrv_op_pull_source_state *state = tevent_req_data(req,
561                                                       struct dreplsrv_op_pull_source_state);
562         NTSTATUS status;
563         struct drsuapi_DsGetNCChanges *r = talloc_get_type(state->ndr_struct_ptr,
564                                            struct drsuapi_DsGetNCChanges);
565         uint32_t ctr_level = 0;
566         struct drsuapi_DsGetNCChangesCtr1 *ctr1 = NULL;
567         struct drsuapi_DsGetNCChangesCtr6 *ctr6 = NULL;
568         enum drsuapi_DsExtendedError extended_ret;
569         state->ndr_struct_ptr = NULL;
570
571         status = dcerpc_drsuapi_DsGetNCChanges_r_recv(subreq, r);
572         TALLOC_FREE(subreq);
573         if (tevent_req_nterror(req, status)) {
574                 return;
575         }
576
577         if (!W_ERROR_IS_OK(r->out.result)) {
578                 status = werror_to_ntstatus(r->out.result);
579                 tevent_req_nterror(req, status);
580                 return;
581         }
582
583         if (*r->out.level_out == 1) {
584                 ctr_level = 1;
585                 ctr1 = &r->out.ctr->ctr1;
586         } else if (*r->out.level_out == 2 &&
587                    r->out.ctr->ctr2.mszip1.ts) {
588                 ctr_level = 1;
589                 ctr1 = &r->out.ctr->ctr2.mszip1.ts->ctr1;
590         } else if (*r->out.level_out == 6) {
591                 ctr_level = 6;
592                 ctr6 = &r->out.ctr->ctr6;
593         } else if (*r->out.level_out == 7 &&
594                    r->out.ctr->ctr7.level == 6 &&
595                    r->out.ctr->ctr7.type == DRSUAPI_COMPRESSION_TYPE_MSZIP &&
596                    r->out.ctr->ctr7.ctr.mszip6.ts) {
597                 ctr_level = 6;
598                 ctr6 = &r->out.ctr->ctr7.ctr.mszip6.ts->ctr6;
599         } else if (*r->out.level_out == 7 &&
600                    r->out.ctr->ctr7.level == 6 &&
601                    r->out.ctr->ctr7.type == DRSUAPI_COMPRESSION_TYPE_XPRESS &&
602                    r->out.ctr->ctr7.ctr.xpress6.ts) {
603                 ctr_level = 6;
604                 ctr6 = &r->out.ctr->ctr7.ctr.xpress6.ts->ctr6;
605         } else {
606                 status = werror_to_ntstatus(WERR_BAD_NET_RESP);
607                 tevent_req_nterror(req, status);
608                 return;
609         }
610
611         if (!ctr1 && !ctr6) {
612                 status = werror_to_ntstatus(WERR_BAD_NET_RESP);
613                 tevent_req_nterror(req, status);
614                 return;
615         }
616
617         if (ctr_level == 6) {
618                 if (!W_ERROR_IS_OK(ctr6->drs_error)) {
619                         status = werror_to_ntstatus(ctr6->drs_error);
620                         tevent_req_nterror(req, status);
621                         return;
622                 }
623                 extended_ret = ctr6->extended_ret;
624         }
625
626         if (ctr_level == 1) {
627                 extended_ret = ctr1->extended_ret;
628         }
629
630         if (state->op->extended_op != DRSUAPI_EXOP_NONE) {
631                 state->op->extended_ret = extended_ret;
632
633                 if (extended_ret != DRSUAPI_EXOP_ERR_SUCCESS) {
634                         status = NT_STATUS_UNSUCCESSFUL;
635                         tevent_req_nterror(req, status);
636                         return;
637                 }
638         }
639
640         dreplsrv_op_pull_source_apply_changes_trigger(req, r, ctr_level, ctr1, ctr6);
641 }
642
643 static void dreplsrv_update_refs_trigger(struct tevent_req *req);
644
645 static void dreplsrv_op_pull_source_apply_changes_trigger(struct tevent_req *req,
646                                                           struct drsuapi_DsGetNCChanges *r,
647                                                           uint32_t ctr_level,
648                                                           struct drsuapi_DsGetNCChangesCtr1 *ctr1,
649                                                            struct drsuapi_DsGetNCChangesCtr6 *ctr6)
650 {
651         struct dreplsrv_op_pull_source_state *state = tevent_req_data(req,
652                                                       struct dreplsrv_op_pull_source_state);
653         struct repsFromTo1 rf1 = *state->op->source_dsa->repsFrom1;
654         struct dreplsrv_service *service = state->op->service;
655         struct dreplsrv_partition *partition = state->op->source_dsa->partition;
656         struct dreplsrv_drsuapi_connection *drsuapi = state->op->source_dsa->conn->drsuapi;
657         struct ldb_dn *schema_dn = ldb_get_schema_basedn(service->samdb);
658         struct dsdb_schema *schema;
659         struct dsdb_schema *working_schema = NULL;
660         const struct drsuapi_DsReplicaOIDMapping_Ctr *mapping_ctr;
661         uint32_t object_count;
662         struct drsuapi_DsReplicaObjectListItemEx *first_object;
663         uint32_t linked_attributes_count;
664         struct drsuapi_DsReplicaLinkedAttribute *linked_attributes;
665         const struct drsuapi_DsReplicaCursor2CtrEx *uptodateness_vector;
666         struct dsdb_extended_replicated_objects *objects;
667         bool more_data = false;
668         WERROR status;
669         NTSTATUS nt_status;
670         uint32_t dsdb_repl_flags = 0;
671
672         switch (ctr_level) {
673         case 1:
674                 mapping_ctr                     = &ctr1->mapping_ctr;
675                 object_count                    = ctr1->object_count;
676                 first_object                    = ctr1->first_object;
677                 linked_attributes_count         = 0;
678                 linked_attributes               = NULL;
679                 rf1.source_dsa_obj_guid         = ctr1->source_dsa_guid;
680                 rf1.source_dsa_invocation_id    = ctr1->source_dsa_invocation_id;
681                 rf1.highwatermark               = ctr1->new_highwatermark;
682                 uptodateness_vector             = NULL; /* TODO: map it */
683                 more_data                       = ctr1->more_data;
684                 break;
685         case 6:
686                 mapping_ctr                     = &ctr6->mapping_ctr;
687                 object_count                    = ctr6->object_count;
688                 first_object                    = ctr6->first_object;
689                 linked_attributes_count         = ctr6->linked_attributes_count;
690                 linked_attributes               = ctr6->linked_attributes;
691                 rf1.source_dsa_obj_guid         = ctr6->source_dsa_guid;
692                 rf1.source_dsa_invocation_id    = ctr6->source_dsa_invocation_id;
693                 rf1.highwatermark               = ctr6->new_highwatermark;
694                 uptodateness_vector             = ctr6->uptodateness_vector;
695                 more_data                       = ctr6->more_data;
696                 break;
697         default:
698                 nt_status = werror_to_ntstatus(WERR_BAD_NET_RESP);
699                 tevent_req_nterror(req, nt_status);
700                 return;
701         }
702
703         schema = dsdb_get_schema(service->samdb, NULL);
704         if (!schema) {
705                 DEBUG(0,(__location__ ": Schema is not loaded yet!\n"));
706                 tevent_req_nterror(req, NT_STATUS_INTERNAL_ERROR);
707                 return;
708         }
709
710         /*
711          * Decide what working schema to use for object conversion.
712          * We won't need a working schema for empty replicas sent.
713          */
714         if (first_object) {
715                 bool is_schema = ldb_dn_compare(partition->dn, schema_dn) == 0;
716                 if (is_schema) {
717                         /* create working schema to convert objects with */
718                         status = dsdb_repl_make_working_schema(service->samdb,
719                                                                schema,
720                                                                mapping_ctr,
721                                                                object_count,
722                                                                first_object,
723                                                                &drsuapi->gensec_skey,
724                                                                state, &working_schema);
725                         if (!W_ERROR_IS_OK(status)) {
726                                 DEBUG(0,("Failed to create working schema: %s\n",
727                                          win_errstr(status)));
728                                 tevent_req_nterror(req, NT_STATUS_INTERNAL_ERROR);
729                                 return;
730                         }
731                 }
732         }
733
734         if (partition->partial_replica || partition->rodc_replica) {
735                 dsdb_repl_flags |= DSDB_REPL_FLAG_PARTIAL_REPLICA;
736         }
737         if (state->op->options & DRSUAPI_DRS_FULL_SYNC_IN_PROGRESS) {
738                 dsdb_repl_flags |= DSDB_REPL_FLAG_PRIORITISE_INCOMING;
739         }
740
741         status = dsdb_replicated_objects_convert(service->samdb,
742                                                  working_schema ? working_schema : schema,
743                                                  partition->nc.dn,
744                                                  mapping_ctr,
745                                                  object_count,
746                                                  first_object,
747                                                  linked_attributes_count,
748                                                  linked_attributes,
749                                                  &rf1,
750                                                  uptodateness_vector,
751                                                  &drsuapi->gensec_skey,
752                                                  dsdb_repl_flags,
753                                                  state, &objects);
754         if (!W_ERROR_IS_OK(status)) {
755                 nt_status = werror_to_ntstatus(WERR_BAD_NET_RESP);
756                 DEBUG(0,("Failed to convert objects: %s/%s\n",
757                           win_errstr(status), nt_errstr(nt_status)));
758                 tevent_req_nterror(req, nt_status);
759                 return;
760         }
761
762         status = dsdb_replicated_objects_commit(service->samdb,
763                                                 working_schema,
764                                                 objects,
765                                                 &state->op->source_dsa->notify_uSN);
766         talloc_free(objects);
767         if (!W_ERROR_IS_OK(status)) {
768                 nt_status = werror_to_ntstatus(WERR_BAD_NET_RESP);
769                 DEBUG(0,("Failed to commit objects: %s/%s\n",
770                           win_errstr(status), nt_errstr(nt_status)));
771                 tevent_req_nterror(req, nt_status);
772                 return;
773         }
774
775         if (state->op->extended_op == DRSUAPI_EXOP_NONE) {
776                 /* if it applied fine, we need to update the highwatermark */
777                 *state->op->source_dsa->repsFrom1 = rf1;
778         }
779
780         /* we don't need this maybe very large structure anymore */
781         TALLOC_FREE(r);
782
783         if (more_data) {
784                 dreplsrv_op_pull_source_get_changes_trigger(req);
785                 return;
786         }
787
788         if (state->op->extended_op != DRSUAPI_EXOP_NONE ||
789             state->op->service->am_rodc) {
790                 /*
791                   we don't do the UpdateRefs for extended ops or if we
792                   are a RODC
793                  */
794                 tevent_req_done(req);
795                 return;
796         }
797
798         /* now we need to update the repsTo record for this partition
799            on the server. These records are initially established when
800            we join the domain, but they quickly expire.  We do it here
801            so we can use the already established DRSUAPI pipe
802         */
803         dreplsrv_update_refs_trigger(req);
804 }
805
806 static void dreplsrv_update_refs_done(struct tevent_req *subreq);
807
808 /*
809   send a UpdateRefs request to refresh our repsTo record on the server
810  */
811 static void dreplsrv_update_refs_trigger(struct tevent_req *req)
812 {
813         struct dreplsrv_op_pull_source_state *state = tevent_req_data(req,
814                                                       struct dreplsrv_op_pull_source_state);
815         struct dreplsrv_service *service = state->op->service;
816         struct dreplsrv_partition *partition = state->op->source_dsa->partition;
817         struct dreplsrv_drsuapi_connection *drsuapi = state->op->source_dsa->conn->drsuapi;
818         struct drsuapi_DsReplicaUpdateRefs *r;
819         char *ntds_dns_name;
820         struct tevent_req *subreq;
821
822         r = talloc(state, struct drsuapi_DsReplicaUpdateRefs);
823         if (tevent_req_nomem(r, req)) {
824                 return;
825         }
826
827         ntds_dns_name = samdb_ntds_msdcs_dns_name(service->samdb, r, &service->ntds_guid);
828         if (tevent_req_nomem(ntds_dns_name, req)) {
829                 talloc_free(r);
830                 return;
831         }
832
833         r->in.bind_handle       = &drsuapi->bind_handle;
834         r->in.level             = 1;
835         r->in.req.req1.naming_context     = &partition->nc;
836         r->in.req.req1.dest_dsa_dns_name  = ntds_dns_name;
837         r->in.req.req1.dest_dsa_guid      = service->ntds_guid;
838         r->in.req.req1.options            = DRSUAPI_DRS_ADD_REF | DRSUAPI_DRS_DEL_REF;
839         if (!service->am_rodc) {
840                 r->in.req.req1.options |= DRSUAPI_DRS_WRIT_REP;
841         }
842
843         state->ndr_struct_ptr = r;
844         subreq = dcerpc_drsuapi_DsReplicaUpdateRefs_r_send(state,
845                                                            state->ev,
846                                                            drsuapi->drsuapi_handle,
847                                                            r);
848         if (tevent_req_nomem(subreq, req)) {
849                 talloc_free(r);
850                 return;
851         }
852         tevent_req_set_callback(subreq, dreplsrv_update_refs_done, req);
853 }
854
855 /*
856   receive a UpdateRefs reply
857  */
858 static void dreplsrv_update_refs_done(struct tevent_req *subreq)
859 {
860         struct tevent_req *req = tevent_req_callback_data(subreq,
861                                  struct tevent_req);
862         struct dreplsrv_op_pull_source_state *state = tevent_req_data(req,
863                                                       struct dreplsrv_op_pull_source_state);
864         struct drsuapi_DsReplicaUpdateRefs *r = talloc_get_type(state->ndr_struct_ptr,
865                                                                 struct drsuapi_DsReplicaUpdateRefs);
866         NTSTATUS status;
867
868         state->ndr_struct_ptr = NULL;
869
870         status = dcerpc_drsuapi_DsReplicaUpdateRefs_r_recv(subreq, r);
871         TALLOC_FREE(subreq);
872         if (!NT_STATUS_IS_OK(status)) {
873                 DEBUG(0,("UpdateRefs failed with %s\n", 
874                          nt_errstr(status)));
875                 tevent_req_nterror(req, status);
876                 return;
877         }
878
879         if (!W_ERROR_IS_OK(r->out.result)) {
880                 status = werror_to_ntstatus(r->out.result);
881                 DEBUG(0,("UpdateRefs failed with %s/%s for %s %s\n",
882                          win_errstr(r->out.result),
883                          nt_errstr(status),
884                          r->in.req.req1.dest_dsa_dns_name,
885                          r->in.req.req1.naming_context->dn));
886                 /*
887                  * TODO we are currently not sending the
888                  * DsReplicaUpdateRefs at the correct moment,
889                  * we do it just after a GetNcChanges which is
890                  * not always correct.
891                  * Especially when another DC is trying to demote
892                  * it will sends us a DsReplicaSync that will trigger a getNcChanges
893                  * this call will succeed but the DsRecplicaUpdateRefs that we send
894                  * just after will not because the DC is in a demote state and
895                  * will reply us a WERR_DS_DRA_BUSY, this error will cause us to
896                  * answer to the DsReplicaSync with a non OK status, the other DC
897                  * will stop the demote due to this error.
898                  * In order to cope with this we will for the moment concider
899                  * a DS_DRA_BUSY not as an error.
900                  * It's not ideal but it should not have a too huge impact for
901                  * running production as this error otherwise never happen and
902                  * due to the fact the send a DsReplicaUpdateRefs after each getNcChanges
903                  */
904                 if (!W_ERROR_EQUAL(r->out.result, WERR_DS_DRA_BUSY)) {
905                         tevent_req_nterror(req, status);
906                         return;
907                 }
908         }
909
910         DEBUG(4,("UpdateRefs OK for %s %s\n", 
911                  r->in.req.req1.dest_dsa_dns_name,
912                  r->in.req.req1.naming_context->dn));
913
914         tevent_req_done(req);
915 }
916
917 WERROR dreplsrv_op_pull_source_recv(struct tevent_req *req)
918 {
919         NTSTATUS status;
920
921         if (tevent_req_is_nterror(req, &status)) {
922                 tevent_req_received(req);
923                 return ntstatus_to_werror(status);
924         }
925
926         tevent_req_received(req);
927         return WERR_OK;
928 }
929