--- sssd-1.1.0/src/providers/fail_over.h.gss	2010-03-22 22:34:57.000000000 +0300
+++ sssd-1.1.0/src/providers/fail_over.h	2010-03-29 11:33:01.072599731 +0400
@@ -93,6 +93,11 @@
                    struct fo_service **_service);
 
 /*
+ * Get number of servers registered for the 'service'.
+ */
+int fo_get_server_count(struct fo_service *service);
+
+/*
  * Adds a server 'name' to the 'service'. Port 'port' will be used for
  * connection. If 'name' is NULL, no server resolution will be done.
  */
--- sssd-1.1.0/src/providers/ldap/sdap_async_private.h.gss	2010-03-22 22:34:57.000000000 +0300
+++ sssd-1.1.0/src/providers/ldap/sdap_async_private.h	2010-03-29 11:33:01.072599731 +0400
@@ -63,6 +63,7 @@
 int sdap_get_tgt_recv(struct tevent_req *req,
                       TALLOC_CTX *mem_ctx,
                       int  *result,
-                      char **ccname);
+                      char **ccname,
+                      time_t *expire_time);
 
 #endif /* _SDAP_ASYNC_PRIVATE_H_ */
--- sssd-1.1.0/src/providers/ldap/sdap_async_connection.c.gss	2010-03-22 22:34:57.000000000 +0300
+++ sssd-1.1.0/src/providers/ldap/sdap_async_connection.c	2010-03-29 11:33:01.073600972 +0400
@@ -600,6 +600,7 @@
 
 struct sdap_kinit_state {
     int result;
+    time_t expire_time;
 };
 
 static void sdap_kinit_done(struct tevent_req *subreq);
@@ -652,8 +653,9 @@
     int ret;
     int result;
     char *ccname = NULL;
+    time_t expire_time;
 
-    ret = sdap_get_tgt_recv(subreq, state, &result, &ccname);
+    ret = sdap_get_tgt_recv(subreq, state, &result, &ccname, &expire_time);
     talloc_zfree(subreq);
     if (ret != EOK) {
         state->result = SDAP_AUTH_FAILED;
@@ -670,6 +672,7 @@
             tevent_req_error(req, EFAULT);
         }
 
+        state->expire_time = expire_time;
         state->result = SDAP_AUTH_SUCCESS;
         tevent_req_done(req);
         return;
@@ -680,7 +683,7 @@
     tevent_req_error(req, EIO);
 }
 
-int sdap_kinit_recv(struct tevent_req *req, enum sdap_result *result)
+int sdap_kinit_recv(struct tevent_req *req, enum sdap_result *result, time_t *expire_time)
 {
     struct sdap_kinit_state *state = tevent_req_data(req,
                                                      struct sdap_kinit_state);
@@ -695,6 +698,7 @@
     }
 
     *result = state->result;
+    *expire_time = state->expire_time;
     return EOK;
 }
 
@@ -1028,10 +1032,14 @@
 {
     struct tevent_req *req = tevent_req_callback_data(subreq,
                                                       struct tevent_req);
+    struct sdap_cli_connect_state *state = tevent_req_data(req,
+                                             struct sdap_cli_connect_state);
+
     enum sdap_result result;
+    time_t expire_time;
     int ret;
 
-    ret = sdap_kinit_recv(subreq, &result);
+    ret = sdap_kinit_recv(subreq, &result, &expire_time);
     talloc_zfree(subreq);
     if (ret) {
         tevent_req_error(req, ret);
@@ -1041,6 +1049,7 @@
         tevent_req_error(req, EACCES);
         return;
     }
+    state->sh->expire_time = expire_time;
 
     sdap_cli_auth_step(req);
 }
