[SSSD] [PATCH] Try all KDCs when getting TGT for LDAP (a sssd-1.5 backport)

Jakub Hrozek jhrozek at redhat.com
Mon Jun 4 12:30:20 UTC 2012


Attached are patches that backport the fix for #1324 to the sssd-1.5
branch.

Patches 1-4 are a dependency - I needed to backport the feature to only
resolve a single service once (upstream #1214). The fix for #1324 depends
on it both contextually and also users who are hit by #1324 will most
likely be hit by #1214, too.
-------------- next part --------------
>From b320a54908ddbafbada38e26cc6edd3b37d34eba Mon Sep 17 00:00:00 2001
From: Jakub Hrozek <jhrozek at redhat.com>
Date: Mon, 4 Jun 2012 11:07:19 +0200
Subject: [PATCH 1/5] Rename fo_get_server_name to fo_get_server_str_name

---
 src/providers/data_provider_fo.c |    6 +++---
 src/providers/fail_over.c        |    2 +-
 src/providers/fail_over.h        |    2 +-
 src/providers/ipa/ipa_common.c   |    4 ++--
 src/providers/krb5/krb5_common.c |    2 +-
 src/providers/ldap/ldap_common.c |    4 ++--
 src/tests/fail_over-tests.c      |    2 +-
 7 files changed, 11 insertions(+), 11 deletions(-)

diff --git a/src/providers/data_provider_fo.c b/src/providers/data_provider_fo.c
index cb14012c17e13172aed7635e04cac692b1136184..d7a4115229a90e400dcb1f00e3288e0e8273b71c 100644
--- a/src/providers/data_provider_fo.c
+++ b/src/providers/data_provider_fo.c
@@ -426,7 +426,7 @@ static void be_resolve_server_done(struct tevent_req *subreq)
             return;
         }
         DEBUG(6, ("Couldn't resolve server (%s), resolver returned (%d)\n",
-                  fo_get_server_name(state->srv), ret));
+                  fo_get_server_str_name(state->srv), ret));
 
         state->attempts++;
         if (state->attempts >= 10) {
@@ -458,7 +458,7 @@ static void be_resolve_server_done(struct tevent_req *subreq)
         srvaddr = fo_get_server_hostent(state->srv);
         if (!srvaddr) {
             DEBUG(3, ("FATAL: No hostent available for server (%s)\n",
-                      fo_get_server_name(state->srv)));
+                      fo_get_server_str_name(state->srv)));
             tevent_req_error(req, EFAULT);
             return;
         }
@@ -467,7 +467,7 @@ static void be_resolve_server_done(struct tevent_req *subreq)
                   ipaddr, 128);
 
         DEBUG(4, ("Found address for server %s: [%s] TTL %d\n",
-                  fo_get_server_name(state->srv), ipaddr,
+                  fo_get_server_str_name(state->srv), ipaddr,
                   srvaddr->addr_list[0]->ttl));
     }
 
diff --git a/src/providers/fail_over.c b/src/providers/fail_over.c
index 2a96317722cda93bc795a4c6286fa4d24ecfbe95..2d4703fa00b2a2d1034ef300691760a60c2ee864 100644
--- a/src/providers/fail_over.c
+++ b/src/providers/fail_over.c
@@ -1354,7 +1354,7 @@ fo_get_server_port(struct fo_server *server)
     return server->port;
 }
 
-const char *fo_get_server_name(struct fo_server *server)
+const char *fo_get_server_str_name(struct fo_server *server)
 {
     if (!server->common) {
         if (fo_is_srv_lookup(server)) {
diff --git a/src/providers/fail_over.h b/src/providers/fail_over.h
index e5d6c525f6a69f92d0583a795adcbe5e1ab252f3..cb9e54e989f6529f68cc4cc991cafa6f3ed9b07d 100644
--- a/src/providers/fail_over.h
+++ b/src/providers/fail_over.h
@@ -167,7 +167,7 @@ void *fo_get_server_user_data(struct fo_server *server);
 
 int fo_get_server_port(struct fo_server *server);
 
-const char *fo_get_server_name(struct fo_server *server);
+const char *fo_get_server_str_name(struct fo_server *server);
 
 struct resolv_hostent *fo_get_server_hostent(struct fo_server *server);
 
diff --git a/src/providers/ipa/ipa_common.c b/src/providers/ipa/ipa_common.c
index 084400f227477c8fd10eef35cd74d4071c03b3dc..a95b7811f539c2eae47d9a271387a1686b557753 100644
--- a/src/providers/ipa/ipa_common.c
+++ b/src/providers/ipa/ipa_common.c
@@ -583,7 +583,7 @@ static void ipa_resolve_callback(void *private_data, struct fo_server *server)
     srvaddr = fo_get_server_hostent(server);
     if (!srvaddr) {
         DEBUG(1, ("FATAL: No hostent available for server (%s)\n",
-                  fo_get_server_name(server)));
+                  fo_get_server_str_name(server)));
         talloc_free(tmp_ctx);
         return;
     }
@@ -611,7 +611,7 @@ static void ipa_resolve_callback(void *private_data, struct fo_server *server)
         return;
     }
 
