[SSSD] [PATCH] Only detect cycle in the fail over on subsequent resolve requests

Jakub Hrozek jhrozek at redhat.com
Wed Mar 7 16:48:45 UTC 2012


The yesterday's fail over patch broke the IPA provider.. The IPA provider
is a special case because it uses fail over port 0 for both LDAP and
Kerberos. That is done to make sure that we never connect to LDAP port on
one host and Kerberos port on a different host.

However, the cycle detection in fail over tripped over this because when
performing a GSSAPI bind, we first request a server with port 0 to get
the LDAP server and before we can mark the server status (or go
offline), we also need to resolve the KDC, which, from fail over point
of view is also running on port 0...

The attached patch adds a boolean parameter to be_resolve_server_send()
and only performs the cycle check if the parameter is false, that is,
when requesting another server during the same operation.
-------------- next part --------------
From 5c02f2775185b629390400a915cedd05d129f56e 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] Detect cycle in the fail over on subsequent resolve requests
 only

---
 src/providers/data_provider_fo.c           |   10 ++++++--
 src/providers/dp_backend.h                 |    3 +-
 src/providers/krb5/krb5_auth.c             |   29 ++++++++++++++-------------
 src/providers/ldap/ldap_auth.c             |    3 +-
 src/providers/ldap/sdap_async_connection.c |    6 +++-
 5 files changed, 30 insertions(+), 21 deletions(-)

diff --git a/src/providers/data_provider_fo.c b/src/providers/data_provider_fo.c
index c358e68d12bce0c518d58aaa17b3b3cdb706d180..228c04a9e98ea5d856f998b01ba7ed45210c8dd8 100644
--- a/src/providers/data_provider_fo.c
+++ b/src/providers/data_provider_fo.c
@@ -342,6 +342,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);
@@ -349,7 +350,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;
@@ -370,6 +372,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,
@@ -443,10 +446,11 @@ 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(SSSDBG_TRACE_LIBS, ("Saving the first resolved server\n"));
         state->svc->first_resolved = state->srv;
-    } else if (state->svc->first_resolved == state->srv) {
+    } else if (state->svc->first_resolved == state->srv &&
+               state->first_try == false) {
         DEBUG(SSSDBG_OP_FAILURE,
               ("The fail over cycled through all available servers\n"));
         ret = ENOENT;
diff --git a/src/providers/dp_backend.h b/src/providers/dp_backend.h
index 96c774783e6590f86cb4a35fe4d920e792d379ce..6e98e7ef3c9370f0cbf93a8f344641b2642bd9a8 100644
--- a/src/providers/dp_backend.h
+++ b/src/providers/dp_backend.h
@@ -207,7 +207,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 72992ba752c8d7a0202f4475b4bc0bd3af8f369d..da25c6daa9b93ba7ccc8348aa0451cb07be7375e 100644
--- a/src/providers/krb5/krb5_auth.c
+++ b/src/providers/krb5/krb5_auth.c
@@ -320,6 +320,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,
@@ -507,16 +510,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(SSSDBG_CRIT_FAILURE, ("krb5_next_kdc failed.\n"));
+        ret = EIO;
         goto done;
     }
 
-    tevent_req_set_callback(subreq, krb5_resolve_kdc_done, req);
-
     return req;
 
 done:
@@ -557,11 +558,10 @@ static void krb5_resolve_kdc_done(struct tevent_req *subreq)
         }
     } 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(SSSDBG_CRIT_FAILURE, ("krb5_next_kpasswd failed.\n"));
+                ret = EIO;
                 goto failed;
             }
 
@@ -718,7 +718,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)
@@ -1004,7 +1003,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;
@@ -1021,7 +1021,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 8b6173e145239a2e604aaa9aea43a632ae8582d9..734249ced33e3b70dcfd452f674a9e3dd5b736da 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 22aa4f91ebb4020efc8b4ac5df210f443010e744..2b7f8c93df55e167ae2f4fb330a47dd600c2974e 100644
--- a/src/providers/ldap/sdap_async_connection.c
+++ b/src/providers/ldap/sdap_async_connection.c
@@ -884,7 +884,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;
@@ -1215,7 +1216,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.7.6



More information about the sssd-devel mailing list