diff options
-rw-r--r-- | server/providers/ldap/ldap_common.c | 139 | ||||
-rw-r--r-- | server/providers/ldap/ldap_common.h | 1 | ||||
-rw-r--r-- | server/providers/ldap/ldap_id.c | 15 | ||||
-rw-r--r-- | server/providers/ldap/ldap_id_cleanup.c | 18 | ||||
-rw-r--r-- | server/providers/ldap/ldap_id_enum.c | 18 |
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))); |