-    new_uri = talloc_asprintf(service, "ldap://%s", fo_get_server_name(server));
+    new_uri = talloc_asprintf(service, "ldap://%s", fo_get_server_str_name(server));
     if (!new_uri) {
         DEBUG(2, ("Failed to copy URI ...\n"));
         talloc_free(tmp_ctx);
diff --git a/src/providers/krb5/krb5_common.c b/src/providers/krb5/krb5_common.c
index 6e190d0c589d759b39890a3dc7e035efe384156f..5fd164ed84fb88aaa472997fe422cbf3dede1a6a 100644
--- a/src/providers/krb5/krb5_common.c
+++ b/src/providers/krb5/krb5_common.c
@@ -380,7 +380,7 @@ static void krb5_resolve_callback(void *private_data, struct fo_server *server)
     srvaddr = fo_get_server_hostent(server);
     if (!srvaddr) {
         DEBUG(1, ("FATAL: No hostent available for server (%s)\n",
-                  fo_get_server_name(server)));
+                  fo_get_server_str_name(server)));
         return;
     }
 
diff --git a/src/providers/ldap/ldap_common.c b/src/providers/ldap/ldap_common.c
index 23f612a5a606abc8631e4822493e16ed4a225d24..2ae262970ebf6248b38ea087df2bfbdbe85b0994 100644
--- a/src/providers/ldap/ldap_common.c
+++ b/src/providers/ldap/ldap_common.c
@@ -552,7 +552,7 @@ static void sdap_uri_callback(void *private_data, struct fo_server *server)
     srvaddr = fo_get_server_hostent(server);
     if (!srvaddr) {
         DEBUG(1, ("FATAL: No hostent available for server (%s)\n",
-                  fo_get_server_name(server)));
+                  fo_get_server_str_name(server)));
         talloc_free(tmp_ctx);
         return;
     }