@@ -1094,6 +1103,7 @@
 
 int sdap_cli_connect_recv(struct tevent_req *req,
                           TALLOC_CTX *memctx,
+                          bool *can_retry,
                           struct sdap_handle **gsh,
                           struct sysdb_attrs **rootdse)
 {
@@ -1102,10 +1112,13 @@
     enum tevent_req_state tstate;
     uint64_t err;
 
+    *can_retry = true;
     if (tevent_req_is_error(req, &tstate, &err)) {
         /* mark the server as bad if connection failed */
         if (state->srv) {
             fo_set_port_status(state->srv, PORT_NOT_WORKING);
+        } else {
+            *can_retry = false;
         }
 
         if (tstate == TEVENT_REQ_USER_ERROR) {
--- sssd-1.1.0/src/providers/ldap/ldap_id.c.gss	2010-03-22 22:34:57.000000000 +0300
+++ sssd-1.1.0/src/providers/ldap/ldap_id.c	2010-03-29 11:33:01.074601096 +0400
@@ -35,7 +35,7 @@
 
 struct users_get_state {
     struct tevent_context *ev;
-    struct sdap_id_ctx *ctx;
+    struct sdap_id_op *op;
     struct sysdb_ctx *sysdb;
     struct sss_domain_info *domain;
 
@@ -46,19 +46,19 @@
     const char **attrs;
 };
 
-static void users_get_connect_done(struct tevent_req *subreq);
 static void users_get_done(struct tevent_req *subreq);
 static void users_get_delete(struct tevent_req *subreq);
 
 struct tevent_req *users_get_send(TALLOC_CTX *memctx,
                                   struct tevent_context *ev,
-                                  struct sdap_id_ctx *ctx,
+                                  struct sdap_id_op *op,
                                   const char *name,
                                   int filter_type,
                                   int attrs_type)
 {
     struct tevent_req *req, *subreq;
     struct users_get_state *state;
+    struct sdap_id_ctx *ctx = op->ctx;
     const char *attr_name;
     int ret;
 
@@ -66,9 +66,9 @@
     if (!req) return NULL;
 
     state->ev = ev;
-    state->ctx = ctx;
+    state->op = op;
     state->sysdb = ctx->be->sysdb;
-    state->domain = state->ctx->be->domain;
+    state->domain = ctx->be->domain;
     state->name = name;
     state->filter_type = filter_type;
 
@@ -98,28 +98,9 @@
                                SDAP_OPTS_USER, &state->attrs);
     if (ret != EOK) goto fail;
 
-    if (!sdap_connected(ctx)) {
-
-        if (ctx->gsh) talloc_zfree(ctx->gsh);
-
-        /* FIXME: add option to decide if tls should be used
-         * or SASL/GSSAPI, etc ... */
-        subreq = sdap_cli_connect_send(state, ev, ctx->opts,
-                                       ctx->be, ctx->service,
-                                       &ctx->rootDSE);
-        if (!subreq) {
-            ret = ENOMEM;
-            goto fail;
-        }
-
-        tevent_req_set_callback(subreq, users_get_connect_done, req);
-
-        return req;
-    }
-
     subreq = sdap_get_users_send(state, state->ev,
                                  state->domain, state->sysdb,
-                                 state->ctx->opts, state->ctx->gsh,
+                                 state->op->ctx->opts, sdap_id_op_handle(op),
                                  state->attrs, state->filter);
     if (!subreq) {
         ret = ENOMEM;
@@ -135,36 +116,6 @@
     return req;
 }
 
-static void users_get_connect_done(struct tevent_req *subreq)
-{
-    struct tevent_req *req = tevent_req_callback_data(subreq,
-                                                      struct tevent_req);
-    struct users_get_state *state = tevent_req_data(req,
-                                                     struct users_get_state);
-    int ret;
-
-    ret = sdap_cli_connect_recv(subreq, state->ctx,
-                                &state->ctx->gsh, &state->ctx->rootDSE);
-    talloc_zfree(subreq);
-    if (ret) {
-        if (ret == ENOTSUP) {
-            DEBUG(0, ("Authentication mechanism not Supported by server"));
-        }
-        tevent_req_error(req, ret);
-        return;
-    }
-
-    subreq = sdap_get_users_send(state, state->ev,
-                                 state->domain, state->sysdb,
-                                 state->ctx->opts, state->ctx->gsh,
-                                 state->attrs, state->filter);
-    if (!subreq) {
-        tevent_req_error(req, ENOMEM);
-        return;
-    }
-    tevent_req_set_callback(subreq, users_get_done, req);
-}
-
 static void users_get_done(struct tevent_req *subreq)
 {
     struct tevent_req *req = tevent_req_callback_data(subreq,
@@ -258,7 +209,7 @@
 
 struct groups_get_state {
     struct tevent_context *ev;
-    struct sdap_id_ctx *ctx;
+    struct sdap_id_op *op;
     struct sysdb_ctx *sysdb;
     struct sss_domain_info *domain;
 
@@ -269,17 +220,17 @@
     const char **attrs;
 };
 
-static void groups_get_connect_done(struct tevent_req *subreq);
 static void groups_get_done(struct tevent_req *subreq);
 static void groups_get_delete(struct tevent_req *subreq);
 
 struct tevent_req *groups_get_send(TALLOC_CTX *memctx,
                                    struct tevent_context *ev,
-                                   struct sdap_id_ctx *ctx,
+                                   struct sdap_id_op *op,
                                    const char *name,
                                    int filter_type,
                                    int attrs_type)
 {
+    struct sdap_id_ctx *ctx = op->ctx;
     struct tevent_req *req, *subreq;
     struct groups_get_state *state;
     const char *attr_name;
@@ -289,9 +240,9 @@
     if (!req) return NULL;
 
     state->ev = ev;
-    state->ctx = ctx;
+    state->op = op;
     state->sysdb = ctx->be->sysdb;
-    state->domain = state->ctx->be->domain;
+    state->domain = ctx->be->domain;
     state->name = name;
     state->filter_type = filter_type;
 
@@ -321,28 +272,9 @@
                                SDAP_OPTS_GROUP, &state->attrs);
     if (ret != EOK) goto fail;
 
-    if (!sdap_connected(ctx)) {
-
-        if (ctx->gsh) talloc_zfree(ctx->gsh);
-
-        /* FIXME: add option to decide if tls should be used
-         * or SASL/GSSAPI, etc ... */
-        subreq = sdap_cli_connect_send(state, ev, ctx->opts,
-                                       ctx->be, ctx->service,
-                                       &ctx->rootDSE);
-        if (!subreq) {
-            ret = ENOMEM;
-            goto fail;
-        }
-
-        tevent_req_set_callback(subreq, groups_get_connect_done, req);
-
-        return req;
-    }
-
     subreq = sdap_get_groups_send(state, state->ev,
                                   state->domain, state->sysdb,
-                                  state->ctx->opts, state->ctx->gsh,
+                                  state->op->ctx->opts, sdap_id_op_handle(op),
                                   state->attrs, state->filter);
     if (!subreq) {
         ret = ENOMEM;
@@ -358,36 +290,6 @@
     return req;
 }
 
-static void groups_get_connect_done(struct tevent_req *subreq)
-{
-    struct tevent_req *req = tevent_req_callback_data(subreq,
-                                                      struct tevent_req);
-    struct groups_get_state *state = tevent_req_data(req,
-                                                     struct groups_get_state);
-    int ret;
-
-    ret = sdap_cli_connect_recv(subreq, state->ctx,
-                                &state->ctx->gsh, &state->ctx->rootDSE);
-    talloc_zfree(subreq);
-    if (ret) {
-        if (ret == ENOTSUP) {
-            DEBUG(0, ("Authentication mechanism not Supported by server"));
-        }
-        tevent_req_error(req, ret);
-        return;
-    }
-
-    subreq = sdap_get_groups_send(state, state->ev,
-                                  state->domain, state->sysdb,
-                                  state->ctx->opts, state->ctx->gsh,
-                                  state->attrs, state->filter);
-    if (!subreq) {
-        tevent_req_error(req, ENOMEM);
-        return;
-    }
-    tevent_req_set_callback(subreq, groups_get_done, req);
-}
-
 static void groups_get_done(struct tevent_req *subreq)
 {
     struct tevent_req *req = tevent_req_callback_data(subreq,
@@ -481,19 +383,19 @@
 
 struct groups_by_user_state {
     struct tevent_context *ev;
-    struct sdap_id_ctx *ctx;
+    struct sdap_id_op *op;
     const char *name;
     const char **attrs;
 };
 
-static void groups_by_user_connect_done(struct tevent_req *subreq);
 static void groups_by_user_done(struct tevent_req *subreq);
 
 static struct tevent_req *groups_by_user_send(TALLOC_CTX *memctx,
                                               struct tevent_context *ev,
-                                              struct sdap_id_ctx *ctx,
+                                              struct sdap_id_op *op,
                                               const char *name)
 {
+    struct sdap_id_ctx *ctx = op->ctx;
     struct tevent_req *req, *subreq;
     struct groups_by_user_state *state;
     int ret;
@@ -502,36 +404,17 @@
     if (!req) return NULL;
 
     state->ev = ev;
-    state->ctx = ctx;
+    state->op = op;
     state->name = name;
 
     ret = build_attrs_from_map(state, ctx->opts->group_map,
                                SDAP_OPTS_GROUP, &state->attrs);
     if (ret != EOK) goto fail;
 
-    if (!sdap_connected(ctx)) {
-
-        if (ctx->gsh) talloc_zfree(ctx->gsh);
-
-        /* FIXME: add option to decide if tls should be used
-         * or SASL/GSSAPI, etc ... */
-        subreq = sdap_cli_connect_send(state, ev, ctx->opts,
-                                       ctx->be, ctx->service,
-                                       &ctx->rootDSE);
-        if (!subreq) {
-            ret = ENOMEM;
-            goto fail;
-        }
-
-        tevent_req_set_callback(subreq, groups_by_user_connect_done, req);
-
-        return req;
-    }
-
     subreq = sdap_get_initgr_send(state, state->ev,
-                                  state->ctx->be->domain,
-                                  state->ctx->be->sysdb,
-                                  state->ctx->opts, state->ctx->gsh,
+                                  state->op->ctx->be->domain,
+                                  state->op->ctx->be->sysdb,
+                                  state->op->ctx->opts, sdap_id_op_handle(op),
                                   state->name, state->attrs);
     if (!subreq) {
         ret = ENOMEM;
@@ -547,37 +430,6 @@
     return req;
 }
 
-static void groups_by_user_connect_done(struct tevent_req *subreq)
-{
-    struct tevent_req *req = tevent_req_callback_data(subreq,
-                                                      struct tevent_req);
-    struct groups_by_user_state *state = tevent_req_data(req,
-                                                     struct groups_by_user_state);
-    int ret;
-
-    ret = sdap_cli_connect_recv(subreq, state->ctx,
-                                &state->ctx->gsh, &state->ctx->rootDSE);
-    talloc_zfree(subreq);
-    if (ret) {
-        if (ret == ENOTSUP) {
-            DEBUG(0, ("Authentication mechanism not Supported by server"));
-        }
-        tevent_req_error(req, ret);
-        return;
-    }
-
-    subreq = sdap_get_initgr_send(state, state->ev,
-                                  state->ctx->be->domain,
-                                  state->ctx->be->sysdb,
-                                  state->ctx->opts, state->ctx->gsh,
-                                  state->name, state->attrs);
-    if (!subreq) {
-        tevent_req_error(req, ENOMEM);
-        return;
-    }
-    tevent_req_set_callback(subreq, groups_by_user_done, req);
-}
-
 static void groups_by_user_done(struct tevent_req *subreq)
 {
     struct tevent_req *req = tevent_req_callback_data(subreq,
@@ -607,6 +459,16 @@
 
 /* FIXME: embed this function in sssd_be and only call out
  * specific functions from modules ? */
+ 
+struct sdap_account_info_state {
+    struct be_req *breq;
+    struct sdap_id_op *op;
+};
+
+static struct sdap_account_info_state *sdap_account_info_create_state(
+    struct sdap_id_ctx *ctx, struct be_req *breq);
+static void sdap_account_info_handler_retry(struct sdap_account_info_state* state);
+static void sdap_account_request_connect_done(struct sdap_id_op* op, int ret, void* pvt);
 
 static void sdap_account_info_users_done(struct tevent_req *req);
 static void sdap_account_info_groups_done(struct tevent_req *req);
@@ -616,9 +478,7 @@
 {
     struct sdap_id_ctx *ctx;
     struct be_acct_req *ar;
-    struct tevent_req *req;
-    const char *err = "Unknown Error";
-    int ret = EOK;
+    struct sdap_account_info_state* state = NULL;
 
     ctx = talloc_get_type(breq->be_ctx->bet_info[BET_ID].pvt_bet_data, struct sdap_id_ctx);
 
@@ -636,59 +496,136 @@
             return sdap_handler_done(breq, DP_ERR_OK, EOK, "Success");
         }
 
-        req = users_get_send(breq, breq->be_ctx->ev, ctx,
+        break;
+
+    case BE_REQ_GROUP: /* group */
+
+        /* skip enumerations on demand */
+        if (strcmp(ar->filter_value, "*") == 0) {
+            return sdap_handler_done(breq, DP_ERR_OK, EOK, "Success");
+        }
+
+        break;
+
+    case BE_REQ_INITGROUPS: /* init groups for user */
+        if (ar->filter_type != BE_FILTER_NAME) {
+            sdap_handler_done(breq, DP_ERR_FATAL, EINVAL, "Invalid filter type");
+            return;
+        }
+        if (ar->attr_type != BE_ATTR_CORE) {
+            sdap_handler_done(breq, DP_ERR_FATAL, EINVAL, "Invalid attr type");
+            return;
+        }
+        if (strchr(ar->filter_value, '*')) {
+            sdap_handler_done(breq, DP_ERR_FATAL, EINVAL, "Invalid filter value");
+            return;
+        }
+
+        break;
+
+    default: /*fail*/
+        sdap_handler_done(breq, DP_ERR_FATAL, EINVAL, "Invalid request type");
+        return;
+    }
+
+    state = sdap_account_info_create_state(ctx, breq);
+    if (!state) {
+        sdap_handler_done(breq, DP_ERR_FATAL, ENOMEM, "Out of memory");
+        return;
+    }
+    
+    sdap_account_info_handler_retry(state);
+}
+
+static struct sdap_account_info_state *sdap_account_info_create_state(struct sdap_id_ctx *ctx, struct be_req *breq)
+{
+    struct sdap_account_info_state* state = talloc_zero(breq, struct sdap_account_info_state);
+    if (!state) {
+        return NULL;
+    }
+    
+    state->breq = breq;
+    state->op = sdap_id_op_create(state, ctx);
+    if (!state->op) {
+        goto fail;
+    }
+    
+    return state;
+    
+fail:
+    talloc_zfree(state);
+    return NULL;
+}
+
+static void sdap_account_info_handler_retry(struct sdap_account_info_state* state)
+{
+    sdap_id_op_connect(state->op, sdap_account_request_connect_done, state);
+}
+
+static void sdap_account_request_connect_done(struct sdap_id_op* op, int ret, void* pvt)
+{
+    struct sdap_account_info_state *state = talloc_get_type(pvt,
+                                                            struct sdap_account_info_state);
+    struct be_req *breq = state->breq;
+    struct be_acct_req *ar;
+    struct tevent_req *req;
+    const char *err = "Unknown Error";
+    
+    ar = talloc_get_type(breq->req_data, struct be_acct_req);
+
+    switch (ar->entry_type & 0xFFF) {
+    case BE_REQ_USER: /* user */
+        if (ret) {
+            err = "Enum Users Failed";
+            break;
+        }
+
+        req = users_get_send(breq, breq->be_ctx->ev, state->op,
                              ar->filter_value,
                              ar->filter_type,
                              ar->attr_type);
         if (!req) {
-            return sdap_handler_done(breq, DP_ERR_FATAL, ENOMEM, "Out of memory");
+            ret = ENOMEM;
+            break;
         }
 
-        tevent_req_set_callback(req, sdap_account_info_users_done, breq);
+        tevent_req_set_callback(req, sdap_account_info_users_done, state);
 
         break;
 
     case BE_REQ_GROUP: /* group */
-
-        if (strcmp(ar->filter_value, "*") == 0) {
-            return sdap_handler_done(breq, DP_ERR_OK, EOK, "Success");
+        if (ret) {
+            err = "Enum Groups Failed";
+            break;
         }
 
-        /* skip enumerations on demand */
-        req = groups_get_send(breq, breq->be_ctx->ev, ctx,
+        req = groups_get_send(breq, breq->be_ctx->ev, state->op,
                               ar->filter_value,
                               ar->filter_type,
                               ar->attr_type);
         if (!req) {
-            return sdap_handler_done(breq, DP_ERR_FATAL, ENOMEM, "Out of memory");
+            ret = ENOMEM;
+            break;
         }
 
-        tevent_req_set_callback(req, sdap_account_info_groups_done, breq);
+        tevent_req_set_callback(req, sdap_account_info_groups_done, state);
 
         break;
 
     case BE_REQ_INITGROUPS: /* init groups for user */
-        if (ar->filter_type != BE_FILTER_NAME) {
-            ret = EINVAL;
-            err = "Invalid filter type";
+        if (ret) {
+            err = "Init Groups Failed";
             break;
         }
-        if (ar->attr_type != BE_ATTR_CORE) {
-            ret = EINVAL;
-            err = "Invalid attr type";
-            break;
-        }
-        if (strchr(ar->filter_value, '*')) {
-            ret = EINVAL;
-            err = "Invalid filter value";
+
+        req = groups_by_user_send(breq, breq->be_ctx->ev, state->op,
+                                  ar->filter_value);
+        if (!req) {
+            ret = ENOMEM;
             break;
         }
-        req = groups_by_user_send(breq, breq->be_ctx->ev, ctx,
-                                  ar->filter_value);
-        if (!req) ret = ENOMEM;
-        /* tevent_req_set_callback(req, groups_by_user_done, breq); */
 
-        tevent_req_set_callback(req, sdap_account_info_initgr_done, breq);
+        tevent_req_set_callback(req, sdap_account_info_initgr_done, state);
 
         break;
 
@@ -697,99 +634,66 @@
         err = "Invalid request type";
     }
 
-    if (ret != EOK) return sdap_handler_done(breq, DP_ERR_FATAL, ret, err);
+    if (ret != EOK) {
+        talloc_zfree(state);
+        
+        if (ret == ENOMEM) {
+            err = "Out of memory";
+        }
+        
+        sdap_handler_done(breq, DP_ERR_FATAL, ret, err);
+    }
 }
 
-static void sdap_account_info_users_done(struct tevent_req *req)
+static void sdap_account_request_done(struct tevent_req *req, int ret, const char* default_error)
 {
-    struct be_req *breq = tevent_req_callback_data(req, struct be_req);
-    struct sdap_id_ctx *ctx;
-    int dp_err = DP_ERR_OK;
-    const char *error = NULL;
-    int ret;
+    struct sdap_account_info_state *state = tevent_req_callback_data(req, struct sdap_account_info_state);
+    struct be_req *breq = state->breq;
+    int dp_err;
+    const char* error;
 
-    ret = users_get_recv(req);
     talloc_zfree(req);
 
-    if (ret) {
-        dp_err = DP_ERR_FATAL;
-        error = "Enum Users Failed";
-
-        if (ret == ETIMEDOUT || ret == EFAULT || ret == EIO) {
-            dp_err = DP_ERR_OFFLINE;
-            ctx = talloc_get_type(breq->be_ctx->bet_info[BET_ID].pvt_bet_data,
-                                  struct sdap_id_ctx);
-            if (sdap_check_gssapi_reconnect(ctx)) {
-                talloc_zfree(ctx->gsh);
-                sdap_account_info_handler(breq);
+    ret = sdap_id_op_done(state->op, ret, &dp_err);
+    switch (dp_err) {
+        case DP_ERR_OK:
+            if( ret != EOK) {
+                /* retry */
+                sdap_account_info_handler_retry(state);
                 return;
             }
-            sdap_mark_offline(ctx);
-        }
+        
+            error = NULL;
+            break;
+
+        case DP_ERR_OFFLINE:
+            error = "Offline";
+            break;
+            
+        default:
+            error = default_error;
+            break;
     }
 
+    talloc_zfree(state);
     sdap_handler_done(breq, dp_err, ret, error);
 }
 
-static void sdap_account_info_groups_done(struct tevent_req *req)
+static void sdap_account_info_users_done(struct tevent_req *req)
 {
-    struct be_req *breq = tevent_req_callback_data(req, struct be_req);
-    struct sdap_id_ctx *ctx;
-    int dp_err = DP_ERR_OK;
-    const char *error = NULL;
-    int ret;
-
-    ret = groups_get_recv(req);
-    talloc_zfree(req);
-
-    if (ret) {
-        dp_err = DP_ERR_FATAL;
-        error = "Enum Groups Failed";
-
-        if (ret == ETIMEDOUT || ret == EFAULT || ret == EIO) {
-            dp_err = DP_ERR_OFFLINE;
-            ctx = talloc_get_type(breq->be_ctx->bet_info[BET_ID].pvt_bet_data,
-                                  struct sdap_id_ctx);
-            if (sdap_check_gssapi_reconnect(ctx)) {
-                talloc_zfree(ctx->gsh);
-                sdap_account_info_handler(breq);
-                return;
-            }
-            sdap_mark_offline(ctx);
-        }
-    }
+    int ret = users_get_recv(req);
+    sdap_account_request_done(req, ret, "Enum Users Failed");
+}
 
-    return sdap_handler_done(breq, dp_err, ret, error);
+static void sdap_account_info_groups_done(struct tevent_req *req)
+{
+    int ret = groups_get_recv(req);
+    sdap_account_request_done(req, ret, "Enum Groups Failed");
 }
 
 static void sdap_account_info_initgr_done(struct tevent_req *req)
 {
-    struct be_req *breq = tevent_req_callback_data(req, struct be_req);
-    struct sdap_id_ctx *ctx;
-    int dp_err = DP_ERR_OK;
-    const char *error = NULL;
-    int ret;
-
-    ret = groups_by_user_recv(req);
-    talloc_zfree(req);
-
-    if (ret) {
-        dp_err = DP_ERR_FATAL;
-        error = "Init Groups Failed";
-
-        if (ret == ETIMEDOUT || ret == EFAULT || ret == EIO) {
-            dp_err = DP_ERR_OFFLINE;
-            ctx = talloc_get_type(breq->be_ctx->bet_info[BET_ID].pvt_bet_data,
-                                  struct sdap_id_ctx);
-            if (sdap_check_gssapi_reconnect(ctx)) {
-                talloc_zfree(ctx->gsh);
-                sdap_account_info_handler(breq);
-                return;
-            }
-            sdap_mark_offline(ctx);
-        }
-    }
-
-    return sdap_handler_done(breq, dp_err, ret, error);
+    int ret = groups_by_user_recv(req);
+    sdap_account_request_done(req, ret, "Init Groups Failed");
 }
 
--- sssd-1.1.0/src/providers/ldap/ldap_child.c.gss	2010-03-22 22:34:57.000000000 +0300
+++ sssd-1.1.0/src/providers/ldap/ldap_child.c	2010-03-29 11:33:01.074601096 +0400
@@ -89,13 +89,13 @@
     return EOK;
 }
 
-static int pack_buffer(struct response *r, int result, const char *msg)
+static int pack_buffer(struct response *r, int result, const char *msg, time_t expire_time)
 {
     int len;
     size_t p = 0;
 
     len = strlen(msg);
-    r->size = 2 * sizeof(uint32_t) + len;
+    r->size = 2 * sizeof(uint32_t) + len + sizeof(time_t);
 
     /* result */
     SAFEALIGN_SET_UINT32(&r->buf[p], result, &p);
@@ -105,6 +105,9 @@
 
     /* message itself */
     safealign_memcpy(&r->buf[p], msg, len, &p);
+    
+    /* ticket expiration time */
+    safealign_memcpy(&r->buf[p], &expire_time, sizeof(expire_time), &p);
 
     return EOK;
 }
@@ -113,7 +116,8 @@
                                   const char *realm_str,
                                   const char *princ_str,
                                   const char *keytab_name,
-                                  const char **ccname_out)
+                                  const char **ccname_out,
+                                  time_t *expire_time_out)
 {
     char *ccname;
     char *realm_name = NULL;
@@ -215,8 +219,6 @@
     krb5_get_init_creds_opt_set_address_list(&options, NULL);
     krb5_get_init_creds_opt_set_forwardable(&options, 0);
     krb5_get_init_creds_opt_set_proxiable(&options, 0);
-    /* set a very short lifetime, we don't keep the ticket around */
-    krb5_get_init_creds_opt_set_tkt_life(&options, 300);
 
     krberr = krb5_get_init_creds_keytab(context, &my_creds, kprinc,
                                         keytab, 0, NULL, &options);
@@ -235,7 +237,7 @@
         ret = EFAULT;
         goto done;
     }
-
+    
     krberr = krb5_cc_store_cred(context, ccache, &my_creds);
     if (krberr) {
         DEBUG(2, ("Failed to store creds: %s\n",
@@ -243,9 +245,11 @@
         ret = EFAULT;
         goto done;
     }
-
+    
+    
     ret = EOK;
     *ccname_out = ccname;
+    *expire_time_out = my_creds.times.endtime;
 
 done:
     if (keytab) krb5_kt_close(context, keytab);
@@ -255,6 +259,7 @@
 
 static int prepare_response(TALLOC_CTX *mem_ctx,
                             const char *ccname,
+                            time_t expire_time,
                             krb5_error_code kerr,
                             struct response **rsp)
 {
@@ -274,7 +279,7 @@
     r->size = 0;
 
     if (kerr == 0) {
-        ret = pack_buffer(r, EOK, ccname);
+        ret = pack_buffer(r, EOK, ccname, expire_time);
     } else {
         krb5_msg = sss_krb5_get_error_message(krb5_error_ctx, kerr);
         if (krb5_msg == NULL) {
@@ -282,7 +287,7 @@
             return ENOMEM;
         }
 
-        ret = pack_buffer(r, EFAULT, krb5_msg);
+        ret = pack_buffer(r, EFAULT, krb5_msg, 0);
         sss_krb5_free_error_message(krb5_error_ctx, krb5_msg);
     }
 
@@ -306,6 +311,7 @@
     uint8_t *buf = NULL;
     ssize_t len = 0;
     const char *ccname = NULL;
+    time_t expire_time = 0;
     struct input_buffer *ibuf = NULL;
     struct response *resp = NULL;
     size_t written;
@@ -392,13 +398,13 @@
 
     kerr = ldap_child_get_tgt_sync(main_ctx,
                                    ibuf->realm_str, ibuf->princ_str,
-                                   ibuf->keytab_name, &ccname);
+                                   ibuf->keytab_name, &ccname, &expire_time);
     if (kerr != EOK) {
         DEBUG(1, ("ldap_child_get_tgt_sync failed.\n"));
         /* Do not return, must report failure */
     }
 
-    ret = prepare_response(main_ctx, ccname, kerr, &resp);
+    ret = prepare_response(main_ctx, ccname, expire_time, kerr, &resp);
     if (ret != EOK) {
         DEBUG(1, ("prepare_response failed. [%d][%s].\n", ret, strerror(ret)));
         return ENOMEM;
--- sssd-1.1.0/src/providers/ldap/sdap_async.h.gss	2010-03-22 22:34:57.000000000 +0300
+++ sssd-1.1.0/src/providers/ldap/sdap_async.h	2010-03-29 11:33:01.075600941 +0400
@@ -66,7 +66,7 @@
                                    const char *keytab,
                                    const char *principal,
                                    const char *realm);
-int sdap_kinit_recv(struct tevent_req *req, enum sdap_result *result);
+int sdap_kinit_recv(struct tevent_req *req, enum sdap_result *result, time_t *expire_time);
 
 struct tevent_req *sdap_auth_send(TALLOC_CTX *memctx,
                                   struct tevent_context *ev,
@@ -106,6 +106,7 @@
                                          struct sysdb_attrs **rootdse);
 int sdap_cli_connect_recv(struct tevent_req *req,
                           TALLOC_CTX *memctx,
+                          bool *can_retry,
                           struct sdap_handle **gsh,
                           struct sysdb_attrs **rootdse);
 
--- sssd-1.1.0/src/providers/ldap/ldap_id_enum.c.gss	2010-03-22 22:34:57.000000000 +0300
+++ sssd-1.1.0/src/providers/ldap/ldap_id_enum.c	2010-03-29 11:33:01.075600941 +0400
@@ -147,18 +147,19 @@
 struct global_enum_state {
     struct tevent_context *ev;
     struct sdap_id_ctx *ctx;
+    struct sdap_id_op *op;
 
     bool purge;
 };
 
 static struct tevent_req *enum_users_send(TALLOC_CTX *memctx,
                                           struct tevent_context *ev,
-                                          struct sdap_id_ctx *ctx,
+                                          struct sdap_id_op *op,
                                           bool purge);
 static void ldap_id_enum_users_done(struct tevent_req *subreq);
 static struct tevent_req *enum_groups_send(TALLOC_CTX *memctx,
                                           struct tevent_context *ev,
-                                          struct sdap_id_ctx *ctx,
+                                          struct sdap_id_op *op,
                                           bool purge);
 static void ldap_id_enum_groups_done(struct tevent_req *subreq);
 static void ldap_id_enum_cleanup_done(struct tevent_req *subreq);
@@ -175,6 +176,11 @@
 
     state->ev = ev;
     state->ctx = ctx;
+    state->op = sdap_id_op_create(state, ctx);
+    if (!state->op) {
+        talloc_zfree(req);
+        return NULL;
+    }
 
     ctx->last_enum = tevent_timeval_current();
 
@@ -185,7 +191,7 @@
         state->purge = false;
     }
 
-    subreq = enum_users_send(state, ev, ctx, state->purge);
+    subreq = enum_users_send(state, ev, state->op, state->purge);
     if (!subreq) {
         talloc_zfree(req);
         return NULL;
@@ -203,43 +209,54 @@
                                                  struct global_enum_state);
     enum tevent_req_state tstate;
     uint64_t err = 0;
+    int retval, dp_err;
 
     if (tevent_req_is_error(subreq, &tstate, &err)) {
         if (tstate != TEVENT_REQ_USER_ERROR) {
             err = EIO;
-        }
-        if (err != ENOENT) {
-            goto fail;
+        } else if (err == ENOENT) {
+            err = EOK;
         }
     }
+    
     talloc_zfree(subreq);
 
-    subreq = enum_groups_send(state, state->ev, state->ctx, state->purge);
-    if (!subreq) {
-        goto fail;
-    }
-    tevent_req_set_callback(subreq, ldap_id_enum_groups_done, req);
-
-    return;
-
-fail:
-    if (err) {
-        DEBUG(9, ("User enumeration failed with: (%d)[%s]\n",
-                  (int)err, strerror(err)));
-
-        if (sdap_check_gssapi_reconnect(state->ctx)) {
-            talloc_zfree(state->ctx->gsh);
-            subreq = enum_users_send(state, state->ev, state->ctx, state->purge);
+    retval = sdap_id_op_done(state->op, err, &dp_err);
+    if (retval != EOK) {
+        if (dp_err == DP_ERR_OK) {
+            /* retry */
+            subreq = enum_users_send(state, state->ev, state->op, state->purge);
             if (subreq != NULL) {
                 tevent_req_set_callback(subreq, ldap_id_enum_users_done, req);
                 return;
             }
+            
+            retval = ENOMEM;
+            dp_err = DP_ERR_FATAL;
         }
-        sdap_mark_offline(state->ctx);
+
+        goto fail;        
+    }
+    
+    subreq = enum_groups_send(state, state->ev, state->op, state->purge);
+    if (!subreq) {
+        retval = ENOMEM;
+        goto fail;
     }
 
-    DEBUG(1, ("Failed to enumerate users, retrying later!\n"));
+    tevent_req_set_callback(subreq, ldap_id_enum_groups_done, req);
+    return;
+    
+fail:
+    if (dp_err != DP_ERR_OFFLINE) {
+        DEBUG(1, ("Failed to enumerate users (%d [%s]), retrying later!\n",
+                  retval, strerror(retval)));
+    } else {
+        DEBUG(9, ("Enumerate users canceled due to Offline, retrying later!\n"));
+    }
+    
     tevent_req_done(req);
+    return;
 }
 
 static void ldap_id_enum_groups_done(struct tevent_req *subreq)
@@ -250,21 +267,41 @@
                                                  struct global_enum_state);
     enum tevent_req_state tstate;
     uint64_t err = 0;
+    int retval, dp_err;
 
     if (tevent_req_is_error(subreq, &tstate, &err)) {
         if (tstate != TEVENT_REQ_USER_ERROR) {
             err = EIO;
-        }
-        if (err != ENOENT) {
-            goto fail;
+        } else if (err == ENOENT) {
+            err = EOK;
         }
     }
+    
     talloc_zfree(subreq);
 
+    retval = sdap_id_op_done(state->op, err, &dp_err);
+    if (retval != EOK) {
+        if (dp_err == DP_ERR_OK) {
+            /* retry */
+            subreq = enum_groups_send(state, state->ev, state->op, state->purge);
+            if (subreq != NULL) {
+                tevent_req_set_callback(subreq, ldap_id_enum_groups_done, req);
+                return;
+            }
+            
+            retval = ENOMEM;
+        }
+        
+        goto fail;
+    }
+    
+    talloc_zfree(state->op);
+
     if (state->purge) {
 
         subreq = ldap_id_cleanup_send(state, state->ev, state->ctx);
         if (!subreq) {
+            retval = ENOMEM;
             goto fail;
         }
         tevent_req_set_callback(subreq, ldap_id_enum_cleanup_done, req);
@@ -274,21 +311,17 @@
 
     tevent_req_done(req);
     return;
-
+    
 fail:
-    /* check if credentials are expired otherwise go offline on failures */
-    if (sdap_check_gssapi_reconnect(state->ctx)) {
-        talloc_zfree(state->ctx->gsh);
-        subreq = enum_groups_send(state, state->ev, state->ctx, state->purge);
-        if (subreq != NULL) {
-            tevent_req_set_callback(subreq, ldap_id_enum_groups_done, req);
-            return;
-        }
+    if (dp_err != DP_ERR_OFFLINE) {
+        DEBUG(1, ("Failed to enumerate groups (%d [%s]), retrying later!\n",
+                  retval, strerror(retval)));
+    } else {
+        DEBUG(9, ("Enumerate groups canceled due to Offline, retrying later!\n"));
     }
-    sdap_mark_offline(state->ctx);
-    DEBUG(1, ("Failed to enumerate groups (%d [%s]), retrying later!\n",
-              (int)err, strerror(err)));
+    
     tevent_req_done(req);
+    return;
 }
 
 static void ldap_id_enum_cleanup_done(struct tevent_req *subreq)
@@ -310,16 +343,17 @@
     const char **attrs;
 };
 
-static void enum_users_connect_done(struct tevent_req *subreq);
+static void enum_users_connect_done(struct sdap_id_op* op, int ret, void* pvt);
 static void enum_users_op_done(struct tevent_req *subreq);
 
 static struct tevent_req *enum_users_send(TALLOC_CTX *memctx,
                                           struct tevent_context *ev,
-                                          struct sdap_id_ctx *ctx,
+                                          struct sdap_id_op *op,
                                           bool purge)
 {
-    struct tevent_req *req, *subreq;
+    struct tevent_req *req;
     struct enum_users_state *state;
+    struct sdap_id_ctx *ctx = op->ctx;
     int ret;
 
     req = tevent_req_create(memctx, &state, struct enum_users_state);
@@ -355,37 +389,11 @@
                                SDAP_OPTS_USER, &state->attrs);
     if (ret != EOK) goto fail;
 
-    if (!sdap_connected(ctx)) {
-
-        if (ctx->gsh) talloc_zfree(ctx->gsh);
-
-        /* FIXME: add option to decide if tls should be used
-         * or SASL/GSSAPI, etc ... */
-        subreq = sdap_cli_connect_send(state, ev, ctx->opts,
-                                       ctx->be, ctx->service,
-                                       &ctx->rootDSE);
-        if (!subreq) {
-            ret = ENOMEM;
-            goto fail;
-        }
-
-        tevent_req_set_callback(subreq, enum_users_connect_done, req);
-
-        return req;
-    }
-
-    subreq = sdap_get_users_send(state, state->ev,
-                                 state->ctx->be->domain,
-                                 state->ctx->be->sysdb,
-                                 state->ctx->opts,
-                                 state->ctx->gsh,
-                                 state->attrs, state->filter);
-    if (!subreq) {
-        ret = ENOMEM;
-        goto fail;
+    sdap_id_op_connect(op, enum_users_connect_done, req);
+    if (!tevent_req_is_in_progress(req)) {
+        tevent_req_post(req, ev);
     }
-    tevent_req_set_callback(subreq, enum_users_op_done, req);
-
+    
     return req;
 
 fail:
@@ -394,21 +402,14 @@
     return req;
 }
 
-static void enum_users_connect_done(struct tevent_req *subreq)
+static void enum_users_connect_done(struct sdap_id_op* op, int ret, void* pvt)
 {
-    struct tevent_req *req = tevent_req_callback_data(subreq,
-                                                      struct tevent_req);
+    struct tevent_req *req = talloc_get_type(pvt, struct tevent_req);
     struct enum_users_state *state = tevent_req_data(req,
                                                      struct enum_users_state);
-    int ret;
+    struct tevent_req *subreq;
 
-    ret = sdap_cli_connect_recv(subreq, state->ctx,
-                                &state->ctx->gsh, &state->ctx->rootDSE);
-    talloc_zfree(subreq);
     if (ret) {
-        if (ret == ENOTSUP) {
-            DEBUG(0, ("Authentication mechanism not Supported by server"));
-        }
         tevent_req_error(req, ret);
         return;
     }
@@ -416,7 +417,7 @@
     subreq = sdap_get_users_send(state, state->ev,
                                  state->ctx->be->domain,
                                  state->ctx->be->sysdb,
-                                 state->ctx->opts, state->ctx->gsh,
+                                 state->ctx->opts, sdap_id_op_handle(op),
                                  state->attrs, state->filter);
     if (!subreq) {
         tevent_req_error(req, ENOMEM);
@@ -462,16 +463,17 @@
     const char **attrs;
 };
 
-static void enum_groups_connect_done(struct tevent_req *subreq);
+static void enum_groups_connect_done(struct sdap_id_op* op, int ret, void* pvt);
 static void enum_groups_op_done(struct tevent_req *subreq);
 
 static struct tevent_req *enum_groups_send(TALLOC_CTX *memctx,
                                           struct tevent_context *ev,
-                                          struct sdap_id_ctx *ctx,
+                                          struct sdap_id_op *op,
                                           bool purge)
 {
-    struct tevent_req *req, *subreq;
+    struct tevent_req *req;
     struct enum_groups_state *state;
+    struct sdap_id_ctx *ctx = op->ctx;
     const char *attr_name;
     int ret;
 
@@ -510,35 +512,10 @@
                                SDAP_OPTS_GROUP, &state->attrs);
     if (ret != EOK) goto fail;
 
-    if (!sdap_connected(ctx)) {
-
-        if (ctx->gsh) talloc_zfree(ctx->gsh);
-
-        /* FIXME: add option to decide if tls should be used
-         * or SASL/GSSAPI, etc ... */
-        subreq = sdap_cli_connect_send(state, ev, ctx->opts,
-                                       ctx->be, ctx->service,
-                                       &ctx->rootDSE);
-        if (!subreq) {
-            ret = ENOMEM;
-            goto fail;
-        }
-
-        tevent_req_set_callback(subreq, enum_groups_connect_done, req);
-
-        return req;
-    }
-
-    subreq = sdap_get_groups_send(state, state->ev,
-                                 state->ctx->be->domain,
-                                 state->ctx->be->sysdb,
-                                 state->ctx->opts, state->ctx->gsh,
-                                 state->attrs, state->filter);
-    if (!subreq) {
-        ret = ENOMEM;
-        goto fail;
+    sdap_id_op_connect(op, enum_groups_connect_done, req);
+    if (!tevent_req_is_in_progress(req)) {
+        tevent_req_post(req, ev);
     }
-    tevent_req_set_callback(subreq, enum_groups_op_done, req);
 
     return req;
 
@@ -548,21 +525,14 @@
     return req;
 }
 
-static void enum_groups_connect_done(struct tevent_req *subreq)
+static void enum_groups_connect_done(struct sdap_id_op* op, int ret, void* pvt)
 {
-    struct tevent_req *req = tevent_req_callback_data(subreq,
-                                                      struct tevent_req);
+    struct tevent_req *req = talloc_get_type(pvt, struct tevent_req);
     struct enum_groups_state *state = tevent_req_data(req,
                                                  struct enum_groups_state);
-    int ret;
+    struct tevent_req *subreq;
 
-    ret = sdap_cli_connect_recv(subreq, state->ctx,
-                                &state->ctx->gsh, &state->ctx->rootDSE);
-    talloc_zfree(subreq);
     if (ret) {
-        if (ret == ENOTSUP) {
-            DEBUG(0, ("Authentication mechanism not Supported by server"));
-        }
         tevent_req_error(req, ret);
         return;
     }
@@ -570,7 +540,7 @@
     subreq = sdap_get_groups_send(state, state->ev,
                                   state->ctx->be->domain,
                                   state->ctx->be->sysdb,
-                                  state->ctx->opts, state->ctx->gsh,
+                                  state->ctx->opts, sdap_id_op_handle(op),
                                   state->attrs, state->filter);
     if (!subreq) {
         tevent_req_error(req, ENOMEM);
--- sssd-1.1.0/src/providers/ldap/ldap_common.h.gss	2010-03-22 22:34:57.000000000 +0300
+++ sssd-1.1.0/src/providers/ldap/ldap_common.h	2010-03-29 11:33:01.076601064 +0400
@@ -33,17 +33,17 @@
 /* a fd the child process would log into */
 extern int ldap_child_debug_fd;
 
+struct sdap_id_connection;
+
 struct sdap_id_ctx {
     struct be_ctx *be;
     struct sdap_options *opts;
-    struct fo_service *fo_service;
     struct sdap_service *service;
 
-    /* what rootDSE returns */
-    struct sysdb_attrs *rootDSE;
-
-    /* global sdap handler */
-    struct sdap_handle *gsh;
+    /* list of all connections */
+    struct sdap_id_connection *connections;
+    /* cached connection */
+    struct sdap_id_connection *cached_connection;
 
     /* enumeration loop timer */
     struct timeval last_enum;
@@ -54,6 +54,44 @@
     char *max_group_timestamp;
 };
 
+struct sdap_id_op;
+typedef void (*sdap_id_connect_callback_t)(struct sdap_id_op* op, int, void*);
+
+/* LDAP ID backend extablished connection data */
+struct sdap_id_connection {
+    /* ID backend context */
+    struct sdap_id_ctx* ctx;
+    /* double linked list pointers */
+    struct sdap_id_connection *prev, *next;
+    /* sdap handle */
+    struct sdap_handle *sh;
+    /* what rootDSE returns */
+    struct sysdb_attrs *rootDSE;
+    /* connection request */
+    struct tevent_req *connect_req;
+    /* timer for connection expiration */
+    struct tevent_timer *expire_timer;
+    /* number of running connection notifies */
+    int notify_lock;
+    /* list of operations using connect */
+    struct sdap_id_op *ops;
+};
+
+/* LDAP ID backend hi-level operation handle with reconnect support */
+struct sdap_id_op {
+    /* ID backend context */
+    struct sdap_id_ctx* ctx;
+    /* double linked list pointers */
+    struct sdap_id_op *prev, *next;
+    /* current connection */
+    struct sdap_id_connection *connection;
+    /* number of reconnects for this operation */
+    int reconnect_retry_count;
+    /* connection callback */
+    sdap_id_connect_callback_t connect_callback;
+    void *connect_data;
+};
+
 struct sdap_auth_ctx {
     struct be_ctx *be;
     struct sdap_options *opts;
@@ -61,6 +99,21 @@
     struct sdap_service *service;
 };
 
+/* common */
+struct sdap_id_op* sdap_id_op_create(TALLOC_CTX *memctx, struct sdap_id_ctx *ctx);
+void sdap_id_op_connect(struct sdap_id_op*, sdap_id_connect_callback_t callback, void *data);
+int sdap_id_op_done(struct sdap_id_op*, int ret, int* dp_error);
+
+static inline struct sdap_handle* sdap_id_op_handle(struct sdap_id_op* op)
+{
+    return op->connection ? op->connection->sh : NULL;
+}
+
+static inline const struct sysdb_attrs* sdap_id_op_rootDSE(struct sdap_id_op* op)
+{
+    return op->connection ? op->connection->rootDSE : NULL;
+}
+
 /* id */
 void sdap_account_info_handler(struct be_req *breq);
 int sdap_id_setup_tasks(struct sdap_id_ctx *ctx);
@@ -89,13 +142,9 @@
 int ldap_id_enumerate_set_timer(struct sdap_id_ctx *ctx, struct timeval tv);
 int ldap_id_cleanup_set_timer(struct sdap_id_ctx *ctx, struct timeval tv);
 
-bool sdap_connected(struct sdap_id_ctx *ctx);
-void sdap_mark_offline(struct sdap_id_ctx *ctx);
-bool sdap_check_gssapi_reconnect(struct sdap_id_ctx *ctx);
-
 struct tevent_req *users_get_send(TALLOC_CTX *memctx,
                                   struct tevent_context *ev,
-                                  struct sdap_id_ctx *ctx,
+                                  struct sdap_id_op *op,
                                   const char *name,
                                   int filter_type,
                                   int attrs_type);
@@ -103,7 +152,7 @@
 
 struct tevent_req *groups_get_send(TALLOC_CTX *memctx,
                                    struct tevent_context *ev,
-                                   struct sdap_id_ctx *ctx,
+                                   struct sdap_id_op *op,
                                    const char *name,
                                    int filter_type,
                                    int attrs_type);
--- sssd-1.1.0/src/providers/ldap/ldap_common.c.gss	2010-03-22 22:34:57.000000000 +0300
+++ sssd-1.1.0/src/providers/ldap/ldap_common.c	2010-03-29 11:33:01.076601064 +0400
@@ -24,8 +24,9 @@
 
 #include "providers/ldap/ldap_common.h"
 #include "providers/fail_over.h"
+#include "providers/ldap/sdap_async.h"
 
-#include "util/sss_krb5.h"
+#include <tevent.h>
 
 /* a fd the child process would log into */
 int ldap_child_debug_fd = -1;
@@ -345,162 +346,486 @@
     return req->fn(req, dp_err, error, errstr);
 }
 
-bool sdap_connected(struct sdap_id_ctx *ctx)
+static int sdap_id_connection_destroy(struct sdap_id_connection*);
+static bool sdap_is_connection_expired(struct sdap_id_connection *connection, int timeout);
+static bool sdap_can_reuse_connection(struct sdap_id_connection *connection);
+
+static int sdap_id_connection_set_expire_timer(struct sdap_id_connection *connection);
+static void sdap_id_connection_expire_handler(struct tevent_context *ev,
+                                              struct tevent_timer *te,
+                                              struct timeval current_time,
+                                              void *pvt);
+
+static int sdap_id_op_destroy(struct sdap_id_op*);
+static void sdap_id_op_hook_connection(struct sdap_id_op *op, struct sdap_id_connection *connection);
+static void sdap_id_op_connect_done(struct tevent_req *subreq);
+
+static int sdap_id_connection_destroy(struct sdap_id_connection* connection)
 {
-    if (ctx->gsh) {
-        return ctx->gsh->connected;
+    struct sdap_id_op* op;
+    
+    /* we clean out list of ops to make sure that order of destruction does not matter */
+    while ((op = connection->ops) != NULL) {
+        op->connection = NULL;
+        
+        /* we are not calling connect callback as the whole context is going down,
+         * so there is no need to bother */
+        op->connect_callback = NULL;
+        op->connect_data = NULL;
+
+        DLIST_REMOVE(connection->ops, op);
     }
 
-    return false;
+    return 0;
 }
 
-void sdap_mark_offline(struct sdap_id_ctx *ctx)
+struct sdap_id_op* sdap_id_op_create(TALLOC_CTX *memctx, struct sdap_id_ctx *ctx)
 {
-    if (ctx->gsh) {
-        /* make sure we mark the connection as gone when we go offline so that
-         * we do not try to reuse a bad connection by mistale later */
-        talloc_zfree(ctx->gsh);
-    }
+    struct sdap_id_op* op = talloc_zero(memctx, struct sdap_id_op);
+    if (!op) {
+        return NULL;
+    }
+    
+    op->ctx = ctx;
+    
+    talloc_set_destructor(op, sdap_id_op_destroy);
+    return op;
+}
 
-    be_mark_offline(ctx->be);
+static int sdap_id_op_destroy(struct sdap_id_op* op)
+{
+    sdap_id_op_hook_connection(op, NULL);
+    return 0;
 }
 
-bool sdap_check_gssapi_reconnect(struct sdap_id_ctx *ctx)
+static void sdap_id_release_connection(struct sdap_id_connection *connection)
 {
-    int ret;
-    bool result = false;
-    const char *mech;
-    const char *realm;
-    char *ccname = NULL;
-    krb5_context context = NULL;
-    krb5_ccache ccache = NULL;
-    krb5_error_code krberr;
-    TALLOC_CTX *tmp_ctx = NULL;
-    krb5_creds mcred;
-    krb5_creds cred;
-    char *server_name = NULL;
-    char *client_princ_str = NULL;
-    char *full_princ = NULL;
-    krb5_principal client_principal = NULL;
-    krb5_principal server_principal = NULL;
-    char hostname[512];
-    int l_errno;
+    struct sdap_id_ctx *ctx;
+    if (!connection || connection->ops || connection->notify_lock) {
+        /* connection is in use */
+        return;
+    }
+    
+    ctx = connection->ctx;
+    if (connection == ctx->cached_connection) {
+        return;
+    }
+    
+    DEBUG(9, ("releasing unused connection\n"));
 
+    DLIST_REMOVE(ctx->connections, connection);
+    talloc_zfree(connection);
+}
 
-    mech = dp_opt_get_string(ctx->opts->basic, SDAP_SASL_MECH);
-    if (mech == NULL || strcasecmp(mech, "GSSAPI") != 0) {
-        return false;
+static void sdap_id_op_hook_connection(struct sdap_id_op *op, struct sdap_id_connection *connection)
+{
+    struct sdap_id_connection *current = op->connection;
+    if (connection == current) {
+        return;
     }
-
-    realm = dp_opt_get_string(ctx->opts->basic, SDAP_KRB5_REALM);
-    if (realm == NULL) {
-        DEBUG(3, ("Kerberos realm not available.\n"));
-        return false;
+    
+    if (current) {
+        DLIST_REMOVE(current->ops, op);
     }
 
-    tmp_ctx = talloc_new(NULL);
-    if (tmp_ctx == NULL) {
-        DEBUG(1, ("talloc_new failed.\n"));
-        return false;
+    op->connection = connection;
+    
+    if (connection) {
+        DLIST_ADD_END(connection->ops, op, struct sdap_id_op*);
+    }
+    
+    if (current) {
+        sdap_id_release_connection(current);
     }
+}
 
-    ccname = talloc_asprintf(tmp_ctx, "FILE:%s/ccache_%s", DB_PATH, realm);
-    if (ccname == NULL) {
-        DEBUG(1, ("talloc_asprintf failed.\n"));
-        goto done;
+static bool sdap_id_op_can_reconnect(struct sdap_id_op *op)
+{
+    /* we allow 2 retries for failover server configured:
+     *   - one for connection broken during request execution
+     *   - one for the following (probably failed) reconnect attempt */
+    int max_retries = 2 * be_fo_get_server_count(op->ctx->be, op->ctx->service->name) - 1;
+    if (max_retries < 1) {
+        max_retries = 1;
     }
+    
+    return op->reconnect_retry_count < max_retries;
+}
 
-    krberr = krb5_init_context(&context);
-    if (krberr) {
-        DEBUG(1, ("Failed to init kerberos context\n"));
-        goto done;
-    }
+void sdap_id_op_connect(struct sdap_id_op *op, sdap_id_connect_callback_t callback, void *data)
+{
+    int error = EOK;
+    struct sdap_id_ctx *ctx = op->ctx;
+    struct sdap_id_connection *connection;
+    struct tevent_req *subreq;
+    
+    /* Try to reuse own connection */
+    connection = op->connection;
+    if (connection) {
+        if (sdap_can_reuse_connection(connection)) {
+            DEBUG(9, ("reusing operation connection\n"));
+            callback(op, EOK, data);
+            return;
+        }
+        
+        if (ctx->cached_connection == connection) {
+            ctx->cached_connection = NULL;
+        }
+        
+        DEBUG(9, ("releasing operation connection\n"));
+        sdap_id_op_hook_connection(op, NULL);
+    }
+    
+    /* Try to reuse context cached connection */
+    connection = ctx->cached_connection;
+    if (connection) {
+        if (connection->connect_req) {
+            DEBUG(9, ("waiting for connection to complete\n"));
+            sdap_id_op_hook_connection(op, connection);
+            op->connect_callback = callback;
+            op->connect_data = data;
+            return;
+        }
+        
+        if (sdap_can_reuse_connection(connection)) {
+            DEBUG(9, ("reusing cached connection\n"));
+            sdap_id_op_hook_connection(op, connection);
+            callback(op, EOK, data);
+            return;
+        }
+        
+        DEBUG(9, ("releasing expired cached connection\n"));
+        ctx->cached_connection = NULL;
+        sdap_id_release_connection(connection);
+    }
+    
+    DEBUG(9, ("beginning to connect\n"));
+
+    connection = talloc_zero(ctx, struct sdap_id_connection);
+    if (!connection) {
+        error = ENOMEM;
+        goto fail;
+    }
+    
+    talloc_set_destructor(connection, sdap_id_connection_destroy);
+    
+    connection->ctx = ctx;
+    subreq = sdap_cli_connect_send(connection,ctx->be->ev,
+                                   ctx->opts, ctx->be,
+                                   ctx->service, &connection->rootDSE);
+    if (!subreq) {
+        error = ENOMEM;
+        goto fail;
+    }
+
+    tevent_req_set_callback(subreq, sdap_id_op_connect_done, connection);
+    connection->connect_req = subreq;
+    
+    DLIST_ADD(ctx->connections, connection);
+    ctx->cached_connection = connection;
+    
+    sdap_id_op_hook_connection(op, connection);
+    op->connect_callback = callback;
+    op->connect_data = data;
+    return;
+
+fail:
+    if (connection) {
+        sdap_id_release_connection(connection);
+    }
+    
+    callback(op, error, data);
+    return;    
+}
 
-    krberr = krb5_cc_resolve(context, ccname, &ccache);
-    if (krberr != 0) {
-        DEBUG(1, ("krb5_cc_resolve failed.\n"));
-        goto done;
+static void sdap_id_op_call_connect_callback(struct sdap_id_op* op, int retval)
+{
+    sdap_id_connect_callback_t callback = op->connect_callback;
+    void* data = op->connect_data;
+    
+    if (!callback) {
+        return;
     }
+    
+    op->connect_callback = NULL;
+    op->connect_data = NULL;
+    
+    callback(op, retval, data);
+}
 
-    server_name = talloc_asprintf(tmp_ctx, "krbtgt/%s@%s", realm, realm);
-    if (server_name == NULL) {
-        DEBUG(1, ("talloc_asprintf failed.\n"));
-        goto done;
-    }
+static void sdap_id_op_connect_done(struct tevent_req *subreq)
+{
+    struct sdap_id_connection *connection = tevent_req_callback_data(subreq,
+                                                                     struct sdap_id_connection);
+    struct sdap_id_ctx *ctx = connection->ctx;
+    bool can_retry = false;
+    int ret;
 
-    krberr = krb5_parse_name(context, server_name, &server_principal);
-    if (krberr != 0) {
-        DEBUG(1, ("krb5_parse_name failed.\n"));
-        goto done;
+    ret = sdap_cli_connect_recv(subreq, connection, &can_retry, &connection->sh, &connection->rootDSE);
+    connection->connect_req = NULL;
+    talloc_zfree(subreq);
+    
+    connection->notify_lock++;
+    
+    if (ret == ENOTSUP) {
+        DEBUG(0, ("Authentication mechanism not Supported by server\n"));
+    }
+    
+    if (ret == EOK && (!connection->sh || !connection->sh->connected)) {
+        DEBUG(0, ("sdap_cli_connect_recv returned bogus connection\n"));
+        ret = EFAULT;
+    }
+    
+    if (ret != EOK && !can_retry) {
+        /* be is going offline as there is no more servers to try */
+        DEBUG(1, ("Failed to connect, going offline (%d [%s])\n",
+                  ret, strerror(ret)));
+        be_mark_offline(connection->ctx->be);
+    }
+    
+    if (ret == EOK) {
+        ret = sdap_id_connection_set_expire_timer(connection);
+    }
+    
+    if (can_retry) {
+        switch (ret) {
+            case EOK:
+            case ENOTSUP:
+            case EACCES:
+            case EIO:
+            case EFAULT:
+            case ETIMEDOUT:
+                break;
+                
+            default:
+                /* do not attempt to retry on errors like ENOMEM */
+                can_retry = false;
+                break;
+        }
     }
+    
+    int notify_count = 0;
+    
+    /* Notify about connection */
+    for(;;) {
+        struct sdap_id_op* op;
 
-    client_princ_str = dp_opt_get_string(ctx->opts->basic, SDAP_SASL_AUTHID);
-    if (client_princ_str) {
-        if (!strchr(client_princ_str, '@')) {
-            full_princ = talloc_asprintf(tmp_ctx, "%s@%s", client_princ_str,
-                                         realm);
-        } else {
-            full_princ = talloc_strdup(tmp_ctx, client_princ_str);
+        if (ret == EOK && !connection->sh->connected) {
+            DEBUG(9, ("connection was broken after %d notifies\n", notify_count));
         }
-    } else {
-        ret = gethostname(hostname, sizeof(hostname)-1);
-        if (ret == -1) {
-            l_errno = errno;
-            DEBUG(1, ("gethostname failed [%d][%s].\n", l_errno,
-                                                        strerror(l_errno)));
-            goto done;
+
+        DLIST_FOR_EACH(op, connection->ops) {
+            if (op->connect_callback) {
+                break;
+            }
+        }
+        
+        if (!op) {
+            break;
+        }
+        
+        /* another connection to notify */
+        notify_count++;
+        
+        if (ret != EOK || !connection->sh->connected) {
+            /* failed to connect or connection got broken during notify */
+            bool retry = false;
+
+            /* drop connection from cache now */
+            if (ctx->cached_connection == connection) {
+                ctx->cached_connection = NULL;
+            }
+
+            if (can_retry) {
+                /* determining whether retry is possible */
+                if (be_is_offline(ctx->be)) {
+                    /* be is offline, no retry possible */
+                    if (ret == EOK) {
+                        DEBUG(9, ("skipping automatic retry on op #%d as be is offline\n", notify_count));
+                        ret = EIO;
+                    }
+                    
+                    can_retry = false;
+                } else {
+                    if (ret == EOK) {
+                        DEBUG(9, ("attempting automatic retry on op #%d\n", notify_count));
+                        retry = true;
+                    } else if (sdap_id_op_can_reconnect(op)) {
+                        DEBUG(9, ("attempting failover retry on op #%d\n", notify_count));
+                        op->reconnect_retry_count++;
+                        retry = true;
+                    }
+                }
+            }
+            
+            if (retry) {
+                sdap_id_connect_callback_t callback = op->connect_callback;
+                void* data = op->connect_data;
+                
+                op->connect_callback = NULL;
+                op->connect_data = NULL;
+
+                sdap_id_op_hook_connection(op, NULL);
+                sdap_id_op_connect(op, callback, data);
+                continue;
+            }
         }
-        hostname[sizeof(hostname)-1] = '\0';
 
-        full_princ = talloc_asprintf(tmp_ctx, "host/%s@%s", hostname, realm);
-    }
-    if (!full_princ) {
-        DEBUG(1, ("Client principal not available.\n"));
-        goto done;
+        if (ret == EOK) {         
+            DEBUG(9, ("notify connected to op #%d\n", notify_count));
+        } else {
+            DEBUG(9, ("notify error to op #%d: %d [%s]\n", notify_count, ret, strerror(ret)));
+        }
+        
+        sdap_id_op_call_connect_callback(op, ret);
     }
-    DEBUG(7, ("Client principal name is: [%s]\n", full_princ));
-    krberr = krb5_parse_name(context, full_princ, &client_principal);
-    if (krberr != 0) {
-        DEBUG(1, ("krb5_parse_name failed.\n"));
-        goto done;
+    
+    /* all connections notified */
+    if (connection->notify_lock > 0) {
+        connection->notify_lock--;
+    }
+        
+    if (ret == EOK && connection->sh->connected && !be_is_offline(ctx->be)) {
+        DEBUG(9, ("caching successful connection after %d notifies\n", notify_count));
+        ctx->cached_connection = connection;
+    } else {
+        if (ctx->cached_connection == connection) {
+            ctx->cached_connection = NULL;
+        }
+        
+        sdap_id_release_connection(connection);
     }
+}
+
+static int sdap_id_connection_set_expire_timer(struct sdap_id_connection *connection)
+{
+    int timeout;
+    struct timeval tv;
 
-    memset(&mcred, 0, sizeof(mcred));
-    memset(&cred, 0, sizeof(mcred));
-    mcred.client = client_principal;
-    mcred.server = server_principal;
+    memset(&tv, 0, sizeof(tv));
 
-    krberr = krb5_cc_retrieve_cred(context, ccache, 0, &mcred, &cred);
-    if (krberr != 0) {
-        DEBUG(1, ("krb5_cc_retrieve_cred failed.\n"));
-        goto done;
+    tv.tv_sec = connection->sh->expire_time;
+    if (tv.tv_sec <= 0) {
+        return EOK;
+    }
+    
+    timeout = dp_opt_get_int(connection->ctx->opts->basic, SDAP_OPT_TIMEOUT);
+    if (timeout > 0) {
+        tv.tv_sec -= timeout;
+    }
+    
+    if (tv.tv_sec <= time(NULL)) {
+        return EOK;
+    }
+    
+    talloc_zfree(connection->expire_timer);
+
+    connection->expire_timer = tevent_add_timer(connection->ctx->be->ev,
+                                                connection,
+                                                tv,
+                                                sdap_id_connection_expire_handler,
+                                                connection);
+    if (!connection->expire_timer) {
+        return ENOMEM;
     }
+    
+    return EOK;
+}
+
+static void sdap_id_connection_expire_handler(struct tevent_context *ev,
+                                              struct tevent_timer *te,
+                                              struct timeval current_time,
+                                              void *pvt)
+{
+    struct sdap_id_connection *connection = talloc_get_type(pvt,
+                                                            struct sdap_id_connection);
+    struct sdap_id_ctx* ctx = connection->ctx;
+
+    DEBUG(3, ("connection is about to expire, releasing it\n"));
 
-    DEBUG(7, ("TGT end time [%d].\n", cred.times.endtime));
+    if (ctx->cached_connection == connection) {
+        ctx->cached_connection = NULL;
 
-    if (cred.times.endtime <= time(NULL)) {
-        DEBUG(3, ("TGT is expired.\n"));
-        result = true;
+        sdap_id_release_connection(connection);
     }
-    krb5_free_cred_contents(context, &cred);
+}
 
-done:
-    if (client_principal != NULL) {
-        krb5_free_principal(context, client_principal);
+static bool sdap_is_connection_expired(struct sdap_id_connection *connection, int timeout)
+{
+    time_t expire_time;
+    if (!connection || !connection->sh || !connection->sh->connected) {
+        return true;
+    }
+    
+    expire_time = connection->sh->expire_time;
+    if (expire_time != 0 && expire_time < time( NULL ) + timeout ) {
+        return true;
     }
-    if (server_principal != NULL) {
-        krb5_free_principal(context, server_principal);
+    
+    return false;
+}
+
+static bool sdap_can_reuse_connection(struct sdap_id_connection *connection)
+{
+    int timeout;
+
+    if (!connection || !connection->sh || !connection->sh->connected) {
+        return false;
     }
-    if (ccache != NULL) {
-        if (result) {
-            krb5_cc_destroy(context, ccache);
+
+    timeout = dp_opt_get_int(connection->ctx->opts->basic, SDAP_OPT_TIMEOUT);
+    return !sdap_is_connection_expired(connection, timeout);
+}
+
+int sdap_id_op_done(struct sdap_id_op *op, int retval, int *dp_err_out)
+{
+    bool communication_error;
+    switch (retval) {
+        case EIO:
+            /* this currently the only possible communication error after connection is established */
+            communication_error = true;
+            break;
+            
+        default:
+            communication_error = false;
+            break;
+    }
+    
+    if (communication_error && op->connection != 0 && op->connection == op->ctx->cached_connection) {
+        /* do not reuse failed connection */
+        op->ctx->cached_connection = NULL;
+    }
+    
+    int dp_err;
+    if (retval == EOK) {
+        dp_err = DP_ERR_OK;
+    } else if (be_is_offline(op->ctx->be)) {
+        /* if backend is already offline, just report offline, do not duplicate errors */
+        dp_err = DP_ERR_OFFLINE;
+        retval = EAGAIN;
+    } else if (communication_error) {
+        /* communication error, can try to reconnect */
+
+        if (!sdap_id_op_can_reconnect(op)) {
+            dp_err = DP_ERR_FATAL;
         } else {
-            krb5_cc_close(context, ccache);
+            dp_err = DP_ERR_OK;
+            retval = EAGAIN;
         }
+    } else {
+        dp_err = DP_ERR_FATAL;
     }
-    if (context != NULL) krb5_free_context(context);
-    talloc_free(tmp_ctx);
-    return result;
+
+    if (dp_err == DP_ERR_OK && retval != EOK) {
+        /* reconnect retry */
+        op->reconnect_retry_count++;
+    } else {
+        /* end of request */
+        op->reconnect_retry_count = 0;
+    }
+
+    *dp_err_out = dp_err;
+    return retval;
 }
 
 int sdap_id_setup_tasks(struct sdap_id_ctx *ctx)
--- sssd-1.1.0/src/providers/ldap/sdap.h.gss	2010-03-22 22:34:57.000000000 +0300
+++ sssd-1.1.0/src/providers/ldap/sdap.h	2010-03-29 11:33:01.077604541 +0400
@@ -70,6 +70,8 @@
 struct sdap_handle {
     LDAP *ldap;
     bool connected;
+    /* Authentication ticket expiration time (if any) */
+    time_t expire_time;
 
 #ifdef HAVE_LDAP_CONNCB
     struct ldap_conncb *conncb;
@@ -225,6 +227,8 @@
     struct ldb_dn *groups_base;
 };
 
+void sdap_disconnect(struct sdap_handle *sh);
+
 int sdap_get_map(TALLOC_CTX *memctx,
                  struct confdb_ctx *cdb,
                  const char *conf_path,
--- sssd-1.1.0/src/providers/ldap/sdap_child_helpers.c.gss	2010-03-22 22:34:57.000000000 +0300
+++ sssd-1.1.0/src/providers/ldap/sdap_child_helpers.c	2010-03-29 11:33:01.077604541 +0400
@@ -30,6 +30,7 @@
 
 #include "util/util.h"
 #include "providers/ldap/ldap_common.h"
+#include "providers/ldap/sdap_async_private.h"
 #include "providers/child_common.h"
 
 #ifndef SSSD_LIBEXEC_PATH
@@ -194,12 +195,15 @@
 
 static int parse_child_response(TALLOC_CTX *mem_ctx,
                                 uint8_t *buf, ssize_t size,
-                                int  *result, char **ccache)
+                                int  *result, char **ccache,
+                                time_t *expire_time_out)
 {
     size_t p = 0;
     uint32_t len;
     uint32_t res;
-    char *ccn;
+    char *ccn = 0;
+    time_t expire_time;
+    int retval = EOK;
 
     /* operation result code */
     SAFEALIGN_COPY_UINT32_CHECK(&res, buf + p, size, &p);
@@ -207,19 +211,34 @@
     /* ccache name size */
     SAFEALIGN_COPY_UINT32_CHECK(&len, buf + p, size, &p);
 
-    if ((p + len ) > size) return EINVAL;
-
+    if ((p + len ) > size)
+        return EINVAL;
+        
     ccn = talloc_size(mem_ctx, sizeof(char) * (len + 1));
     if (ccn == NULL) {
         DEBUG(1, ("talloc_size failed.\n"));
         return ENOMEM;
     }
-    memcpy(ccn, buf+p, sizeof(char) * (len + 1));
+    safealign_memcpy(ccn, buf+p, sizeof(char) * len, &p);
     ccn[len] = '\0';
+    
+    if (p + sizeof(time_t) > size) {
+        retval = EINVAL;
+        goto cleanup;
+    }
+    safealign_memcpy(&expire_time, buf+p, sizeof(time_t), &p);
 
     *result = res;
     *ccache = ccn;
-    return EOK;
+    *expire_time_out = expire_time;
+    return retval;
+    
+cleanup:
+    if (ccn != 0) {
+        talloc_free(ccn);
+    }
+    
+    return retval;
 }
 
 /* ==The-public-async-interface============================================*/
@@ -352,25 +371,28 @@
 int sdap_get_tgt_recv(struct tevent_req *req,
                            TALLOC_CTX *mem_ctx,
                            int  *result,
-                           char **ccname)
+                           char **ccname,
+                           time_t *expire_time_out)
 {
     struct sdap_get_tgt_state *state = tevent_req_data(req,
                                              struct sdap_get_tgt_state);
     char *ccn;
+    time_t expire_time;
     int  res;
     int ret;
 
     TEVENT_REQ_RETURN_ON_ERROR(req);
 
-    ret = parse_child_response(mem_ctx, state->buf, state->len, &res, &ccn);
+    ret = parse_child_response(mem_ctx, state->buf, state->len, &res, &ccn, &expire_time);
     if (ret != EOK) {
         DEBUG(1, ("Cannot parse child response: [%d][%s]\n", ret, strerror(ret)));
         return ret;
     }
 
-    DEBUG(6, ("Child responded: %d [%s]\n", res, ccn));
+    DEBUG(6, ("Child responded: %d [%s], expired on [%ld]\n", res, ccn, (long)expire_time));
     *result = res;
     *ccname = ccn;
+    *expire_time_out = expire_time;
     return EOK;
 }
 
--- sssd-1.1.0/src/providers/fail_over.c.gss	2010-03-22 22:34:57.000000000 +0300
+++ sssd-1.1.0/src/providers/fail_over.c	2010-03-29 11:33:01.078601032 +0400
@@ -341,6 +341,19 @@
 }
 
 int
+fo_get_server_count(struct fo_service *service)
+{
+    struct fo_server *server;
+    int count = 0;
+
+    DLIST_FOR_EACH(server, service->server_list) {
+        count++;
+    }
+
+    return count;
+}
+
+int
 fo_add_server(struct fo_service *service, const char *name, int port,
               void *user_data)
 {
--- sssd-1.1.0/src/providers/data_provider_fo.c.gss	2010-03-29 11:47:40.281725460 +0400
+++ sssd-1.1.0/src/providers/data_provider_fo.c	2010-03-29 11:48:00.639600499 +0400
@@ -226,6 +226,28 @@
     return EOK;
 }
 
+int be_fo_get_server_count(struct be_ctx *ctx, const char *service_name)
+{
+    struct be_svc_data* svc_data;
+    struct fo_service *svc;
+    
+    if (!ctx->be_fo) {
+        return 0;
+    }
+
+    DLIST_FOR_EACH(svc_data, ctx->be_fo->svcs) {
+        if (strcmp(svc_data->name, service_name) == 0) {
+            break;
+        }
+    }
+    
+    if (!svc_data) {
+        return 0;
+    }
+
+    return fo_get_server_count(svc_data->fo_service);
+}
+
 int be_fo_add_server(struct be_ctx *ctx, const char *service_name,
                      const char *server, int port, void *user_data)
 {
--- sssd-1.1.0/src/providers/ipa/ipa_access.c.gss	2010-03-22 22:34:57.000000000 +0300
+++ sssd-1.1.0/src/providers/ipa/ipa_access.c	2010-03-29 11:33:01.078601032 +0400
@@ -315,6 +315,7 @@
 struct hbac_get_host_info_state {
     struct tevent_context *ev;
     struct sdap_id_ctx *sdap_ctx;
+    struct sdap_id_op *sdap_op;
     struct sysdb_ctx *sysdb;
     struct sysdb_handle *handle;
     bool offline;
@@ -329,7 +330,7 @@
     struct hbac_host_info **hbac_host_info;
 };
 
-static void hbac_get_host_info_connect_done(struct tevent_req *subreq);
+static void hbac_get_host_info_connect_done(struct sdap_id_op* op, int ret, void* pvt);
 static void hbac_get_host_memberof_done(struct tevent_req *subreq);
 static void hbac_get_host_info_sysdb_transaction_started(struct tevent_req *subreq);
 static void hbac_get_host_info_store_prepare(struct tevent_req *req);
@@ -430,41 +431,18 @@
 
         return req;
     }
-
-    if (sdap_ctx->gsh == NULL || ! sdap_ctx->gsh->connected) {
-        if (sdap_ctx->gsh != NULL) {
-            talloc_zfree(sdap_ctx->gsh);
-        }
-
-        subreq = sdap_cli_connect_send(state, ev, sdap_ctx->opts,
-                                       sdap_ctx->be, sdap_ctx->service, NULL);
-        if (!subreq) {
-            DEBUG(1, ("sdap_cli_connect_send failed.\n"));
-            ret = ENOMEM;
-            goto fail;
-        }
-
-        tevent_req_set_callback(subreq, hbac_get_host_info_connect_done, req);
-
-        return req;
-    }
-
-    subreq = sdap_get_generic_send(state, state->ev,
-                                   state->sdap_ctx->opts,
-                                   state->sdap_ctx->gsh,
-                                   state->host_search_base,
-                                   LDAP_SCOPE_SUB,
-                                   state->host_filter,
-                                   state->host_attrs,
-                                   NULL, 0);
-
-    if (subreq == NULL) {
-        DEBUG(1, ("sdap_get_generic_send failed.\n"));
+    
+    state->sdap_op = sdap_id_op_create(state, sdap_ctx);
+    if (!state->sdap_op) {
+        DEBUG(1, ("sdap_id_op_create failed.\n"));
         ret = ENOMEM;
         goto fail;
     }
-
-    tevent_req_set_callback(subreq, hbac_get_host_memberof_done, req);
+    
+    sdap_id_op_connect(state->sdap_op, hbac_get_host_info_connect_done, req);
+    if (!tevent_req_is_in_progress(req)) {
+        tevent_req_post(req, ev);
+    }
 
     return req;
 
@@ -474,17 +452,14 @@
     return req;
 }
 
-static void hbac_get_host_info_connect_done(struct tevent_req *subreq)
+static void hbac_get_host_info_connect_done(struct sdap_id_op* op, int ret, void* pvt)
 {
-    struct tevent_req *req = tevent_req_callback_data(subreq,
-                                                      struct tevent_req);
+    struct tevent_req *req = talloc_get_type(pvt,
+                                             struct tevent_req);
     struct hbac_get_host_info_state *state = tevent_req_data(req,
                                                struct hbac_get_host_info_state);
-    int ret;
+    struct tevent_req *subreq;
 
-    ret = sdap_cli_connect_recv(subreq, state->sdap_ctx, &state->sdap_ctx->gsh,
-                                NULL);
-    talloc_zfree(subreq);
     if (ret) {
         tevent_req_error(req, ret);
         return;
@@ -492,7 +467,7 @@
 
     subreq = sdap_get_generic_send(state, state->ev,
                                    state->sdap_ctx->opts,
-                                   state->sdap_ctx->gsh,
+                                   sdap_id_op_handle(op),
                                    state->host_search_base,
                                    LDAP_SCOPE_SUB,
                                    state->host_filter,
@@ -804,6 +779,7 @@
 struct hbac_get_rules_state {
     struct tevent_context *ev;
     struct sdap_id_ctx *sdap_ctx;
+    struct sdap_id_op *sdap_op;
     struct sysdb_ctx *sysdb;
     struct sysdb_handle *handle;
     bool offline;
@@ -820,7 +796,7 @@
     int current_item;
 };
 
-static void hbac_get_rules_connect_done(struct tevent_req *subreq);
+static void hbac_get_rules_connect_done(struct sdap_id_op* op, int ret, void* pvt);
 static void hbac_rule_get_done(struct tevent_req *subreq);
 static void hbac_rule_sysdb_transaction_started(struct tevent_req *subreq);
 static void hbac_rule_sysdb_delete_done(struct tevent_req *subreq);
@@ -939,41 +915,18 @@
 
         return req;
     }
-
-    if (sdap_ctx->gsh == NULL || ! sdap_ctx->gsh->connected) {
-        if (sdap_ctx->gsh != NULL) {
-            talloc_zfree(sdap_ctx->gsh);
-        }
-
-        subreq = sdap_cli_connect_send(state, ev, sdap_ctx->opts,
-                                       sdap_ctx->be, sdap_ctx->service, NULL);
-        if (!subreq) {
-            DEBUG(1, ("sdap_cli_connect_send failed.\n"));
-            ret = ENOMEM;
-            goto fail;
-        }
-
-        tevent_req_set_callback(subreq, hbac_get_rules_connect_done, req);
-
-        return req;
-    }
-
-    subreq = sdap_get_generic_send(state, state->ev,
-                                   state->sdap_ctx->opts,
-                                   state->sdap_ctx->gsh,
-                                   state->hbac_search_base,
-                                   LDAP_SCOPE_SUB,
-                                   state->hbac_filter,
-                                   state->hbac_attrs,
-                                   NULL, 0);
-
-    if (subreq == NULL) {
-        DEBUG(1, ("sdap_get_generic_send failed.\n"));
+    
+    state->sdap_op = sdap_id_op_create(state, sdap_ctx);
+    if (!state->sdap_op) {
+        DEBUG(1, ("sdap_id_op_create failed.\n"));
         ret = ENOMEM;
         goto fail;
     }
-
-    tevent_req_set_callback(subreq, hbac_rule_get_done, req);
+    
+    sdap_id_op_connect(state->sdap_op, hbac_get_rules_connect_done, req);
+    if (!tevent_req_is_in_progress(req)) {
+        tevent_req_post(req, ev);
+    }
 
     return req;
 
@@ -983,17 +936,14 @@
     return req;
 }
 
-static void hbac_get_rules_connect_done(struct tevent_req *subreq)
+static void hbac_get_rules_connect_done(struct sdap_id_op* op, int ret, void* pvt)
 {
-    struct tevent_req *req = tevent_req_callback_data(subreq,
-                                                      struct tevent_req);
+    struct tevent_req *req = talloc_get_type(pvt,
+                                             struct tevent_req);
     struct hbac_get_rules_state *state = tevent_req_data(req,
                                                      struct hbac_get_rules_state);
-    int ret;
+    struct tevent_req *subreq;
 
-    ret = sdap_cli_connect_recv(subreq, state->sdap_ctx, &state->sdap_ctx->gsh,
-                                NULL);
-    talloc_zfree(subreq);
     if (ret) {
         tevent_req_error(req, ret);
         return;
@@ -1001,7 +951,7 @@
 
     subreq = sdap_get_generic_send(state, state->ev,
                                    state->sdap_ctx->opts,
-                                   state->sdap_ctx->gsh,
+                                   sdap_id_op_handle(op),
                                    state->hbac_search_base,
                                    LDAP_SCOPE_SUB,
                                    state->hbac_filter,
--- sssd-1.1.0/src/providers/dp_backend.h.gss	2010-03-22 22:34:57.000000000 +0300
+++ sssd-1.1.0/src/providers/dp_backend.h	2010-03-29 11:33:01.079601156 +0400
@@ -130,6 +130,7 @@
 int be_fo_service_add_callback(TALLOC_CTX *memctx,
                                struct be_ctx *ctx, const char *service_name,
                                be_svc_callback_fn_t *fn, void *private_data);
+int be_fo_get_server_count(struct be_ctx *ctx, const char *service_name);
 int be_fo_add_server(struct be_ctx *ctx, const char *service_name,
                      const char *server, int port, void *user_data);
 
