summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--server/providers/ldap/ldap_common.c139
-rw-r--r--server/providers/ldap/ldap_common.h1
-rw-r--r--server/providers/ldap/ldap_id.c15
-rw-r--r--server/providers/ldap/ldap_id_cleanup.c18
-rw-r--r--server/providers/ldap/ldap_id_enum.c18
5 files changed, 189 insertions, 2 deletions
diff --git a/server/providers/ldap/ldap_common.c b/server/providers/ldap/ldap_common.c
index d43d1485..e4f3f6bb 100644
--- a/server/providers/ldap/ldap_common.c
+++ b/server/providers/ldap/ldap_common.c
@@ -25,6 +25,8 @@
#include "providers/ldap/ldap_common.h"
#include "providers/fail_over.h"
+#include "util/sss_krb5.h"
+
/* a fd the child process would log into */
int ldap_child_debug_fd = -1;
@@ -305,6 +307,143 @@ void sdap_mark_offline(struct sdap_id_ctx *ctx)
be_mark_offline(ctx->be);
}
+bool sdap_check_gssapi_reconnect(struct sdap_id_ctx *ctx)
+{
+ 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;
+
+
+ mech = dp_opt_get_string(ctx->opts->basic, SDAP_SASL_MECH);
+ if (mech == NULL || strcasecmp(mech, "GSSAPI") != 0) {
+ return false;
+ }
+
+ realm = dp_opt_get_string(ctx->opts->basic, SDAP_KRB5_REALM);
+ if (realm == NULL) {
+ DEBUG(3, ("Kerberos realm not available.\n"));
+ return false;
+ }
+
+ tmp_ctx = talloc_new(NULL);
+ if (tmp_ctx == NULL) {
+ DEBUG(1, ("talloc_new failed.\n"));
+ return false;
+ }
+
+ ccname = talloc_asprintf(tmp_ctx, "FILE:%s/ccache_%s", DB_PATH, realm);
+ if (ccname == NULL) {
+ DEBUG(1, ("talloc_asprintf failed.\n"));
+ goto done;
+ }
+
+ krberr = krb5_init_context(&context);
+ if (krberr) {
+ DEBUG(1, ("Failed to init kerberos context\n"));
+ goto done;
+ }
+
+ krberr = krb5_cc_resolve(context, ccname, &ccache);
+ if (krberr != 0) {
+ DEBUG(1, ("krb5_cc_resolve failed.\n"));
+ goto done;
+ }
+
+ server_name = talloc_asprintf(tmp_ctx, "krbtgt/%s@%s", realm, realm);
+ if (server_name == NULL) {
+ DEBUG(1, ("talloc_asprintf failed.\n"));
+ goto done;
+ }
+
+ krberr = krb5_parse_name(context, server_name, &server_principal);
+ if (krberr != 0) {
+ DEBUG(1, ("krb5_parse_name failed.\n"));
+ goto done;
+ }
+
+ 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);
+ }
+ } 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;
+ }
+ 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;
+ }
+ 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;
+ }
+
+ memset(&mcred, 0, sizeof(mcred));
+ memset(&cred, 0, sizeof(mcred));
+ mcred.client = client_principal;
+ mcred.server = server_principal;
+
+ krberr = krb5_cc_retrieve_cred(context, ccache, 0, &mcred, &cred);
+ if (krberr != 0) {
+ DEBUG(1, ("krb5_cc_retrieve_cred failed.\n"));
+ goto done;
+ }
+
+ DEBUG(7, ("TGT end time [%d].\n", cred.times.endtime));
+
+ if (cred.times.endtime <= time(NULL)) {
+ DEBUG(3, ("TGT is expired.\n"));
+ result = true;
+ }
+ krb5_free_cred_contents(context, &cred);
+
+done:
+ if (client_principal != NULL) {
+ krb5_free_principal(context, client_principal);
+ }
+ if (server_principal != NULL) {
+ krb5_free_principal(context, server_principal);
+ }
+ if (ccache != NULL) {
+ if (result) {
+ krb5_cc_destroy(context, ccache);
+ } else {
+ krb5_cc_close(context, ccache);
+ }
+ }
+ if (context != NULL) krb5_free_context(context);
+ talloc_free(tmp_ctx);
+ return result;
+}
int sdap_id_setup_tasks(struct sdap_id_ctx *ctx)
{
diff --git a/server/providers/ldap/ldap_common.h b/server/providers/ldap/ldap_common.h
index b1985455..ff1ffb72 100644
--- a/server/providers/ldap/ldap_common.h
+++ b/server/providers/ldap/ldap_common.h
@@ -91,6 +91,7 @@ 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,
diff --git a/server/providers/ldap/ldap_id.c b/server/providers/ldap/ldap_id.c
index 18b387e5..4bbc07a6 100644
--- a/server/providers/ldap/ldap_id.c
+++ b/server/providers/ldap/ldap_id.c
@@ -719,6 +719,11 @@ static void sdap_account_info_users_done(struct tevent_req *req)
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);
}
}
@@ -745,6 +750,11 @@ static void sdap_account_info_groups_done(struct tevent_req *req)
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);
}
}
@@ -771,6 +781,11 @@ static void sdap_account_info_initgr_done(struct tevent_req *req)
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);
}
}
diff --git a/server/providers/ldap/ldap_id_cleanup.c b/server/providers/ldap/ldap_id_cleanup.c
index 60d3b28a..f3fb4443 100644
--- a/server/providers/ldap/ldap_id_cleanup.c
+++ b/server/providers/ldap/ldap_id_cleanup.c
@@ -212,6 +212,14 @@ fail:
DEBUG(9, ("User cleanup failed with: (%d)[%s]\n",
(int)err, strerror(err)));
+ if (sdap_check_gssapi_reconnect(state->ctx)) {
+ talloc_zfree(state->ctx->gsh);
+ subreq = cleanup_users_send(state, state->ev, state->ctx);
+ if (subreq != NULL) {
+ tevent_req_set_callback(subreq, ldap_id_cleanup_users_done, req);
+ return;
+ }
+ }
sdap_mark_offline(state->ctx);
}
@@ -242,7 +250,15 @@ static void ldap_id_cleanup_groups_done(struct tevent_req *subreq)
return;
fail:
- /* always go offline on failures */
+ /* check if credentials are expired otherwise go offline on failures */
+ if (sdap_check_gssapi_reconnect(state->ctx)) {
+ talloc_zfree(state->ctx->gsh);
+ subreq = cleanup_groups_send(state, state->ev, state->ctx);
+ if (subreq != NULL) {
+ tevent_req_set_callback(subreq, ldap_id_cleanup_groups_done, req);
+ return;
+ }
+ }
sdap_mark_offline(state->ctx);
DEBUG(1, ("Failed to cleanup groups (%d [%s]), retrying later!\n",
(int)err, strerror(err)));
diff --git a/server/providers/ldap/ldap_id_enum.c b/server/providers/ldap/ldap_id_enum.c
index 1ddcbf8f..bc06e8bd 100644
--- a/server/providers/ldap/ldap_id_enum.c
+++ b/server/providers/ldap/ldap_id_enum.c
@@ -227,6 +227,14 @@ fail:
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);
+ if (subreq != NULL) {
+ tevent_req_set_callback(subreq, ldap_id_enum_users_done, req);
+ return;
+ }
+ }
sdap_mark_offline(state->ctx);
}
@@ -268,7 +276,15 @@ static void ldap_id_enum_groups_done(struct tevent_req *subreq)
return;
fail:
- /* always go offline on failures */
+ /* 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;
+ }
+ }
sdap_mark_offline(state->ctx);
DEBUG(1, ("Failed to enumerate groups (%d [%s]), retrying later!\n",
(int)err, strerror(err)));