docs: fix a typo in history file
[bbaumbach/samba-autobuild/.git] / source4 / dsdb / repl / drepl_out_helpers.c
1 /* 
2    Unix SMB/CIFS Implementation.
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 "samba/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 #undef DBGC_CLASS
40 #define DBGC_CLASS            DBGC_DRS_REPL
41
42 struct dreplsrv_out_drsuapi_state {
43         struct tevent_context *ev;
44
45         struct dreplsrv_out_connection *conn;
46
47         struct dreplsrv_drsuapi_connection *drsuapi;
48
49         struct drsuapi_DsBindInfoCtr bind_info_ctr;
50         struct drsuapi_DsBind bind_r;
51 };
52
53 static void dreplsrv_out_drsuapi_connect_done(struct composite_context *creq);
54
55 struct tevent_req *dreplsrv_out_drsuapi_send(TALLOC_CTX *mem_ctx,
56                                              struct tevent_context *ev,
57                                              struct dreplsrv_out_connection *conn)
58 {
59         struct tevent_req *req;
60         struct dreplsrv_out_drsuapi_state *state;
61         struct composite_context *creq;
62
63         req = tevent_req_create(mem_ctx, &state,
64                                 struct dreplsrv_out_drsuapi_state);
65         if (req == NULL) {
66                 return NULL;
67         }
68
69         state->ev       = ev;
70         state->conn     = conn;
71         state->drsuapi  = conn->drsuapi;
72
73         if (state->drsuapi != NULL) {
74                 struct dcerpc_binding_handle *b =
75                         state->drsuapi->pipe->binding_handle;
76                 bool is_connected = dcerpc_binding_handle_is_connected(b);
77
78                 if (is_connected) {
79                         tevent_req_done(req);
80                         return tevent_req_post(req, ev);
81                 }
82
83                 TALLOC_FREE(conn->drsuapi);
84         }
85
86         state->drsuapi = talloc_zero(state, struct dreplsrv_drsuapi_connection);
87         if (tevent_req_nomem(state->drsuapi, req)) {
88                 return tevent_req_post(req, ev);
89         }
90
91         creq = dcerpc_pipe_connect_b_send(state, conn->binding, &ndr_table_drsuapi,
92                                           conn->service->system_session_info->credentials,
93                                           ev, conn->service->task->lp_ctx);
94         if (tevent_req_nomem(creq, req)) {
95                 return tevent_req_post(req, ev);
96         }
97         composite_continue(NULL, creq, dreplsrv_out_drsuapi_connect_done, req);
98
99         return req;
100 }
101
102 static void dreplsrv_out_drsuapi_bind_done(struct tevent_req *subreq);
103
104 static void dreplsrv_out_drsuapi_connect_done(struct composite_context *creq)
105 {
106         struct tevent_req *req = talloc_get_type(creq->async.private_data,
107                                                  struct tevent_req);
108         struct dreplsrv_out_drsuapi_state *state = tevent_req_data(req,
109                                                    struct dreplsrv_out_drsuapi_state);
110         NTSTATUS status;
111         struct tevent_req *subreq;
112
113         status = dcerpc_pipe_connect_b_recv(creq,
114                                             state->drsuapi,
115                                             &state->drsuapi->pipe);
116         if (tevent_req_nterror(req, status)) {
117                 return;
118         }
119
120         state->drsuapi->drsuapi_handle = state->drsuapi->pipe->binding_handle;
121
122         status = gensec_session_key(state->drsuapi->pipe->conn->security_state.generic_state,
123                                     state->drsuapi,
124                                     &state->drsuapi->gensec_skey);
125         if (tevent_req_nterror(req, status)) {
126                 return;
127         }
128
129         state->bind_info_ctr.length             = 28;
130         state->bind_info_ctr.info.info28        = state->conn->service->bind_info28;
131
132         state->bind_r.in.bind_guid = &state->conn->service->ntds_guid;
133         state->bind_r.in.bind_info = &state->bind_info_ctr;
134         state->bind_r.out.bind_handle = &state->drsuapi->bind_handle;
135
136         subreq = dcerpc_drsuapi_DsBind_r_send(state,
137                                               state->ev,
138                                               state->drsuapi->drsuapi_handle,
139                                               &state->bind_r);
140         if (tevent_req_nomem(subreq, req)) {
141                 return;
142         }
143         tevent_req_set_callback(subreq, dreplsrv_out_drsuapi_bind_done, req);
144 }
145
146 static void dreplsrv_out_drsuapi_bind_done(struct tevent_req *subreq)
147 {
148         struct tevent_req *req = tevent_req_callback_data(subreq,
149                                  struct tevent_req);
150         struct dreplsrv_out_drsuapi_state *state = tevent_req_data(req,
151                                                    struct dreplsrv_out_drsuapi_state);
152         NTSTATUS status;
153
154         status = dcerpc_drsuapi_DsBind_r_recv(subreq, state);
155         TALLOC_FREE(subreq);
156         if (tevent_req_nterror(req, status)) {
157                 return;
158         }
159
160         if (!W_ERROR_IS_OK(state->bind_r.out.result)) {
161                 status = werror_to_ntstatus(state->bind_r.out.result);
162                 tevent_req_nterror(req, status);
163                 return;
164         }
165
166         ZERO_STRUCT(state->drsuapi->remote_info28);
167         if (state->bind_r.out.bind_info) {
168                 struct drsuapi_DsBindInfo28 *info28;
169                 info28 = &state->drsuapi->remote_info28;
170
171                 switch (state->bind_r.out.bind_info->length) {
172                 case 24: {
173                         struct drsuapi_DsBindInfo24 *info24;
174                         info24 = &state->bind_r.out.bind_info->info.info24;
175
176                         info28->supported_extensions    = info24->supported_extensions;
177                         info28->site_guid               = info24->site_guid;
178                         info28->pid                     = info24->pid;
179                         info28->repl_epoch              = 0;
180                         break;
181                 }
182                 case 28: {
183                         *info28 = state->bind_r.out.bind_info->info.info28;
184                         break;
185                 }
186                 case 32: {
187                         struct drsuapi_DsBindInfo32 *info32;
188                         info32 = &state->bind_r.out.bind_info->info.info32;
189
190                         info28->supported_extensions    = info32->supported_extensions;
191                         info28->site_guid               = info32->site_guid;
192                         info28->pid                     = info32->pid;
193                         info28->repl_epoch              = info32->repl_epoch;
194                         break;
195                 }
196                 case 48: {
197                         struct drsuapi_DsBindInfo48 *info48;
198                         info48 = &state->bind_r.out.bind_info->info.info48;
199
200                         info28->supported_extensions    = info48->supported_extensions;
201                         info28->site_guid               = info48->site_guid;
202                         info28->pid                     = info48->pid;
203                         info28->repl_epoch              = info48->repl_epoch;
204                         break;
205                 }
206                 case 52: {
207                         struct drsuapi_DsBindInfo52 *info52;
208                         info52 = &state->bind_r.out.bind_info->info.info52;
209
210                         info28->supported_extensions    = info52->supported_extensions;
211                         info28->site_guid               = info52->site_guid;
212                         info28->pid                     = info52->pid;
213                         info28->repl_epoch              = info52->repl_epoch;
214                         break;
215                 }
216                 default:
217                         DEBUG(1, ("Warning: invalid info length in bind info: %d\n",
218                                 state->bind_r.out.bind_info->length));
219                         break;
220                 }
221         }
222
223         tevent_req_done(req);
224 }
225
226 NTSTATUS dreplsrv_out_drsuapi_recv(struct tevent_req *req)
227 {
228         struct dreplsrv_out_drsuapi_state *state = tevent_req_data(req,
229                                                    struct dreplsrv_out_drsuapi_state);
230         NTSTATUS status;
231
232         if (tevent_req_is_nterror(req, &status)) {
233                 tevent_req_received(req);
234                 return status;
235         }
236
237         state->conn->drsuapi = talloc_move(state->conn, &state->drsuapi);
238
239         tevent_req_received(req);
240         return NT_STATUS_OK;
241 }
242
243 struct dreplsrv_op_pull_source_schema_cycle {
244         struct repsFromTo1 repsFrom1;
245         size_t object_count;
246         struct drsuapi_DsReplicaObjectListItemEx *first_object;
247         struct drsuapi_DsReplicaObjectListItemEx *last_object;
248         uint32_t linked_attributes_count;
249         struct drsuapi_DsReplicaLinkedAttribute *linked_attributes;
250 };
251
252 struct dreplsrv_op_pull_source_state {
253         struct tevent_context *ev;
254         struct dreplsrv_out_operation *op;
255         void *ndr_struct_ptr;
256         /*
257          * Used when we have to re-try with a different NC, eg for
258          * EXOP retry or to get a current schema first
259          */
260         struct dreplsrv_partition_source_dsa *source_dsa_retry;
261         enum drsuapi_DsExtendedOperation extended_op_retry;
262         bool retry_started;
263         struct dreplsrv_op_pull_source_schema_cycle *schema_cycle;
264 };
265
266 static void dreplsrv_op_pull_source_connect_done(struct tevent_req *subreq);
267
268 struct tevent_req *dreplsrv_op_pull_source_send(TALLOC_CTX *mem_ctx,
269                                                 struct tevent_context *ev,
270                                                 struct dreplsrv_out_operation *op)
271 {
272         struct tevent_req *req;
273         struct dreplsrv_op_pull_source_state *state;
274         struct tevent_req *subreq;
275
276         req = tevent_req_create(mem_ctx, &state,
277                                 struct dreplsrv_op_pull_source_state);
278         if (req == NULL) {
279                 return NULL;
280         }
281         state->ev = ev;
282         state->op = op;
283
284         subreq = dreplsrv_out_drsuapi_send(state, ev, op->source_dsa->conn);
285         if (tevent_req_nomem(subreq, req)) {
286                 return tevent_req_post(req, ev);
287         }
288         tevent_req_set_callback(subreq, dreplsrv_op_pull_source_connect_done, req);
289
290         return req;
291 }
292
293 static bool dreplsrv_op_pull_source_detect_schema_cycle(struct tevent_req *req)
294 {
295         struct dreplsrv_op_pull_source_state *state =
296                 tevent_req_data(req,
297                 struct dreplsrv_op_pull_source_state);
298         bool is_schema = false;
299
300         if (state->op->extended_op == DRSUAPI_EXOP_NONE) {
301                 struct dreplsrv_out_operation *op = state->op;
302                 struct dreplsrv_service *service = op->service;
303                 struct ldb_dn *schema_dn = ldb_get_schema_basedn(service->samdb);
304                 struct dreplsrv_partition *partition = op->source_dsa->partition;
305
306                 is_schema = ldb_dn_compare(partition->dn, schema_dn) == 0;
307         }
308
309         if (is_schema) {
310                 struct dreplsrv_op_pull_source_schema_cycle *sc;
311
312                 sc = talloc_zero(state,
313                                  struct dreplsrv_op_pull_source_schema_cycle);
314                 if (tevent_req_nomem(sc, req)) {
315                         return false;
316                 }
317                 sc->repsFrom1 = *state->op->source_dsa->repsFrom1;
318
319                 state->schema_cycle = sc;
320         }
321
322         return true;
323 }
324
325 static void dreplsrv_op_pull_source_get_changes_trigger(struct tevent_req *req);
326
327 static void dreplsrv_op_pull_source_connect_done(struct tevent_req *subreq)
328 {
329         struct tevent_req *req = tevent_req_callback_data(subreq,
330                                  struct tevent_req);
331         NTSTATUS status;
332         bool ok;
333
334         status = dreplsrv_out_drsuapi_recv(subreq);
335         TALLOC_FREE(subreq);
336         if (tevent_req_nterror(req, status)) {
337                 return;
338         }
339
340         ok = dreplsrv_op_pull_source_detect_schema_cycle(req);
341         if (!ok) {
342                 return;
343         }
344
345         dreplsrv_op_pull_source_get_changes_trigger(req);
346 }
347
348 static void dreplsrv_op_pull_source_get_changes_done(struct tevent_req *subreq);
349
350 /*
351   get a RODC partial attribute set for a replication call
352  */
353 static NTSTATUS dreplsrv_get_rodc_partial_attribute_set(struct dreplsrv_service *service,
354                                                         TALLOC_CTX *mem_ctx,
355                                                         struct drsuapi_DsPartialAttributeSet **_pas,
356                                                         struct drsuapi_DsReplicaOIDMapping_Ctr **pfm,
357                                                         bool for_schema)
358 {
359         struct drsuapi_DsPartialAttributeSet *pas;
360         struct dsdb_schema *schema;
361         uint32_t i;
362
363         pas = talloc_zero(mem_ctx, struct drsuapi_DsPartialAttributeSet);
364         NT_STATUS_HAVE_NO_MEMORY(pas);
365
366         schema = dsdb_get_schema(service->samdb, NULL);
367
368         pas->version = 1;
369         pas->attids = talloc_array(pas, enum drsuapi_DsAttributeId, schema->num_attributes);
370         if (pas->attids == NULL) {
371                 TALLOC_FREE(pas);
372                 return NT_STATUS_NO_MEMORY;
373         }
374
375         for (i=0; i<schema->num_attributes; i++) {
376                 struct dsdb_attribute *a;
377                 a = schema->attributes_by_attributeID_id[i];
378                 if (a->systemFlags & (DS_FLAG_ATTR_NOT_REPLICATED | DS_FLAG_ATTR_IS_CONSTRUCTED)) {
379                         continue;
380                 }
381                 if (a->searchFlags & SEARCH_FLAG_RODC_ATTRIBUTE) {
382                         continue;
383                 }
384                 pas->attids[pas->num_attids] = dsdb_attribute_get_attid(a, for_schema);
385                 pas->num_attids++;
386         }
387
388         pas->attids = talloc_realloc(pas, pas->attids, enum drsuapi_DsAttributeId, pas->num_attids);
389         if (pas->attids == NULL) {
390                 TALLOC_FREE(pas);
391                 return NT_STATUS_NO_MEMORY;
392         }
393
394         *_pas = pas;
395
396         if (pfm != NULL) {
397                 dsdb_get_oid_mappings_drsuapi(schema, true, mem_ctx, pfm);
398         }
399
400         return NT_STATUS_OK;
401 }
402
403
404 /*
405   get a GC partial attribute set for a replication call
406  */
407 static NTSTATUS dreplsrv_get_gc_partial_attribute_set(struct dreplsrv_service *service,
408                                                       TALLOC_CTX *mem_ctx,
409                                                       struct drsuapi_DsPartialAttributeSet **_pas,
410                                                       struct drsuapi_DsReplicaOIDMapping_Ctr **pfm)
411 {
412         struct drsuapi_DsPartialAttributeSet *pas;
413         struct dsdb_schema *schema;
414         uint32_t i;
415
416         pas = talloc_zero(mem_ctx, struct drsuapi_DsPartialAttributeSet);
417         NT_STATUS_HAVE_NO_MEMORY(pas);
418
419         schema = dsdb_get_schema(service->samdb, NULL);
420
421         pas->version = 1;
422         pas->attids = talloc_array(pas, enum drsuapi_DsAttributeId, schema->num_attributes);
423         if (pas->attids == NULL) {
424                 TALLOC_FREE(pas);
425                 return NT_STATUS_NO_MEMORY;
426         }
427
428         for (i=0; i<schema->num_attributes; i++) {
429                 struct dsdb_attribute *a;
430                 a = schema->attributes_by_attributeID_id[i];
431                 if (a->isMemberOfPartialAttributeSet) {
432                         pas->attids[pas->num_attids] = dsdb_attribute_get_attid(a, false);
433                         pas->num_attids++;
434                 }
435         }
436
437         pas->attids = talloc_realloc(pas, pas->attids, enum drsuapi_DsAttributeId, pas->num_attids);
438         if (pas->attids == NULL) {
439                 TALLOC_FREE(pas);
440                 return NT_STATUS_NO_MEMORY;
441         }
442
443         *_pas = pas;
444
445         if (pfm != NULL) {
446                 dsdb_get_oid_mappings_drsuapi(schema, true, mem_ctx, pfm);
447         }
448
449         return NT_STATUS_OK;
450 }
451
452 /*
453   convert from one udv format to the other
454  */
455 static WERROR udv_convert(TALLOC_CTX *mem_ctx,
456                           const struct replUpToDateVectorCtr2 *udv,
457                           struct drsuapi_DsReplicaCursorCtrEx *udv_ex)
458 {
459         uint32_t i;
460
461         udv_ex->version = 2;
462         udv_ex->reserved1 = 0;
463         udv_ex->reserved2 = 0;
464         udv_ex->count = udv->count;
465         udv_ex->cursors = talloc_array(mem_ctx, struct drsuapi_DsReplicaCursor, udv->count);
466         W_ERROR_HAVE_NO_MEMORY(udv_ex->cursors);
467
468         for (i=0; i<udv->count; i++) {
469                 udv_ex->cursors[i].source_dsa_invocation_id = udv->cursors[i].source_dsa_invocation_id;
470                 udv_ex->cursors[i].highest_usn = udv->cursors[i].highest_usn;
471         }
472
473         return WERR_OK;
474 }
475
476
477 static void dreplsrv_op_pull_source_get_changes_trigger(struct tevent_req *req)
478 {
479         struct dreplsrv_op_pull_source_state *state = tevent_req_data(req,
480                                                       struct dreplsrv_op_pull_source_state);
481         const struct repsFromTo1 *rf1 = state->op->source_dsa->repsFrom1;
482         struct dreplsrv_service *service = state->op->service;
483         struct dreplsrv_partition *partition = state->op->source_dsa->partition;
484         struct dreplsrv_drsuapi_connection *drsuapi = state->op->source_dsa->conn->drsuapi;
485         struct drsuapi_DsGetNCChanges *r;
486         struct drsuapi_DsReplicaCursorCtrEx *uptodateness_vector;
487         struct tevent_req *subreq;
488         struct drsuapi_DsPartialAttributeSet *pas = NULL;
489         NTSTATUS status;
490         uint32_t replica_flags;
491         struct drsuapi_DsReplicaHighWaterMark highwatermark;
492         struct drsuapi_DsReplicaOIDMapping_Ctr *mappings = NULL;
493         bool is_schema = false;
494
495         if (state->schema_cycle != NULL) {
496                 is_schema = true;
497                 rf1 = &state->schema_cycle->repsFrom1;
498         }
499
500         r = talloc(state, struct drsuapi_DsGetNCChanges);
501         if (tevent_req_nomem(r, req)) {
502                 return;
503         }
504
505         r->out.level_out = talloc(r, uint32_t);
506         if (tevent_req_nomem(r->out.level_out, req)) {
507                 return;
508         }
509         r->in.req = talloc(r, union drsuapi_DsGetNCChangesRequest);
510         if (tevent_req_nomem(r->in.req, req)) {
511                 return;
512         }
513         r->out.ctr = talloc(r, union drsuapi_DsGetNCChangesCtr);
514         if (tevent_req_nomem(r->out.ctr, req)) {
515                 return;
516         }
517
518         if (partition->uptodatevector.count != 0 &&
519             partition->uptodatevector_ex.count == 0) {
520                 WERROR werr;
521                 werr = udv_convert(partition, &partition->uptodatevector, &partition->uptodatevector_ex);
522                 if (!W_ERROR_IS_OK(werr)) {
523                         DEBUG(0,(__location__ ": Failed to convert UDV for %s : %s\n",
524                                  ldb_dn_get_linearized(partition->dn), win_errstr(werr)));
525                         tevent_req_nterror(req, werror_to_ntstatus(werr));
526                         return;
527                 }
528         }
529
530         if (partition->uptodatevector_ex.count == 0) {
531                 uptodateness_vector = NULL;
532         } else {
533                 uptodateness_vector = &partition->uptodatevector_ex;
534         }
535
536         replica_flags = rf1->replica_flags;
537         highwatermark = rf1->highwatermark;
538
539         if (state->op->options & DRSUAPI_DRS_GET_ANC) {
540                 replica_flags |= DRSUAPI_DRS_GET_ANC;
541         }
542
543         if (state->op->options & DRSUAPI_DRS_SYNC_FORCED) {
544                 replica_flags |= DRSUAPI_DRS_SYNC_FORCED;
545         }
546
547         if (partition->partial_replica) {
548                 status = dreplsrv_get_gc_partial_attribute_set(service, r,
549                                                                &pas,
550                                                                &mappings);
551                 if (!NT_STATUS_IS_OK(status)) {
552                         DEBUG(0,(__location__ ": Failed to construct GC partial attribute set : %s\n", nt_errstr(status)));
553                         tevent_req_nterror(req, status);
554                         return;
555                 }
556                 replica_flags &= ~DRSUAPI_DRS_WRIT_REP;
557         } else if (partition->rodc_replica || state->op->extended_op == DRSUAPI_EXOP_REPL_SECRET) {
558                 status = dreplsrv_get_rodc_partial_attribute_set(service, r,
559                                                                  &pas,
560                                                                  &mappings,
561                                                                  is_schema);
562                 if (!NT_STATUS_IS_OK(status)) {
563                         DEBUG(0,(__location__ ": Failed to construct RODC partial attribute set : %s\n", nt_errstr(status)));
564                         tevent_req_nterror(req, status);
565                         return;
566                 }
567                 replica_flags &= ~DRSUAPI_DRS_WRIT_REP;
568                 if (state->op->extended_op == DRSUAPI_EXOP_REPL_SECRET) {
569                         replica_flags &= ~DRSUAPI_DRS_SPECIAL_SECRET_PROCESSING;
570                 } else {
571                         replica_flags |= DRSUAPI_DRS_SPECIAL_SECRET_PROCESSING;
572                 }
573
574                 /*
575                  * As per MS-DRSR:
576                  *
577                  * 4.1.10.4
578                  * Client Behavior When Sending the IDL_DRSGetNCChanges Request
579                  *
580                  * 4.1.10.4.1
581                  * ReplicateNCRequestMsg
582                  */
583                 replica_flags |= DRSUAPI_DRS_GET_ALL_GROUP_MEMBERSHIP;
584         } else {
585                 replica_flags |= DRSUAPI_DRS_GET_ALL_GROUP_MEMBERSHIP;
586         }
587
588         if (state->op->extended_op != DRSUAPI_EXOP_NONE) {
589                 /*
590                  * If it's an exop never set the ADD_REF even if it's in
591                  * repsFrom flags.
592                  */
593                 replica_flags &= ~DRSUAPI_DRS_ADD_REF;
594         }
595
596         /* is this a full resync of all objects? */
597         if (state->op->options & DRSUAPI_DRS_FULL_SYNC_NOW) {
598                 ZERO_STRUCT(highwatermark);
599                 /* clear the FULL_SYNC_NOW option for subsequent
600                    stages of the replication cycle */
601                 state->op->options &= ~DRSUAPI_DRS_FULL_SYNC_NOW;
602                 state->op->options |= DRSUAPI_DRS_FULL_SYNC_IN_PROGRESS;
603                 replica_flags |= DRSUAPI_DRS_NEVER_SYNCED;
604         }
605         if (state->op->options & DRSUAPI_DRS_FULL_SYNC_IN_PROGRESS) {
606                 uptodateness_vector = NULL;
607         }
608
609         r->in.bind_handle       = &drsuapi->bind_handle;
610
611         if (drsuapi->remote_info28.supported_extensions & DRSUAPI_SUPPORTED_EXTENSION_GETCHGREQ_V10) {
612                 r->in.level                             = 10;
613                 r->in.req->req10.destination_dsa_guid   = service->ntds_guid;
614                 r->in.req->req10.source_dsa_invocation_id= rf1->source_dsa_invocation_id;
615                 r->in.req->req10.naming_context         = &partition->nc;
616                 r->in.req->req10.highwatermark          = highwatermark;
617                 r->in.req->req10.uptodateness_vector    = uptodateness_vector;
618                 r->in.req->req10.replica_flags          = replica_flags;
619                 r->in.req->req10.max_object_count       = 133;
620                 r->in.req->req10.max_ndr_size           = 1336811;
621                 r->in.req->req10.extended_op            = state->op->extended_op;
622                 r->in.req->req10.fsmo_info              = state->op->fsmo_info;
623                 r->in.req->req10.partial_attribute_set  = pas;
624                 r->in.req->req10.partial_attribute_set_ex= NULL;
625                 r->in.req->req10.mapping_ctr.num_mappings= mappings == NULL ? 0 : mappings->num_mappings;
626                 r->in.req->req10.mapping_ctr.mappings   = mappings == NULL ? NULL : mappings->mappings;
627
628                 /* the only difference to v8 is the more_flags */
629                 r->in.req->req10.more_flags = state->op->more_flags;
630
631         } else if (drsuapi->remote_info28.supported_extensions & DRSUAPI_SUPPORTED_EXTENSION_GETCHGREQ_V8) {
632                 r->in.level                             = 8;
633                 r->in.req->req8.destination_dsa_guid    = service->ntds_guid;
634                 r->in.req->req8.source_dsa_invocation_id= rf1->source_dsa_invocation_id;
635                 r->in.req->req8.naming_context          = &partition->nc;
636                 r->in.req->req8.highwatermark           = highwatermark;
637                 r->in.req->req8.uptodateness_vector     = uptodateness_vector;
638                 r->in.req->req8.replica_flags           = replica_flags;
639                 r->in.req->req8.max_object_count        = 133;
640                 r->in.req->req8.max_ndr_size            = 1336811;
641                 r->in.req->req8.extended_op             = state->op->extended_op;
642                 r->in.req->req8.fsmo_info               = state->op->fsmo_info;
643                 r->in.req->req8.partial_attribute_set   = pas;
644                 r->in.req->req8.partial_attribute_set_ex= NULL;
645                 r->in.req->req8.mapping_ctr.num_mappings= mappings == NULL ? 0 : mappings->num_mappings;
646                 r->in.req->req8.mapping_ctr.mappings    = mappings == NULL ? NULL : mappings->mappings;
647         } else {
648                 r->in.level                             = 5;
649                 r->in.req->req5.destination_dsa_guid    = service->ntds_guid;
650                 r->in.req->req5.source_dsa_invocation_id= rf1->source_dsa_invocation_id;
651                 r->in.req->req5.naming_context          = &partition->nc;
652                 r->in.req->req5.highwatermark           = highwatermark;
653                 r->in.req->req5.uptodateness_vector     = uptodateness_vector;
654                 r->in.req->req5.replica_flags           = replica_flags;
655                 r->in.req->req5.max_object_count        = 133;
656                 r->in.req->req5.max_ndr_size            = 1336770;
657                 r->in.req->req5.extended_op             = state->op->extended_op;
658                 r->in.req->req5.fsmo_info               = state->op->fsmo_info;
659         }
660
661 #if 0
662         NDR_PRINT_IN_DEBUG(drsuapi_DsGetNCChanges, r);
663 #endif
664
665         state->ndr_struct_ptr = r;
666         subreq = dcerpc_drsuapi_DsGetNCChanges_r_send(state,
667                                                       state->ev,
668                                                       drsuapi->drsuapi_handle,
669                                                       r);
670         if (tevent_req_nomem(subreq, req)) {
671                 return;
672         }
673         tevent_req_set_callback(subreq, dreplsrv_op_pull_source_get_changes_done, req);
674 }
675
676 static void dreplsrv_op_pull_source_apply_changes_trigger(struct tevent_req *req,
677                                                           struct drsuapi_DsGetNCChanges *r,
678                                                           uint32_t ctr_level,
679                                                           struct drsuapi_DsGetNCChangesCtr1 *ctr1,
680                                                           struct drsuapi_DsGetNCChangesCtr6 *ctr6);
681
682 static void dreplsrv_op_pull_source_get_changes_done(struct tevent_req *subreq)
683 {
684         struct tevent_req *req = tevent_req_callback_data(subreq,
685                                  struct tevent_req);
686         struct dreplsrv_op_pull_source_state *state = tevent_req_data(req,
687                                                       struct dreplsrv_op_pull_source_state);
688         NTSTATUS status;
689         struct drsuapi_DsGetNCChanges *r = talloc_get_type(state->ndr_struct_ptr,
690                                            struct drsuapi_DsGetNCChanges);
691         uint32_t ctr_level = 0;
692         struct drsuapi_DsGetNCChangesCtr1 *ctr1 = NULL;
693         struct drsuapi_DsGetNCChangesCtr6 *ctr6 = NULL;
694         enum drsuapi_DsExtendedError extended_ret = DRSUAPI_EXOP_ERR_NONE;
695         state->ndr_struct_ptr = NULL;
696
697         status = dcerpc_drsuapi_DsGetNCChanges_r_recv(subreq, r);
698         TALLOC_FREE(subreq);
699         if (tevent_req_nterror(req, status)) {
700                 return;
701         }
702
703         if (!W_ERROR_IS_OK(r->out.result)) {
704                 status = werror_to_ntstatus(r->out.result);
705                 tevent_req_nterror(req, status);
706                 return;
707         }
708
709         if (*r->out.level_out == 1) {
710                 ctr_level = 1;
711                 ctr1 = &r->out.ctr->ctr1;
712         } else if (*r->out.level_out == 2 &&
713                    r->out.ctr->ctr2.mszip1.ts) {
714                 ctr_level = 1;
715                 ctr1 = &r->out.ctr->ctr2.mszip1.ts->ctr1;
716         } else if (*r->out.level_out == 6) {
717                 ctr_level = 6;
718                 ctr6 = &r->out.ctr->ctr6;
719         } else if (*r->out.level_out == 7 &&
720                    r->out.ctr->ctr7.level == 6 &&
721                    r->out.ctr->ctr7.type == DRSUAPI_COMPRESSION_TYPE_MSZIP &&
722                    r->out.ctr->ctr7.ctr.mszip6.ts) {
723                 ctr_level = 6;
724                 ctr6 = &r->out.ctr->ctr7.ctr.mszip6.ts->ctr6;
725         } else if (*r->out.level_out == 7 &&
726                    r->out.ctr->ctr7.level == 6 &&
727                    r->out.ctr->ctr7.type == DRSUAPI_COMPRESSION_TYPE_WIN2K3_LZ77_DIRECT2 &&
728                    r->out.ctr->ctr7.ctr.xpress6.ts) {
729                 ctr_level = 6;
730                 ctr6 = &r->out.ctr->ctr7.ctr.xpress6.ts->ctr6;
731         } else {
732                 status = werror_to_ntstatus(WERR_BAD_NET_RESP);
733                 tevent_req_nterror(req, status);
734                 return;
735         }
736
737         if (!ctr1 && !ctr6) {
738                 status = werror_to_ntstatus(WERR_BAD_NET_RESP);
739                 tevent_req_nterror(req, status);
740                 return;
741         }
742
743         if (ctr_level == 6) {
744                 if (!W_ERROR_IS_OK(ctr6->drs_error)) {
745                         status = werror_to_ntstatus(ctr6->drs_error);
746                         tevent_req_nterror(req, status);
747                         return;
748                 }
749                 extended_ret = ctr6->extended_ret;
750         }
751
752         if (ctr_level == 1) {
753                 extended_ret = ctr1->extended_ret;
754         }
755
756         if (state->op->extended_op != DRSUAPI_EXOP_NONE) {
757                 state->op->extended_ret = extended_ret;
758
759                 if (extended_ret != DRSUAPI_EXOP_ERR_SUCCESS) {
760                         status = NT_STATUS_UNSUCCESSFUL;
761                         tevent_req_nterror(req, status);
762                         return;
763                 }
764         }
765
766         dreplsrv_op_pull_source_apply_changes_trigger(req, r, ctr_level, ctr1, ctr6);
767 }
768
769 /**
770  * If processing a chunk of replication data fails, check if it is due to a
771  * problem that can be fixed by setting extra flags in the GetNCChanges request,
772  * i.e. GET_ANC or GET_TGT.
773  * @returns NT_STATUS_OK if the request was retried, and an error code if not
774  */
775 static NTSTATUS dreplsrv_op_pull_retry_with_flags(struct tevent_req *req,
776                                                   WERROR error_code)
777 {
778         struct dreplsrv_op_pull_source_state *state;
779         NTSTATUS nt_status = NT_STATUS_OK;
780
781         state = tevent_req_data(req, struct dreplsrv_op_pull_source_state);
782
783         /*
784          * Check if we failed to apply the records due to a missing parent or
785          * target object. If so, try again and ask for any mising parent/target
786          * objects to be included this time.
787          */
788         if (W_ERROR_EQUAL(error_code, WERR_DS_DRA_RECYCLED_TARGET)) {
789
790                 if (state->op->more_flags & DRSUAPI_DRS_GET_TGT) {
791                         DEBUG(1,("Missing target object despite setting DRSUAPI_DRS_GET_TGT flag\n"));
792                         nt_status = NT_STATUS_INVALID_NETWORK_RESPONSE;
793                 } else {
794                         state->op->more_flags |= DRSUAPI_DRS_GET_TGT;
795                         DEBUG(1,("Missing target object when we didn't set the DRSUAPI_DRS_GET_TGT flag, retrying\n"));
796                         dreplsrv_op_pull_source_get_changes_trigger(req);
797                 }
798         } else if (W_ERROR_EQUAL(error_code, WERR_DS_DRA_MISSING_PARENT)) {
799
800                 if (state->op->options & DRSUAPI_DRS_GET_ANC) {
801                         DEBUG(1,("Missing parent object despite setting DRSUAPI_DRS_GET_ANC flag\n"));
802                         nt_status = NT_STATUS_INVALID_NETWORK_RESPONSE;
803                 } else {
804                         state->op->options |= DRSUAPI_DRS_GET_ANC;
805                         DEBUG(4,("Missing parent object when we didn't set the DRSUAPI_DRS_GET_ANC flag, retrying\n"));
806                         dreplsrv_op_pull_source_get_changes_trigger(req);
807                 }
808         } else {
809                 nt_status = werror_to_ntstatus(WERR_BAD_NET_RESP);
810         }
811
812         return nt_status;
813 }
814
815
816 static void dreplsrv_update_refs_trigger(struct tevent_req *req);
817
818 static void dreplsrv_op_pull_source_apply_changes_trigger(struct tevent_req *req,
819                                                           struct drsuapi_DsGetNCChanges *r,
820                                                           uint32_t ctr_level,
821                                                           struct drsuapi_DsGetNCChangesCtr1 *ctr1,
822                                                            struct drsuapi_DsGetNCChangesCtr6 *ctr6)
823 {
824         struct dreplsrv_op_pull_source_state *state = tevent_req_data(req,
825                                                       struct dreplsrv_op_pull_source_state);
826         struct repsFromTo1 rf1 = *state->op->source_dsa->repsFrom1;
827         struct dreplsrv_service *service = state->op->service;
828         struct dreplsrv_partition *partition = state->op->source_dsa->partition;
829         struct dreplsrv_drsuapi_connection *drsuapi = state->op->source_dsa->conn->drsuapi;
830         struct ldb_dn *schema_dn = ldb_get_schema_basedn(service->samdb);
831         struct dreplsrv_op_pull_source_schema_cycle *sc = NULL;
832         struct dsdb_schema *schema;
833         struct dsdb_schema *working_schema = NULL;
834         const struct drsuapi_DsReplicaOIDMapping_Ctr *mapping_ctr;
835         uint32_t object_count;
836         struct drsuapi_DsReplicaObjectListItemEx *first_object;
837         uint32_t linked_attributes_count;
838         struct drsuapi_DsReplicaLinkedAttribute *linked_attributes;
839         const struct drsuapi_DsReplicaCursor2CtrEx *uptodateness_vector;
840         struct dsdb_extended_replicated_objects *objects;
841         bool more_data = false;
842         WERROR status;
843         NTSTATUS nt_status;
844         uint32_t dsdb_repl_flags = 0;
845         struct ldb_dn *nc_root = NULL;
846         bool was_schema = false;
847         int ret;
848
849         switch (ctr_level) {
850         case 1:
851                 mapping_ctr                     = &ctr1->mapping_ctr;
852                 object_count                    = ctr1->object_count;
853                 first_object                    = ctr1->first_object;
854                 linked_attributes_count         = 0;
855                 linked_attributes               = NULL;
856                 rf1.source_dsa_obj_guid         = ctr1->source_dsa_guid;
857                 rf1.source_dsa_invocation_id    = ctr1->source_dsa_invocation_id;
858                 rf1.highwatermark               = ctr1->new_highwatermark;
859                 uptodateness_vector             = NULL; /* TODO: map it */
860                 more_data                       = ctr1->more_data;
861                 break;
862         case 6:
863                 mapping_ctr                     = &ctr6->mapping_ctr;
864                 object_count                    = ctr6->object_count;
865                 first_object                    = ctr6->first_object;
866                 linked_attributes_count         = ctr6->linked_attributes_count;
867                 linked_attributes               = ctr6->linked_attributes;
868                 rf1.source_dsa_obj_guid         = ctr6->source_dsa_guid;
869                 rf1.source_dsa_invocation_id    = ctr6->source_dsa_invocation_id;
870                 rf1.highwatermark               = ctr6->new_highwatermark;
871                 uptodateness_vector             = ctr6->uptodateness_vector;
872                 more_data                       = ctr6->more_data;
873                 break;
874         default:
875                 nt_status = werror_to_ntstatus(WERR_BAD_NET_RESP);
876                 tevent_req_nterror(req, nt_status);
877                 return;
878         }
879
880         /*
881          * We need to cache the schema changes until we replicated
882          * everything before we can apply the new schema.
883          */
884         if (state->schema_cycle != NULL) {
885                 TALLOC_CTX *mem = NULL;
886                 struct drsuapi_DsReplicaObjectListItemEx **ptr = NULL;
887                 struct drsuapi_DsReplicaObjectListItemEx *l = NULL;
888
889                 was_schema = true;
890                 sc = state->schema_cycle;
891
892                 sc->repsFrom1 = rf1;
893
894                 if (sc->first_object == NULL) {
895                         mem = sc;
896                         ptr = &sc->first_object;
897                 } else {
898                         mem = sc->last_object;
899                         ptr = &sc->last_object->next_object;
900                 }
901                 *ptr = talloc_move(mem, &first_object);
902                 for (l = *ptr; l != NULL; l = l->next_object) {
903                         sc->object_count++;
904                         if (l->next_object == NULL) {
905                                 sc->last_object = l;
906                                 break;
907                         }
908                 }
909
910                 if (sc->linked_attributes_count == 0) {
911                         sc->linked_attributes = talloc_move(sc, &linked_attributes);
912                         sc->linked_attributes_count = linked_attributes_count;
913                         linked_attributes_count = 0;
914                 } else if (linked_attributes_count > 0) {
915                         struct drsuapi_DsReplicaLinkedAttribute *new_las = NULL;
916                         struct drsuapi_DsReplicaLinkedAttribute *tmp_las = NULL;
917                         uint64_t new_count;
918                         uint64_t add_size;
919                         uint32_t add_idx;
920
921                         new_count = sc->linked_attributes_count;
922                         new_count += linked_attributes_count;
923                         if (new_count > UINT32_MAX) {
924                                 nt_status = werror_to_ntstatus(WERR_BAD_NET_RESP);
925                                 tevent_req_nterror(req, nt_status);
926                                 return;
927                         }
928                         add_size = linked_attributes_count;
929                         add_size *= sizeof(linked_attributes[0]);
930                         if (add_size > SIZE_MAX) {
931                                 nt_status = werror_to_ntstatus(WERR_BAD_NET_RESP);
932                                 tevent_req_nterror(req, nt_status);
933                                 return;
934                         }
935                         add_idx = sc->linked_attributes_count;
936
937                         tmp_las = talloc_realloc(sc,
938                                                  sc->linked_attributes,
939                                                  struct drsuapi_DsReplicaLinkedAttribute,
940                                                  new_count);
941                         if (tevent_req_nomem(tmp_las, req)) {
942                                 return;
943                         }
944                         new_las = talloc_move(tmp_las, &linked_attributes);
945                         memcpy(&tmp_las[add_idx], new_las, add_size);
946                         sc->linked_attributes = tmp_las;
947                         sc->linked_attributes_count = new_count;
948                         linked_attributes_count = 0;
949                 }
950
951                 if (more_data) {
952                         /* we don't need this structure anymore */
953                         TALLOC_FREE(r);
954
955                         dreplsrv_op_pull_source_get_changes_trigger(req);
956                         return;
957                 }
958
959                 /* detach sc from state */
960                 state->schema_cycle = NULL;
961         }
962
963         schema = dsdb_get_schema(service->samdb, state);
964         if (!schema) {
965                 DEBUG(0,(__location__ ": Schema is not loaded yet!\n"));
966                 tevent_req_nterror(req, NT_STATUS_INTERNAL_ERROR);
967                 return;
968         }
969
970         /*
971          * Decide what working schema to use for object conversion.
972          * We won't need a working schema for empty replicas sent.
973          */
974         if (sc != NULL) {
975                 first_object = talloc_move(r, &sc->first_object);
976                 object_count = sc->object_count;
977                 linked_attributes = talloc_move(r, &sc->linked_attributes);
978                 linked_attributes_count = sc->linked_attributes_count;
979                 TALLOC_FREE(sc);
980
981                 if (first_object != NULL) {
982                         /* create working schema to convert objects with */
983                         status = dsdb_repl_make_working_schema(service->samdb,
984                                                                schema,
985                                                                mapping_ctr,
986                                                                object_count,
987                                                                first_object,
988                                                                &drsuapi->gensec_skey,
989                                                                state, &working_schema);
990                         if (!W_ERROR_IS_OK(status)) {
991                                 DEBUG(0,("Failed to create working schema: %s\n",
992                                          win_errstr(status)));
993                                 tevent_req_nterror(req, NT_STATUS_INTERNAL_ERROR);
994                                 return;
995                         }
996                 }
997         }
998
999         if (partition->partial_replica || partition->rodc_replica) {
1000                 dsdb_repl_flags |= DSDB_REPL_FLAG_PARTIAL_REPLICA;
1001         }
1002         if (state->op->options & DRSUAPI_DRS_FULL_SYNC_IN_PROGRESS) {
1003                 dsdb_repl_flags |= DSDB_REPL_FLAG_PRIORITISE_INCOMING;
1004         }
1005         if (state->op->options & DRSUAPI_DRS_SPECIAL_SECRET_PROCESSING) {
1006                 dsdb_repl_flags |= DSDB_REPL_FLAG_EXPECT_NO_SECRETS;
1007         }
1008         if (state->op->options & DRSUAPI_DRS_CRITICAL_ONLY ||
1009             state->op->extended_op != DRSUAPI_EXOP_NONE) {
1010                 dsdb_repl_flags |= DSDB_REPL_FLAG_OBJECT_SUBSET;
1011         }
1012
1013         if (state->op->more_flags & DRSUAPI_DRS_GET_TGT) {
1014                 dsdb_repl_flags |= DSDB_REPL_FLAG_TARGETS_UPTODATE;
1015         }
1016
1017         if (state->op->extended_op != DRSUAPI_EXOP_NONE) {
1018                 ret = dsdb_find_nc_root(service->samdb, partition,
1019                                         partition->dn, &nc_root);
1020                 if (ret != LDB_SUCCESS) {
1021                         DEBUG(0,(__location__ ": Failed to find nc_root for %s\n",
1022                                  ldb_dn_get_linearized(partition->dn)));
1023                         tevent_req_nterror(req, NT_STATUS_INTERNAL_ERROR);
1024                         return;
1025                 }
1026         } else {
1027                 nc_root = partition->dn;
1028         }
1029
1030         status = dsdb_replicated_objects_convert(service->samdb,
1031                                                  working_schema ? working_schema : schema,
1032                                                  nc_root,
1033                                                  mapping_ctr,
1034                                                  object_count,
1035                                                  first_object,
1036                                                  linked_attributes_count,
1037                                                  linked_attributes,
1038                                                  &rf1,
1039                                                  uptodateness_vector,
1040                                                  &drsuapi->gensec_skey,
1041                                                  dsdb_repl_flags,
1042                                                  state, &objects);
1043
1044         if (W_ERROR_EQUAL(status, WERR_DS_DRA_SCHEMA_MISMATCH)) {
1045                 struct dreplsrv_partition *p;
1046                 bool ok;
1047
1048                 if (was_schema) {
1049                         nt_status = werror_to_ntstatus(WERR_BAD_NET_RESP);
1050                         DBG_ERR("Got mismatch for schema partition: %s/%s\n",
1051                                   win_errstr(status), nt_errstr(nt_status));
1052                         tevent_req_nterror(req, nt_status);
1053                         return;
1054                 }
1055
1056                 if (state->retry_started) {
1057                         nt_status = werror_to_ntstatus(WERR_BAD_NET_RESP);
1058                         DEBUG(0,("Failed to convert objects after retry: %s/%s\n",
1059                                   win_errstr(status), nt_errstr(nt_status)));
1060                         tevent_req_nterror(req, nt_status);
1061                         return;
1062                 }
1063
1064                 /*
1065                  * Change info sync or extended operation into a fetch
1066                  * of the schema partition, so we get all the schema
1067                  * objects we need.
1068                  *
1069                  * We don't want to re-do the remote exop,
1070                  * unless it was REPL_SECRET so we set the
1071                  * fallback operation to just be a fetch of
1072                  * the relevent partition.
1073                  */
1074
1075
1076                 if (state->op->extended_op == DRSUAPI_EXOP_REPL_SECRET) {
1077                         state->extended_op_retry = state->op->extended_op;
1078                 } else {
1079                         state->extended_op_retry = DRSUAPI_EXOP_NONE;
1080                 }
1081                 state->op->extended_op = DRSUAPI_EXOP_NONE;
1082
1083                 if (ldb_dn_compare(nc_root, partition->dn) == 0) {
1084                         state->source_dsa_retry = state->op->source_dsa;
1085                 } else {
1086                         status = dreplsrv_partition_find_for_nc(service,
1087                                                                 NULL, NULL,
1088                                                                 ldb_dn_get_linearized(nc_root),
1089                                                                 &p);
1090                         if (!W_ERROR_IS_OK(status)) {
1091                                 DEBUG(2, ("Failed to find requested Naming Context for %s: %s",
1092                                           ldb_dn_get_linearized(nc_root),
1093                                           win_errstr(status)));
1094                                 nt_status = werror_to_ntstatus(status);
1095                                 tevent_req_nterror(req, nt_status);
1096                                 return;
1097                         }
1098                         status = dreplsrv_partition_source_dsa_by_guid(p,
1099                                                                        &state->op->source_dsa->repsFrom1->source_dsa_obj_guid,
1100                                                                        &state->source_dsa_retry);
1101
1102                         if (!W_ERROR_IS_OK(status)) {
1103                                 struct GUID_txt_buf str;
1104                                 DEBUG(2, ("Failed to find requested source DSA for %s and %s: %s",
1105                                           ldb_dn_get_linearized(nc_root),
1106                                           GUID_buf_string(&state->op->source_dsa->repsFrom1->source_dsa_obj_guid, &str),
1107                                           win_errstr(status)));
1108                                 nt_status = werror_to_ntstatus(status);
1109                                 tevent_req_nterror(req, nt_status);
1110                                 return;
1111                         }
1112                 }
1113
1114                 /* Find schema naming context to be synchronized first */
1115                 status = dreplsrv_partition_find_for_nc(service,
1116                                                         NULL, NULL,
1117                                                         ldb_dn_get_linearized(schema_dn),
1118                                                         &p);
1119                 if (!W_ERROR_IS_OK(status)) {
1120                         DEBUG(2, ("Failed to find requested Naming Context for schema: %s",
1121                                   win_errstr(status)));
1122                         nt_status = werror_to_ntstatus(status);
1123                         tevent_req_nterror(req, nt_status);
1124                         return;
1125                 }
1126
1127                 status = dreplsrv_partition_source_dsa_by_guid(p,
1128                                                                &state->op->source_dsa->repsFrom1->source_dsa_obj_guid,
1129                                                                &state->op->source_dsa);
1130                 if (!W_ERROR_IS_OK(status)) {
1131                         struct GUID_txt_buf str;
1132                         DEBUG(2, ("Failed to find requested source DSA for %s and %s: %s",
1133                                   ldb_dn_get_linearized(schema_dn),
1134                                   GUID_buf_string(&state->op->source_dsa->repsFrom1->source_dsa_obj_guid, &str),
1135                                   win_errstr(status)));
1136                         nt_status = werror_to_ntstatus(status);
1137                         tevent_req_nterror(req, nt_status);
1138                         return;
1139                 }
1140                 DEBUG(4,("Wrong schema when applying reply GetNCChanges, retrying\n"));
1141
1142                 state->retry_started = true;
1143
1144                 ok = dreplsrv_op_pull_source_detect_schema_cycle(req);
1145                 if (!ok) {
1146                         return;
1147                 }
1148
1149                 dreplsrv_op_pull_source_get_changes_trigger(req);
1150                 return;
1151
1152         } else if (!W_ERROR_IS_OK(status)) {
1153                 nt_status = werror_to_ntstatus(WERR_BAD_NET_RESP);
1154                 DEBUG(0,("Failed to convert objects: %s/%s\n",
1155                           win_errstr(status), nt_errstr(nt_status)));
1156                 tevent_req_nterror(req, nt_status);
1157                 return;
1158         }
1159
1160         status = dsdb_replicated_objects_commit(service->samdb,
1161                                                 working_schema,
1162                                                 objects,
1163                                                 &state->op->source_dsa->notify_uSN);
1164         talloc_free(objects);
1165
1166         if (!W_ERROR_IS_OK(status)) {
1167
1168                 /*
1169                  * Check if this error can be fixed by resending the GetNCChanges
1170                  * request with extra flags set (i.e. GET_ANC/GET_TGT)
1171                  */
1172                 nt_status = dreplsrv_op_pull_retry_with_flags(req, status);
1173
1174                 if (NT_STATUS_IS_OK(nt_status)) {
1175
1176                         /*
1177                          * We resent the request. Don't update the highwatermark,
1178                          * we'll start this part of the cycle again.
1179                          */
1180                         return;
1181                 }
1182
1183                 DEBUG(0,("Failed to commit objects: %s/%s\n",
1184                           win_errstr(status), nt_errstr(nt_status)));
1185                 tevent_req_nterror(req, nt_status);
1186                 return;
1187         }
1188
1189         if (state->op->extended_op == DRSUAPI_EXOP_NONE) {
1190                 /* if it applied fine, we need to update the highwatermark */
1191                 *state->op->source_dsa->repsFrom1 = rf1;
1192         }
1193
1194         /* we don't need this maybe very large structure anymore */
1195         TALLOC_FREE(r);
1196
1197         if (more_data) {
1198                 dreplsrv_op_pull_source_get_changes_trigger(req);
1199                 return;
1200         }
1201
1202         /*
1203          * If we had to divert via doing some other thing, such as
1204          * pulling the schema, then go back and do the original
1205          * operation once we are done.
1206          */
1207         if (state->source_dsa_retry != NULL) {
1208                 state->op->source_dsa = state->source_dsa_retry;
1209                 state->op->extended_op = state->extended_op_retry;
1210                 state->source_dsa_retry = NULL;
1211                 dreplsrv_op_pull_source_get_changes_trigger(req);
1212                 return;
1213         }
1214
1215         if (state->op->extended_op != DRSUAPI_EXOP_NONE ||
1216             state->op->service->am_rodc) {
1217                 /*
1218                   we don't do the UpdateRefs for extended ops or if we
1219                   are a RODC
1220                  */
1221                 tevent_req_done(req);
1222                 return;
1223         }
1224
1225         /* now we need to update the repsTo record for this partition
1226            on the server. These records are initially established when
1227            we join the domain, but they quickly expire.  We do it here
1228            so we can use the already established DRSUAPI pipe
1229         */
1230         dreplsrv_update_refs_trigger(req);
1231 }
1232
1233 static void dreplsrv_update_refs_done(struct tevent_req *subreq);
1234
1235 /*
1236   send a UpdateRefs request to refresh our repsTo record on the server
1237  */
1238 static void dreplsrv_update_refs_trigger(struct tevent_req *req)
1239 {
1240         struct dreplsrv_op_pull_source_state *state = tevent_req_data(req,
1241                                                       struct dreplsrv_op_pull_source_state);
1242         struct dreplsrv_service *service = state->op->service;
1243         struct dreplsrv_partition *partition = state->op->source_dsa->partition;
1244         struct dreplsrv_drsuapi_connection *drsuapi = state->op->source_dsa->conn->drsuapi;
1245         struct drsuapi_DsReplicaUpdateRefs *r;
1246         char *ntds_dns_name;
1247         struct tevent_req *subreq;
1248
1249         r = talloc(state, struct drsuapi_DsReplicaUpdateRefs);
1250         if (tevent_req_nomem(r, req)) {
1251                 return;
1252         }
1253
1254         ntds_dns_name = samdb_ntds_msdcs_dns_name(service->samdb, r, &service->ntds_guid);
1255         if (tevent_req_nomem(ntds_dns_name, req)) {
1256                 talloc_free(r);
1257                 return;
1258         }
1259
1260         r->in.bind_handle       = &drsuapi->bind_handle;
1261         r->in.level             = 1;
1262         r->in.req.req1.naming_context     = &partition->nc;
1263         r->in.req.req1.dest_dsa_dns_name  = ntds_dns_name;
1264         r->in.req.req1.dest_dsa_guid      = service->ntds_guid;
1265         r->in.req.req1.options            = DRSUAPI_DRS_ADD_REF | DRSUAPI_DRS_DEL_REF;
1266         if (!service->am_rodc) {
1267                 r->in.req.req1.options |= DRSUAPI_DRS_WRIT_REP;
1268         }
1269
1270         state->ndr_struct_ptr = r;
1271         subreq = dcerpc_drsuapi_DsReplicaUpdateRefs_r_send(state,
1272                                                            state->ev,
1273                                                            drsuapi->drsuapi_handle,
1274                                                            r);
1275         if (tevent_req_nomem(subreq, req)) {
1276                 talloc_free(r);
1277                 return;
1278         }
1279         tevent_req_set_callback(subreq, dreplsrv_update_refs_done, req);
1280 }
1281
1282 /*
1283   receive a UpdateRefs reply
1284  */
1285 static void dreplsrv_update_refs_done(struct tevent_req *subreq)
1286 {
1287         struct tevent_req *req = tevent_req_callback_data(subreq,
1288                                  struct tevent_req);
1289         struct dreplsrv_op_pull_source_state *state = tevent_req_data(req,
1290                                                       struct dreplsrv_op_pull_source_state);
1291         struct drsuapi_DsReplicaUpdateRefs *r = talloc_get_type(state->ndr_struct_ptr,
1292                                                                 struct drsuapi_DsReplicaUpdateRefs);
1293         NTSTATUS status;
1294
1295         state->ndr_struct_ptr = NULL;
1296
1297         status = dcerpc_drsuapi_DsReplicaUpdateRefs_r_recv(subreq, r);
1298         TALLOC_FREE(subreq);
1299         if (!NT_STATUS_IS_OK(status)) {
1300                 DEBUG(0,("UpdateRefs failed with %s\n", 
1301                          nt_errstr(status)));
1302                 tevent_req_nterror(req, status);
1303                 return;
1304         }
1305
1306         if (!W_ERROR_IS_OK(r->out.result)) {
1307                 status = werror_to_ntstatus(r->out.result);
1308                 DEBUG(0,("UpdateRefs failed with %s/%s for %s %s\n",
1309                          win_errstr(r->out.result),
1310                          nt_errstr(status),
1311                          r->in.req.req1.dest_dsa_dns_name,
1312                          r->in.req.req1.naming_context->dn));
1313                 /*
1314                  * TODO we are currently not sending the
1315                  * DsReplicaUpdateRefs at the correct moment,
1316                  * we do it just after a GetNcChanges which is
1317                  * not always correct.
1318                  * Especially when another DC is trying to demote
1319                  * it will sends us a DsReplicaSync that will trigger a getNcChanges
1320                  * this call will succeed but the DsRecplicaUpdateRefs that we send
1321                  * just after will not because the DC is in a demote state and
1322                  * will reply us a WERR_DS_DRA_BUSY, this error will cause us to
1323                  * answer to the DsReplicaSync with a non OK status, the other DC
1324                  * will stop the demote due to this error.
1325                  * In order to cope with this we will for the moment concider
1326                  * a DS_DRA_BUSY not as an error.
1327                  * It's not ideal but it should not have a too huge impact for
1328                  * running production as this error otherwise never happen and
1329                  * due to the fact the send a DsReplicaUpdateRefs after each getNcChanges
1330                  */
1331                 if (!W_ERROR_EQUAL(r->out.result, WERR_DS_DRA_BUSY)) {
1332                         tevent_req_nterror(req, status);
1333                         return;
1334                 }
1335         }
1336
1337         DEBUG(4,("UpdateRefs OK for %s %s\n", 
1338                  r->in.req.req1.dest_dsa_dns_name,
1339                  r->in.req.req1.naming_context->dn));
1340
1341         tevent_req_done(req);
1342 }
1343
1344 WERROR dreplsrv_op_pull_source_recv(struct tevent_req *req)
1345 {
1346         NTSTATUS status;
1347
1348         if (tevent_req_is_nterror(req, &status)) {
1349                 tevent_req_received(req);
1350                 return ntstatus_to_werror(status);
1351         }
1352
1353         tevent_req_received(req);
1354         return WERR_OK;
1355 }
1356