drepl: Support GET_TGT on periodic replication client
[nivanova/samba-autobuild/.git] / source4 / dsdb / repl / drepl_out_pull.c
index 0c68cc931056bf475f8a33a3ddb31c4f97433167..62a403c91c94545b780d698b79bd9b3db29d2426 100644 (file)
@@ -57,8 +57,8 @@ void drepl_reps_update(struct dreplsrv_service *s, const char *reps_attr,
        }
 
        for (i=0; i<count; i++) {
-               if (GUID_compare(source_dsa_obj_guid,
-                                &reps[i].ctr.ctr1.source_dsa_obj_guid) == 0) {
+               if (GUID_equal(source_dsa_obj_guid,
+                              &reps[i].ctr.ctr1.source_dsa_obj_guid)) {
                        break;
                }
        }
@@ -101,15 +101,34 @@ WERROR dreplsrv_schedule_partition_pull_source(struct dreplsrv_service *s,
        W_ERROR_HAVE_NO_MEMORY(op);
 
        op->service     = s;
-       op->source_dsa  = source;
+       /*
+        * source may either be the long-term list of partners, or
+        * from dreplsrv_partition_source_dsa_temporary().  Because it
+        * can be either, we can't talloc_steal() it here, so we
+        * instead we reference it.
+        *
+        * We never talloc_free() the p->sources pointers - indeed we
+        * never remove them - and the temp source will otherwise go
+        * away with the msg it is allocated on.
+        *
+        * Finally the pointer created in drepl_request_extended_op()
+        * is removed with talloc_unlink().
+        *
+        */
+       op->source_dsa  = talloc_reference(op, source);
+       if (!op->source_dsa) {
+               return WERR_NOT_ENOUGH_MEMORY;
+       }
+
        op->options     = options;
        op->extended_op = extended_op;
        op->fsmo_info   = fsmo_info;
        op->callback    = callback;
        op->cb_data     = cb_data;
        op->schedule_time = time(NULL);
+       op->more_flags  = 0;
 
-       DLIST_ADD_END(s->ops.pending, op, struct dreplsrv_out_operation *);
+       DLIST_ADD_END(s->ops.pending, op);
 
        return WERR_OK;
 }
@@ -178,8 +197,9 @@ void dreplsrv_run_pull_ops(struct dreplsrv_service *s)
        time_t t;
        NTTIME now;
        struct tevent_req *subreq;
+       WERROR werr;
 
-       if (s->ops.current) {
+       if (s->ops.n_current || s->ops.current) {
                /* if there's still one running, we're done */
                return;
        }
@@ -198,24 +218,40 @@ void dreplsrv_run_pull_ops(struct dreplsrv_service *s)
 
        op->source_dsa->repsFrom1->last_attempt = now;
 
-       subreq = dreplsrv_op_pull_source_send(op, s->task->event_ctx, op);
-       if (!subreq) {
-               struct repsFromTo1 *rf = op->source_dsa->repsFrom1;
-
-               if (op->extended_op == DRSUAPI_EXOP_NONE) {
-                       drepl_reps_update(s, "repsFrom", op->source_dsa->partition->dn,
-                                         &rf->source_dsa_obj_guid, WERR_NOMEM);
+       /* check if inbound replication is enabled */
+       if (!(op->options & DRSUAPI_DRS_SYNC_FORCED)) {
+               uint32_t rep_options;
+               if (samdb_ntds_options(op->service->samdb, &rep_options) != LDB_SUCCESS) {
+                       werr = WERR_DS_DRA_INTERNAL_ERROR;
+                       goto failed;
                }
-               s->ops.current = NULL;
-
-               /*
-                * call the callback (if any) so it gets the chance
-                * to do its job just like in any other failure situation
-                */
-               if (op->callback) {
-                       op->callback(s, WERR_NOMEM, op->extended_ret, op->cb_data);
+
+               if ((rep_options & DS_NTDSDSA_OPT_DISABLE_INBOUND_REPL)) {
+                       werr = WERR_DS_DRA_SINK_DISABLED;
+                       goto failed;
                }
-               return;
        }
+
+       subreq = dreplsrv_op_pull_source_send(op, s->task->event_ctx, op);
+       if (!subreq) {
+               werr = WERR_NOT_ENOUGH_MEMORY;
+               goto failed;
+       }
+
        tevent_req_set_callback(subreq, dreplsrv_pending_op_callback, op);
+       return;
+
+failed:
+       if (op->extended_op == DRSUAPI_EXOP_NONE) {
+               drepl_reps_update(s, "repsFrom", op->source_dsa->partition->dn,
+                                 &op->source_dsa->repsFrom1->source_dsa_obj_guid, werr);
+       }
+       /* unblock queue processing */
+       s->ops.current = NULL;
+       /*
+        * let the callback do its job just like in any other failure situation
+        */
+       if (op->callback) {
+               op->callback(s, werr, op->extended_ret, op->cb_data);
+       }
 }