[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