@@ -571,7 +571,7 @@ static void sdap_uri_callback(void *private_data, struct fo_server *server)
             tmp = SSS_LDAP_SRV_NAME;
         }
         new_uri = talloc_asprintf(service, "%s://%s:%d",
-                                  tmp, fo_get_server_name(server),
+                                  tmp, fo_get_server_str_name(server),
                                   fo_get_server_port(server));
     } else {
         new_uri = talloc_strdup(service, tmp);
diff --git a/src/tests/fail_over-tests.c b/src/tests/fail_over-tests.c
index efd8756d8a439d6f9817a6779b98ea62bfd0dc3a..d8a6d510b0a00d309b51c4afee3b88f63fe9f615 100644
--- a/src/tests/fail_over-tests.c
+++ b/src/tests/fail_over-tests.c
@@ -170,7 +170,7 @@ test_resolve_service_callback(struct tevent_req *req)
     if (task->new_server_status >= 0)
         fo_set_server_status(server, task->new_server_status);
 
-    if (strcmp(fo_get_server_name(server), "unknown name")) {
+    if (strcmp(fo_get_server_str_name(server), "unknown name")) {
         he = fo_get_server_hostent(server);
         fail_if(he == NULL, "%s: fo_get_server_hostent() returned NULL");
         for (i = 0; he->addr_list[i]; i++) {
-- 
1.7.10.2

-------------- next part --------------
>From d09d44355ea95e229388db52c784fa1752d214b7 Mon Sep 17 00:00:00 2001
From: Jakub Hrozek <jhrozek at redhat.com>
Date: Sat, 16 Jul 2011 18:00:40 +0200
Subject: [PATCH 2/5] fo_get_server_name() getter for a server name

Allows to be more concise in tests and more defensive in resolve
callbacks
---
 src/providers/data_provider_fo.c |    2 +-
 src/providers/fail_over.c        |    9 +++++++++
 src/providers/fail_over.h        |    2 ++
 src/providers/ipa/ipa_common.c   |   10 +++++++++-
 src/providers/ldap/ldap_common.c |   11 ++++++++++-
 src/tests/fail_over-tests.c      |    2 +-
 6 files changed, 32 insertions(+), 4 deletions(-)

diff --git a/src/providers/data_provider_fo.c b/src/providers/data_provider_fo.c
index d7a4115229a90e400dcb1f00e3288e0e8273b71c..c3f8c3ba72a8696d6bffef08f0b88a3616843bd0 100644
--- a/src/providers/data_provider_fo.c
+++ b/src/providers/data_provider_fo.c
@@ -452,7 +452,7 @@ static void be_resolve_server_done(struct tevent_req *subreq)
 
     /* all fine we got the server */
 
-    if (debug_level >= 4) {
+    if (debug_level >= 4 && fo_get_server_name(state->srv)) {
         struct resolv_hostent *srvaddr;
         char ipaddr[128];
         srvaddr = fo_get_server_hostent(state->srv);
diff --git a/src/providers/fail_over.c b/src/providers/fail_over.c
index 2d4703fa00b2a2d1034ef300691760a60c2ee864..3c46d8dd233b55306b64a84a6a16335b0c384d1e 100644
--- a/src/providers/fail_over.c
+++ b/src/providers/fail_over.c
@@ -1354,6 +1354,15 @@ fo_get_server_port(struct fo_server *server)
     return server->port;
 }
 
+const char *
+fo_get_server_name(struct fo_server *server)
+{
+    if (!server->common) {
+        return NULL;
+    }
+    return server->common->name;
+}
+
 const char *fo_get_server_str_name(struct fo_server *server)
 {
     if (!server->common) {
diff --git a/src/providers/fail_over.h b/src/providers/fail_over.h
index cb9e54e989f6529f68cc4cc991cafa6f3ed9b07d..3ca6096c45c4b73706f07b593448734a69272678 100644
--- a/src/providers/fail_over.h
+++ b/src/providers/fail_over.h
@@ -167,6 +167,8 @@ void *fo_get_server_user_data(struct fo_server *server);
 
 int fo_get_server_port(struct fo_server *server);
 
+const char *fo_get_server_name(struct fo_server *server);
+
 const char *fo_get_server_str_name(struct fo_server *server);
 
 struct resolv_hostent *fo_get_server_hostent(struct fo_server *server);
diff --git a/src/providers/ipa/ipa_common.c b/src/providers/ipa/ipa_common.c
index a95b7811f539c2eae47d9a271387a1686b557753..7f5806870c6eabf7048a7f12bd874d35f0502599 100644
--- a/src/providers/ipa/ipa_common.c
+++ b/src/providers/ipa/ipa_common.c
@@ -565,6 +565,7 @@ static void ipa_resolve_callback(void *private_data, struct fo_server *server)
     char *address;
     const char *safe_address;
     char *new_uri;
+    const char *srv_name;
     int ret;
 
     tmp_ctx = talloc_new(NULL);
@@ -611,7 +612,14 @@ static void ipa_resolve_callback(void *private_data, struct fo_server *server)
         return;
     }
 
-    new_uri = talloc_asprintf(service, "ldap://%s", fo_get_server_str_name(server));
+    srv_name = fo_get_server_name(server);
+    if (srv_name == NULL) {
+        DEBUG(1, ("Could not get server host name\n"));
+        talloc_free(tmp_ctx);
+        return;
+    }
+
+    new_uri = talloc_asprintf(service, "ldap://%s", srv_name);
     if (!new_uri) {
         DEBUG(2, ("Failed to copy URI ...\n"));
         talloc_free(tmp_ctx);
diff --git a/src/providers/ldap/ldap_common.c b/src/providers/ldap/ldap_common.c
index 2ae262970ebf6248b38ea087df2bfbdbe85b0994..253cf25db3b68c74e64bcd948d81abab7f991812 100644
--- a/src/providers/ldap/ldap_common.c
+++ b/src/providers/ldap/ldap_common.c
@@ -533,6 +533,7 @@ static void sdap_uri_callback(void *private_data, struct fo_server *server)
     struct resolv_hostent *srvaddr;
     struct sockaddr_storage *sockaddr;
     const char *tmp;
+    const char *srv_name;
     char *new_uri;
 
     tmp_ctx = talloc_new(NULL);
@@ -570,8 +571,16 @@ static void sdap_uri_callback(void *private_data, struct fo_server *server)
             DEBUG(1, ("Unknown service, using ldap\n"));
             tmp = SSS_LDAP_SRV_NAME;
         }
+
+        srv_name = fo_get_server_name(server);
+        if (srv_name == NULL) {
+            DEBUG(1, ("Could not get server host name\n"));
+            talloc_free(tmp_ctx);
+            return;
+        }
+
         new_uri = talloc_asprintf(service, "%s://%s:%d",
-                                  tmp, fo_get_server_str_name(server),
+                                  tmp, srv_name,
                                   fo_get_server_port(server));
     } else {
         new_uri = talloc_strdup(service, tmp);
diff --git a/src/tests/fail_over-tests.c b/src/tests/fail_over-tests.c
index d8a6d510b0a00d309b51c4afee3b88f63fe9f615..8beaa8a2699470725aa45b1395c9110419cd529f 100644
--- a/src/tests/fail_over-tests.c
+++ b/src/tests/fail_over-tests.c
@@ -170,7 +170,7 @@ test_resolve_service_callback(struct tevent_req *req)
     if (task->new_server_status >= 0)
         fo_set_server_status(server, task->new_server_status);
 
-    if (strcmp(fo_get_server_str_name(server), "unknown name")) {
+    if (fo_get_server_name(server) != NULL) {
         he = fo_get_server_hostent(server);
         fail_if(he == NULL, "%s: fo_get_server_hostent() returned NULL");
         for (i = 0; he->addr_list[i]; i++) {
-- 
1.7.10.2

-------------- next part --------------
>From ce294a5f179d743ea60281b34499fc334a258525 Mon Sep 17 00:00:00 2001
From: Jakub Hrozek <jhrozek at redhat.com>
Date: Mon, 5 Mar 2012 21:09:37 +0100
Subject: [PATCH 3/5] Only do one cycle when resolving a server

https://fedorahosted.org/sssd/ticket/1214
---
 src/providers/data_provider_fo.c           |   71 +++++++++++++++++++++++-----
 src/providers/dp_backend.h                 |    5 ++
 src/providers/fail_over.c                  |    6 +++
 src/providers/fail_over.h                  |    3 ++
 src/providers/krb5/krb5_auth.c             |   19 +++++---
 src/providers/ldap/ldap_auth.c             |    5 +-
 src/providers/ldap/sdap_async_connection.c |   13 +++--
 7 files changed, 93 insertions(+), 29 deletions(-)

diff --git a/src/providers/data_provider_fo.c b/src/providers/data_provider_fo.c
index c3f8c3ba72a8696d6bffef08f0b88a3616843bd0..5d634cab948fdf7a8805653c7aa29cadba36e5d2 100644
--- a/src/providers/data_provider_fo.c
+++ b/src/providers/data_provider_fo.c
@@ -46,6 +46,7 @@ struct be_svc_data {
     bool run_callbacks;
 
     struct be_svc_callback *callbacks;
+    struct fo_server *first_resolved;
 };
 
 struct be_failover_ctx {
@@ -408,31 +409,31 @@ static void be_resolve_server_done(struct tevent_req *subreq)
     switch (ret) {
     case EOK:
         if (!state->srv) {
-            tevent_req_error(req, EFAULT);
-            return;
+            ret = EFAULT;
+            goto fail;
         }
         break;
 
     case ENOENT:
         /* all servers have been tried and none
          * was found good, go offline */
-        tevent_req_error(req, EIO);
-        return;
+        ret = EIO;
+        goto fail;
 
     default:
         /* mark server as bad and retry */
         if (!state->srv) {
-            tevent_req_error(req, EFAULT);
-            return;
+            ret = EFAULT;
+            goto fail;
         }
         DEBUG(6, ("Couldn't resolve server (%s), resolver returned (%d)\n",
-                  fo_get_server_str_name(state->srv), ret));
+              fo_get_server_str_name(state->srv), ret));
 
         state->attempts++;
         if (state->attempts >= 10) {
             DEBUG(2, ("Failed to find a server after 10 attempts\n"));
-            tevent_req_error(req, EIO);
-            return;
+            ret = EIO;
+            goto fail;
         }
 
         /* now try next one */
@@ -442,8 +443,8 @@ static void be_resolve_server_done(struct tevent_req *subreq)
                                          state->ctx->be_fo->fo_ctx,
                                          state->svc->fo_service);
         if (!subreq) {
-            tevent_req_error(req, ENOMEM);
-            return;
+            ret = ENOMEM;
+            goto fail;
         }
         tevent_req_set_callback(subreq, be_resolve_server_done, req);
 
@@ -451,6 +452,14 @@ static void be_resolve_server_done(struct tevent_req *subreq)
     }
 
     /* all fine we got the server */
+    if (state->svc->first_resolved == NULL) {
+        DEBUG(7, ("Saving the first resolved server\n"));
+        state->svc->first_resolved = state->srv;
+    } else if (state->svc->first_resolved == state->srv) {
+        DEBUG(2, ("The fail over cycled through all available servers\n"));
+        ret = ENOENT;
+        goto fail;
+    }
 
     if (debug_level >= 4 && fo_get_server_name(state->srv)) {
         struct resolv_hostent *srvaddr;
@@ -459,8 +468,8 @@ static void be_resolve_server_done(struct tevent_req *subreq)
         if (!srvaddr) {
             DEBUG(3, ("FATAL: No hostent available for server (%s)\n",
                       fo_get_server_str_name(state->srv)));
-            tevent_req_error(req, EFAULT);
-            return;
+            ret = EFAULT;
+            goto fail;
         }
 
         inet_ntop(srvaddr->family, srvaddr->addr_list[0]->ipaddr,
@@ -488,6 +497,12 @@ static void be_resolve_server_done(struct tevent_req *subreq)
     }
 
     tevent_req_done(req);
+    return;
+
+fail:
+    DEBUG(7, ("Server resolution failed: %d\n", ret));
+    state->svc->first_resolved = NULL;
+    tevent_req_error(req, ret);
 }
 
 int be_resolve_server_recv(struct tevent_req *req, struct fo_server **srv)
@@ -534,3 +549,33 @@ void reset_fo(struct be_ctx *be_ctx)
     fo_reset_services(be_ctx->be_fo->fo_ctx);
 }
 
+void be_fo_set_port_status(struct be_ctx *ctx,
+                           struct fo_server *server,
+                           enum port_status status)
+{
+    struct be_svc_data *svc;
+    struct fo_service *fsvc;
+
+    fo_set_port_status(server, status);
+
+    fsvc = fo_get_server_service(server);
+    if (!fsvc) {
+        DEBUG(3, ("BUG: No service associated with server\n"));
+        return;
+    }
+
+    DLIST_FOR_EACH(svc, ctx->be_fo->svcs) {
+        if (svc->fo_service == fsvc) break;
+    }
+
+    if (!svc) {
+        DEBUG(3, ("BUG: Unknown service\n"));
+        return;
+    }
+
+    if (status == PORT_WORKING) {
+        /* We were successful in connecting to the server. Cycle through all
+         * available servers next time */
+        svc->first_resolved = NULL;
+    }
+}
diff --git a/src/providers/dp_backend.h b/src/providers/dp_backend.h
index 3d5e40bae43b326c00ce9464abfca1e5918ced01..5d75287ea20a7bea04de0ac2f44aa60701c92553 100644
--- a/src/providers/dp_backend.h
+++ b/src/providers/dp_backend.h
@@ -185,6 +185,11 @@ struct tevent_req *be_resolve_server_send(TALLOC_CTX *memctx,
                                           struct be_ctx *ctx,
                                           const char *service_name);
 int be_resolve_server_recv(struct tevent_req *req, struct fo_server **srv);
+
+void be_fo_set_port_status(struct be_ctx *ctx,
+                           struct fo_server *server,
+                           enum port_status status);
+
 /*
  * Instruct fail-over to try next server on the next connect attempt.
  * Should be used after connection to service was unexpectedly dropped
diff --git a/src/providers/fail_over.c b/src/providers/fail_over.c
index 3c46d8dd233b55306b64a84a6a16335b0c384d1e..2b47e55cbd4e5c703ec7c741625bbf6b690bec9f 100644
--- a/src/providers/fail_over.c
+++ b/src/providers/fail_over.c
@@ -1411,3 +1411,9 @@ void fo_reset_services(struct fo_ctx *fo_ctx)
     }
 }
 
+struct fo_service *
+fo_get_server_service(struct fo_server *server)
+{
+    if (!server) return NULL;
+    return server->service;
+}
diff --git a/src/providers/fail_over.h b/src/providers/fail_over.h
index 3ca6096c45c4b73706f07b593448734a69272678..50c0dcf8d48df2bb6a3534e99c3de980f873f817 100644
--- a/src/providers/fail_over.h
+++ b/src/providers/fail_over.h
@@ -178,4 +178,7 @@ time_t fo_get_server_hostname_last_change(struct fo_server *server);
 int fo_is_srv_lookup(struct fo_server *s);
 
 void fo_reset_services(struct fo_ctx *fo_ctx);
+
+struct fo_service *fo_get_server_service(struct fo_server *server);
+
 #endif /* !__FAIL_OVER_H__ */
diff --git a/src/providers/krb5/krb5_auth.c b/src/providers/krb5/krb5_auth.c
index 7b72660adaaff35d20bfa5482a3d20a5774fd6cf..f2777f2f9f696dd82545c02f8c74ae1e57f15fbb 100644
--- a/src/providers/krb5/krb5_auth.c
+++ b/src/providers/krb5/krb5_auth.c
@@ -876,14 +876,16 @@ static void krb5_child_done(struct tevent_req *subreq)
     if (kr->kpasswd_srv != NULL) {
         /* ..which is unreachable by now.. */
         if (msg_status == PAM_AUTHTOK_LOCK_BUSY) {
-            fo_set_port_status(kr->kpasswd_srv, PORT_NOT_WORKING);
+            be_fo_set_port_status(state->be_ctx,
+                                  kr->kpasswd_srv, PORT_NOT_WORKING);
             /* ..try to resolve next kpasswd server */
             if (krb5_next_kpasswd(req) == NULL) {
                 tevent_req_error(req, ENOMEM);
             }
             return;
         } else {
-            fo_set_port_status(kr->kpasswd_srv, PORT_WORKING);
+            be_fo_set_port_status(state->be_ctx,
+                                  kr->kpasswd_srv, PORT_WORKING);
         }
     }
 
@@ -893,7 +895,7 @@ static void krb5_child_done(struct tevent_req *subreq)
     if (msg_status == PAM_AUTHINFO_UNAVAIL ||
         (kr->kpasswd_srv == NULL && msg_status == PAM_AUTHTOK_LOCK_BUSY)) {
         if (kr->srv != NULL) {
-            fo_set_port_status(kr->srv, PORT_NOT_WORKING);
+            be_fo_set_port_status(state->be_ctx, kr->srv, PORT_NOT_WORKING);
             /* ..try to resolve next KDC */
             if (krb5_next_kdc(req) == NULL) {
                 tevent_req_error(req, ENOMEM);
@@ -901,7 +903,7 @@ static void krb5_child_done(struct tevent_req *subreq)
             return;
         }
     } else if (kr->srv != NULL) {
-        fo_set_port_status(kr->srv, PORT_WORKING);
+        be_fo_set_port_status(state->be_ctx, kr->srv, PORT_WORKING);
     }
 
     /* Now only a successful authentication or password change is left.
@@ -972,17 +974,20 @@ static struct tevent_req *krb5_next_server(struct tevent_req *req)
     switch (pd->cmd) {
         case SSS_PAM_AUTHENTICATE:
         case SSS_CMD_RENEW:
-            fo_set_port_status(state->kr->srv, PORT_NOT_WORKING);
+            be_fo_set_port_status(state->be_ctx,
+                                  state->kr->srv, PORT_NOT_WORKING);
             next_req = krb5_next_kdc(req);
             break;
         case SSS_PAM_CHAUTHTOK:
         case SSS_PAM_CHAUTHTOK_PRELIM:
             if (state->kr->kpasswd_srv) {
-                fo_set_port_status(state->kr->kpasswd_srv, PORT_NOT_WORKING);
+                be_fo_set_port_status(state->be_ctx,
+                                      state->kr->kpasswd_srv, PORT_NOT_WORKING);
                 next_req = krb5_next_kpasswd(req);
                 break;
             } else {
-                fo_set_port_status(state->kr->srv, PORT_NOT_WORKING);
+                be_fo_set_port_status(state->be_ctx,
+                                      state->kr->srv, PORT_NOT_WORKING);
                 next_req = krb5_next_kdc(req);
                 break;
             }
diff --git a/src/providers/ldap/ldap_auth.c b/src/providers/ldap/ldap_auth.c
index f01c23d6e5de3d55d64f858803054d930e2577f5..a1b0acd1071809fdb5388dd25d5dd476ab7ba0ca 100644
--- a/src/providers/ldap/ldap_auth.c
+++ b/src/providers/ldap/ldap_auth.c
@@ -588,7 +588,8 @@ static void auth_connect_done(struct tevent_req *subreq)
     if (ret) {
         if (state->srv) {
             /* mark this server as bad if connection failed */
-            fo_set_port_status(state->srv, PORT_NOT_WORKING);
+            be_fo_set_port_status(state->ctx->be,
+                                  state->srv, PORT_NOT_WORKING);
         }
         if (ret == ETIMEDOUT) {
             if (auth_get_server(req) == NULL) {
@@ -600,7 +601,7 @@ static void auth_connect_done(struct tevent_req *subreq)
         tevent_req_error(req, ret);
         return;
     } else if (state->srv) {
-        fo_set_port_status(state->srv, PORT_WORKING);
+        be_fo_set_port_status(state->ctx->be, state->srv, PORT_WORKING);
     }
 
     ret = get_user_dn(state, state->ctx->be->sysdb, state->ctx->opts,
diff --git a/src/providers/ldap/sdap_async_connection.c b/src/providers/ldap/sdap_async_connection.c
index 570d6d4908ef057a7dd5fca4d36626c738bc10d5..3210784787f78a5bb58af06c81ae7f73c77e3867 100644
--- a/src/providers/ldap/sdap_async_connection.c
+++ b/src/providers/ldap/sdap_async_connection.c
@@ -930,7 +930,7 @@ static void sdap_kinit_done(struct tevent_req *subreq)
         return;
     } else {
         if (kerr == KRB5_KDC_UNREACH) {
-            fo_set_port_status(state->kdc_srv, PORT_NOT_WORKING);
+            be_fo_set_port_status(state->be, state->kdc_srv, PORT_NOT_WORKING);
             nextreq = sdap_kinit_next_kdc(req);
             if (!nextreq) {
                 tevent_req_error(req, ENOMEM);
@@ -1156,7 +1156,6 @@ struct tevent_req *sdap_cli_connect_send(TALLOC_CTX *memctx,
     state->be = be;
     state->srv = NULL;
     state->srv_opts = NULL;
-    state->be = be;
     state->use_rootdse = !skip_rootdse;
 
     ret = sdap_cli_resolve_next(req);
@@ -1239,7 +1238,7 @@ static void sdap_cli_connect_done(struct tevent_req *subreq)
     talloc_zfree(subreq);
     if (ret) {
         /* retry another server */
-        fo_set_port_status(state->srv, PORT_NOT_WORKING);
+        be_fo_set_port_status(state->be, state->srv, PORT_NOT_WORKING);
         ret = sdap_cli_resolve_next(req);
         if (ret != EOK) {
             tevent_req_error(req, ret);
@@ -1313,7 +1312,7 @@ static void sdap_cli_rootdse_done(struct tevent_req *subreq)
     talloc_zfree(subreq);
     if (ret) {
         if (ret == ETIMEDOUT) { /* retry another server */
-            fo_set_port_status(state->srv, PORT_NOT_WORKING);
+            be_fo_set_port_status(state->be, state->srv, PORT_NOT_WORKING);
             ret = sdap_cli_resolve_next(req);
             if (ret != EOK) {
                 tevent_req_error(req, ret);
@@ -1426,7 +1425,7 @@ static void sdap_cli_kinit_done(struct tevent_req *subreq)
     talloc_zfree(subreq);
     if (ret) {
         if (ret == ETIMEDOUT) { /* child timed out, retry another server */
-            fo_set_port_status(state->srv, PORT_NOT_WORKING);
+            be_fo_set_port_status(state->be, state->srv, PORT_NOT_WORKING);
             ret = sdap_cli_resolve_next(req);
             if (ret != EOK) {
                 tevent_req_error(req, ret);
@@ -1510,7 +1509,7 @@ int sdap_cli_connect_recv(struct tevent_req *req,
     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);
+            be_fo_set_port_status(state->be, state->srv, PORT_NOT_WORKING);
         } else {
             if (can_retry) {
                 *can_retry = false;
@@ -1522,7 +1521,7 @@ int sdap_cli_connect_recv(struct tevent_req *req,
         }
         return EIO;
     } else if (state->srv) {
-        fo_set_port_status(state->srv, PORT_WORKING);
+        be_fo_set_port_status(state->be, state->srv, PORT_WORKING);
     }
 
     if (gsh) {
-- 
1.7.10.2

-------------- next part --------------
>From 21a90d9d9650f4a65202b4b76bfae453896472de Mon Sep 17 00:00:00 2001
From: Jakub Hrozek <jhrozek at redhat.com>
Date: Wed, 7 Mar 2012 17:08:52 +0100
Subject: [PATCH 4/5] Detect cycle in the fail over on subsequent resolve
 requests only

---
 src/providers/data_provider_fo.c           |    7 ++++--
 src/providers/dp_backend.h                 |    3 ++-
 src/providers/krb5/krb5_auth.c             |   32 +++++++++++++---------------
 src/providers/ldap/ldap_auth.c             |    3 ++-
 src/providers/ldap/sdap_async_connection.c |    6 ++++--
 5 files changed, 28 insertions(+), 23 deletions(-)

diff --git a/src/providers/data_provider_fo.c b/src/providers/data_provider_fo.c
index 5d634cab948fdf7a8805653c7aa29cadba36e5d2..d5cb0a47646a239fee7e2c6322f5f49b1e95b934 100644
--- a/src/providers/data_provider_fo.c
+++ b/src/providers/data_provider_fo.c
@@ -352,6 +352,7 @@ struct be_resolve_server_state {
     int attempts;
 
     struct fo_server *srv;
+    bool first_try;
 };
 
 static void be_resolve_server_done(struct tevent_req *subreq);
@@ -359,7 +360,8 @@ static void be_resolve_server_done(struct tevent_req *subreq);
 struct tevent_req *be_resolve_server_send(TALLOC_CTX *memctx,
                                           struct tevent_context *ev,
                                           struct be_ctx *ctx,
-                                          const char *service_name)
+                                          const char *service_name,
+                                          bool first_try)
 {
     struct tevent_req *req, *subreq;
     struct be_resolve_server_state *state;
@@ -380,6 +382,7 @@ struct tevent_req *be_resolve_server_send(TALLOC_CTX *memctx,
 
     state->svc = svc;
     state->attempts = 0;
+    state->first_try = first_try;
 
     subreq = fo_resolve_service_send(state, ev,
                                      ctx->be_fo->resolv,
@@ -452,7 +455,7 @@ static void be_resolve_server_done(struct tevent_req *subreq)
     }
 
     /* all fine we got the server */
-    if (state->svc->first_resolved == NULL) {
+    if (state->svc->first_resolved == NULL || state->first_try == true) {
         DEBUG(7, ("Saving the first resolved server\n"));
         state->svc->first_resolved = state->srv;
     } else if (state->svc->first_resolved == state->srv) {
diff --git a/src/providers/dp_backend.h b/src/providers/dp_backend.h
index 5d75287ea20a7bea04de0ac2f44aa60701c92553..27ae9d73c135953a22a31ede396bf2ca71bebffa 100644
--- a/src/providers/dp_backend.h
+++ b/src/providers/dp_backend.h
@@ -183,7 +183,8 @@ int be_fo_add_server(struct be_ctx *ctx, const char *service_name,
 struct tevent_req *be_resolve_server_send(TALLOC_CTX *memctx,
                                           struct tevent_context *ev,
                                           struct be_ctx *ctx,
-                                          const char *service_name);
+                                          const char *service_name,
+                                          bool first_try);
 int be_resolve_server_recv(struct tevent_req *req, struct fo_server **srv);
 
 void be_fo_set_port_status(struct be_ctx *ctx,
diff --git a/src/providers/krb5/krb5_auth.c b/src/providers/krb5/krb5_auth.c
index f2777f2f9f696dd82545c02f8c74ae1e57f15fbb..24a6a4a4ec936f49d8277c22554633ea999e90b3 100644
--- a/src/providers/krb5/krb5_auth.c
+++ b/src/providers/krb5/krb5_auth.c
@@ -324,6 +324,9 @@ int krb5_auth_recv(struct tevent_req *req, int *pam_status, int *dp_err)
     return EOK;
 }
 
+static struct tevent_req *krb5_next_kdc(struct tevent_req *req);
+static struct tevent_req *krb5_next_kpasswd(struct tevent_req *req);
+
 struct tevent_req *krb5_auth_send(TALLOC_CTX *mem_ctx,
                                   struct tevent_context *ev,
                                   struct be_ctx *be_ctx,
@@ -511,16 +514,14 @@ struct tevent_req *krb5_auth_send(TALLOC_CTX *mem_ctx,
 
     kr->srv = NULL;
     kr->kpasswd_srv = NULL;
-    subreq = be_resolve_server_send(state, state->ev, state->be_ctx,
-                                    krb5_ctx->service->name);
-    if (subreq == NULL) {
-        DEBUG(1, ("be_resolve_server_send failed.\n"));
-        ret = ENOMEM;
+
+    subreq = krb5_next_kdc(req);
+    if (!subreq) {
+        DEBUG(1, ("krb5_next_kdc failed.\n"));
+        ret = EIO;
         goto done;
     }
 
-    tevent_req_set_callback(subreq, krb5_resolve_kdc_done, req);
-
     return req;
 
 done:
@@ -551,16 +552,12 @@ static void krb5_resolve_kdc_done(struct tevent_req *subreq)
         kr->is_offline = true;
     } else {
         if (kr->krb5_ctx->kpasswd_service != NULL) {
-            subreq = be_resolve_server_send(state, state->ev, state->be_ctx,
-                                            kr->krb5_ctx->kpasswd_service->name);
+            subreq = krb5_next_kpasswd(req);
             if (subreq == NULL) {
-                DEBUG(1, ("be_resolve_server_send failed.\n"));
-                ret = ENOMEM;
+                DEBUG(1, ("krb5_next_kpasswd failed.\n"));
+                ret = EIO;
                 goto failed;
             }
-
-            tevent_req_set_callback(subreq, krb5_resolve_kpasswd_done, req);
-
             return;
         }
     }
@@ -710,7 +707,6 @@ done:
 }
 
 static struct tevent_req *krb5_next_server(struct tevent_req *req);
-static struct tevent_req *krb5_next_kdc(struct tevent_req *req);
 static struct tevent_req *krb5_next_kpasswd(struct tevent_req *req);
 
 static void krb5_child_done(struct tevent_req *subreq)
@@ -1005,7 +1001,8 @@ static struct tevent_req *krb5_next_kdc(struct tevent_req *req)
 
     next_req = be_resolve_server_send(state, state->ev,
                                       state->be_ctx,
-                                      state->krb5_ctx->service->name);
+                                      state->krb5_ctx->service->name,
+                                      state->kr->srv == NULL ? true : false);
     if (next_req == NULL) {
         DEBUG(1, ("be_resolve_server_send failed.\n"));
         return NULL;
@@ -1022,7 +1019,8 @@ static struct tevent_req *krb5_next_kpasswd(struct tevent_req *req)
 
     next_req = be_resolve_server_send(state, state->ev,
                                 state->be_ctx,
-                                state->krb5_ctx->kpasswd_service->name);
+                                state->krb5_ctx->kpasswd_service->name,
+                                state->kr->kpasswd_srv == NULL ? true : false);
     if (next_req == NULL) {
         DEBUG(1, ("be_resolve_server_send failed.\n"));
         return NULL;
diff --git a/src/providers/ldap/ldap_auth.c b/src/providers/ldap/ldap_auth.c
index a1b0acd1071809fdb5388dd25d5dd476ab7ba0ca..9b3abcb1060738c5bfe17891f5275a5f3873cc93 100644
--- a/src/providers/ldap/ldap_auth.c
+++ b/src/providers/ldap/ldap_auth.c
@@ -517,7 +517,8 @@ static struct tevent_req *auth_get_server(struct tevent_req *req)
     next_req = be_resolve_server_send(state,
                                       state->ev,
                                       state->ctx->be,
-                                      state->sdap_service->name);
+                                      state->sdap_service->name,
+                                      state->srv == NULL ? true : false);
     if (!next_req) {
         DEBUG(1, ("be_resolve_server_send failed.\n"));
         return NULL;
diff --git a/src/providers/ldap/sdap_async_connection.c b/src/providers/ldap/sdap_async_connection.c
index 3210784787f78a5bb58af06c81ae7f73c77e3867..63250d618d4e74b87f4eb62b960d2ef16fbb3abc 100644
--- a/src/providers/ldap/sdap_async_connection.c
+++ b/src/providers/ldap/sdap_async_connection.c
@@ -852,7 +852,8 @@ static struct tevent_req *sdap_kinit_next_kdc(struct tevent_req *req)
 
     next_req = be_resolve_server_send(state, state->ev,
                                       state->be,
-                                      state->krb_service_name);
+                                      state->krb_service_name,
+                                      state->kdc_srv == NULL ? true : false);
     if (next_req == NULL) {
         DEBUG(1, ("be_resolve_server_send failed.\n"));
         return NULL;
@@ -1178,7 +1179,8 @@ static int sdap_cli_resolve_next(struct tevent_req *req)
     /* NOTE: this call may cause service->uri to be refreshed
      * with a new valid server. Do not use service->uri before */
     subreq = be_resolve_server_send(state, state->ev,
-                                    state->be, state->service->name);
+                                    state->be, state->service->name,
+                                    state->srv == NULL ? true : false);
     if (!subreq) {
         return ENOMEM;
     }
-- 
1.7.10.2

-------------- next part --------------
>From 9404d454c7f22f31223e454891a6a8ceded2717d Mon Sep 17 00:00:00 2001
From: Jakub Hrozek <jhrozek at redhat.com>
Date: Mon, 4 Jun 2012 10:39:44 +0200
Subject: [PATCH 5/5] Try all KDCs when getting TGT for LDAP

When the ldap child process is killed after a timeout, try the next KDC.
When none of the ldap child processes succeed, just abort the connection
because we wouldn't be able to authenticate to the LDAP server anyway.

https://fedorahosted.org/sssd/ticket/1324
---
 src/providers/ldap/sdap_async_connection.c |   31 ++++++++++++++--------------
 1 file changed, 16 insertions(+), 15 deletions(-)

diff --git a/src/providers/ldap/sdap_async_connection.c b/src/providers/ldap/sdap_async_connection.c
index 63250d618d4e74b87f4eb62b960d2ef16fbb3abc..b5c323baf66e1dcaf3d7afda755634ab2655c18f 100644
--- a/src/providers/ldap/sdap_async_connection.c
+++ b/src/providers/ldap/sdap_async_connection.c
@@ -910,7 +910,18 @@ static void sdap_kinit_done(struct tevent_req *subreq)
     ret = sdap_get_tgt_recv(subreq, state, &result,
                             &kerr, &ccname, &expire_time);
     talloc_zfree(subreq);
-    if (ret != EOK) {
+    if (ret == ETIMEDOUT) {
+        /* The child didn't even respond. Perhaps the KDC is too busy,
+         * retry with another KDC */
+        DEBUG(4, ("Communication with KDC timed out, trying the next one\n"));
+        be_fo_set_port_status(state->be, state->kdc_srv, PORT_NOT_WORKING);
+        nextreq = sdap_kinit_next_kdc(req);
+        if (!nextreq) {
+            tevent_req_error(req, ENOMEM);
+        }
+        return;
+    } else if (ret != EOK) {
+        /* A severe error while executing the child. Abort the operation. */
         state->result = SDAP_AUTH_FAILED;
         DEBUG(1, ("child failed (%d [%s])\n", ret, strerror(ret)));
         tevent_req_error(req, ret);
@@ -1425,20 +1436,10 @@ static void sdap_cli_kinit_done(struct tevent_req *subreq)
 
     ret = sdap_kinit_recv(subreq, &result, &expire_time);
     talloc_zfree(subreq);
-    if (ret) {
-        if (ret == ETIMEDOUT) { /* child timed out, retry another server */
-            be_fo_set_port_status(state->be, state->srv, PORT_NOT_WORKING);
-            ret = sdap_cli_resolve_next(req);
-            if (ret != EOK) {
-                tevent_req_error(req, ret);
-            }
-            return;
-        }
-
-        tevent_req_error(req, ret);
-        return;
-    }
-    if (result != SDAP_AUTH_SUCCESS) {
+    if (ret != EOK || result != SDAP_AUTH_SUCCESS) {
+        /* We're not able to authenticate to the LDAP server.
+         * There's not much we can do except for going offline */
+        DEBUG(6, ("Cannot get a TGT: ret [%d] result [%d]\n", ret, result));
         tevent_req_error(req, EACCES);
         return;
     }
-- 
1.7.10.2



More information about the sssd-devel mailing list