summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--Makefile.am1
-rw-r--r--src/providers/ipa/ipa_common.c1
-rw-r--r--src/providers/krb5/krb5_common.c2
-rw-r--r--src/providers/krb5/krb5_common.h6
-rw-r--r--src/providers/ldap/ldap_common.c171
-rw-r--r--src/providers/ldap/ldap_common.h20
-rw-r--r--src/providers/ldap/ldap_init.c11
-rw-r--r--src/providers/ldap/sdap.h1
-rw-r--r--src/providers/ldap/sdap_async.h3
-rw-r--r--src/providers/ldap/sdap_async_connection.c92
10 files changed, 303 insertions, 5 deletions
diff --git a/Makefile.am b/Makefile.am
index d1fcd862b..605b97ad9 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -769,6 +769,7 @@ libsss_ldap_la_SOURCES = \
src/providers/ldap/sdap_fd_events.c \
src/providers/ldap/sdap_id_op.c \
src/providers/ldap/sdap.c \
+ src/providers/krb5/krb5_common.c \
src/util/user_info_msg.c \
src/util/sss_ldap.c \
src/util/sss_krb5.c
diff --git a/src/providers/ipa/ipa_common.c b/src/providers/ipa/ipa_common.c
index 3d999f51e..dea1a73fe 100644
--- a/src/providers/ipa/ipa_common.c
+++ b/src/providers/ipa/ipa_common.c
@@ -542,6 +542,7 @@ int ipa_service_init(TALLOC_CTX *memctx, struct be_ctx *ctx,
ret = ENOMEM;
goto done;
}
+ service->sdap->kinit_service_name = service->krb5_service->name;
realm = talloc_strdup(service, domain);
if (!realm) {
diff --git a/src/providers/krb5/krb5_common.c b/src/providers/krb5/krb5_common.c
index d41fdb9df..3863acd9c 100644
--- a/src/providers/krb5/krb5_common.c
+++ b/src/providers/krb5/krb5_common.c
@@ -426,7 +426,7 @@ done:
}
-static errno_t remove_krb5_info_files(TALLOC_CTX *mem_ctx, const char *realm)
+errno_t remove_krb5_info_files(TALLOC_CTX *mem_ctx, const char *realm)
{
int ret;
errno_t err;
diff --git a/src/providers/krb5/krb5_common.h b/src/providers/krb5/krb5_common.h
index f3bbbb84b..6398ea225 100644
--- a/src/providers/krb5/krb5_common.h
+++ b/src/providers/krb5/krb5_common.h
@@ -136,4 +136,10 @@ errno_t krb5_install_offline_callback(struct be_ctx *be_ctx,
errno_t krb5_install_sigterm_handler(struct tevent_context *ev,
struct krb5_ctx *krb5_ctx);
+
+errno_t write_krb5info_file(const char *realm, const char *kdc,
+ const char *service);
+
+errno_t remove_krb5_info_files(TALLOC_CTX *mem_ctx, const char *realm);
+
#endif /* __KRB5_COMMON_H__ */
diff --git a/src/providers/ldap/ldap_common.c b/src/providers/ldap/ldap_common.c
index cf2cd6992..87fd43a19 100644
--- a/src/providers/ldap/ldap_common.c
+++ b/src/providers/ldap/ldap_common.c
@@ -25,6 +25,7 @@
#include "providers/ldap/ldap_common.h"
#include "providers/fail_over.h"
#include "providers/ldap/sdap_async_private.h"
+#include "providers/krb5/krb5_common.h"
#include "util/sss_krb5.h"
@@ -420,6 +421,176 @@ static void sdap_uri_callback(void *private_data, struct fo_server *server)
service->uri = new_uri;
}
+static void sdap_finalize(struct tevent_context *ev,
+ struct tevent_signal *se,
+ int signum,
+ int count,
+ void *siginfo,
+ void *private_data)
+{
+ char *realm = (char *) private_data;
+ int ret;
+
+ ret = remove_krb5_info_files(se, realm);
+ if (ret != EOK) {
+ DEBUG(1, ("remove_krb5_info_files failed.\n"));
+ }
+
+ sig_term(signum);
+}
+
+errno_t sdap_install_sigterm_handler(TALLOC_CTX *mem_ctx,
+ struct tevent_context *ev,
+ const char *realm)
+{
+ char *sig_realm;
+ struct tevent_signal *sige;
+
+ BlockSignals(false, SIGTERM);
+
+ sig_realm = talloc_strdup(mem_ctx, realm);
+ if (sig_realm == NULL) {
+ DEBUG(1, ("talloc_strdup failed!\n"));
+ return ENOMEM;
+ }
+
+ sige = tevent_add_signal(ev, mem_ctx, SIGTERM, SA_SIGINFO, sdap_finalize,
+ sig_realm);
+ if (sige == NULL) {
+ DEBUG(1, ("tevent_add_signal failed.\n"));
+ talloc_free(sig_realm);
+ return ENOMEM;
+ }
+ talloc_steal(sige, sig_realm);
+
+ return EOK;
+}
+
+void sdap_remove_kdcinfo_files_callback(void *pvt)
+{
+ int ret;
+ TALLOC_CTX *tmp_ctx = NULL;
+ struct remove_info_files_ctx *ctx = talloc_get_type(pvt,
+ struct remove_info_files_ctx);
+
+ ret = be_fo_run_callbacks_at_next_request(ctx->be_ctx,
+ ctx->kdc_service_name);
+ if (ret != EOK) {
+ DEBUG(1, ("be_fo_run_callbacks_at_next_request failed, "
+ "krb5 info files will not be removed, because "
+ "it is unclear if they will be recreated properly.\n"));
+ return;
+ }
+
+ tmp_ctx = talloc_new(NULL);
+ if (tmp_ctx == NULL) {
+ DEBUG(1, ("talloc_new failed, cannot remove krb5 info files.\n"));
+ return;
+ }
+
+ ret = remove_krb5_info_files(tmp_ctx, ctx->realm);
+ if (ret != EOK) {
+ DEBUG(1, ("remove_krb5_info_files failed.\n"));
+ }
+
+ talloc_zfree(tmp_ctx);
+}
+
+
+errno_t sdap_install_offline_callback(TALLOC_CTX *mem_ctx,
+ struct be_ctx *be_ctx,
+ const char *realm,
+ const char *service_name)
+{
+ int ret;
+ struct remove_info_files_ctx *ctx;
+
+ ctx = talloc_zero(mem_ctx, struct remove_info_files_ctx);
+ if (ctx == NULL) {
+ DEBUG(1, ("talloc_zfree failed.\n"));
+ return ENOMEM;
+ }
+
+ ctx->be_ctx = be_ctx;
+ ctx->realm = talloc_strdup(ctx, realm);
+ ctx->kdc_service_name = talloc_strdup(ctx, service_name);
+ if (ctx->realm == NULL || ctx->kdc_service_name == NULL) {
+ DEBUG(1, ("talloc_strdup failed!\n"));
+ ret = ENOMEM;
+ goto done;
+ }
+
+ ret = be_add_offline_cb(ctx, be_ctx,
+ sdap_remove_kdcinfo_files_callback,
+ ctx, NULL);
+ if (ret != EOK) {
+ DEBUG(1, ("be_add_offline_cb failed.\n"));
+ goto done;
+ }
+
+ ret = EOK;
+done:
+ if (ret != EOK) {
+ talloc_zfree(ctx);
+ }
+ return ret;
+}
+
+int sdap_gssapi_init(TALLOC_CTX *mem_ctx,
+ struct dp_option *opts,
+ struct be_ctx *bectx,
+ struct sdap_service *sdap_service,
+ struct krb5_service **krb5_service)
+{
+ int ret;
+ const char *krb5_servers;
+ const char *krb5_realm;
+ struct krb5_service *service = NULL;
+
+ krb5_servers = dp_opt_get_string(opts, SDAP_KRB5_KDCIP);
+ if (krb5_servers == NULL) {
+ DEBUG(1, ("Missing krb5_kdcip option, using service discovery!\n"));
+ }
+
+ krb5_realm = dp_opt_get_string(opts, SDAP_KRB5_REALM);
+ if (krb5_realm == NULL) {
+ DEBUG(0, ("Missing krb5_realm option, will use libkrb default\n"));
+ }
+
+ ret = krb5_service_init(mem_ctx, bectx, SSS_KRB5KDC_FO_SRV, krb5_servers,
+ krb5_realm, &service);
+ if (ret != EOK) {
+ DEBUG(0, ("Failed to init KRB5 failover service!\n"));
+ goto done;
+ }
+
+ ret = sdap_install_sigterm_handler(mem_ctx, bectx->ev, krb5_realm);
+ if (ret != EOK) {
+ DEBUG(0, ("Failed to install sigterm handler\n"));
+ goto done;
+ }
+
+ ret = sdap_install_offline_callback(mem_ctx, bectx,
+ krb5_realm, SSS_KRB5KDC_FO_SRV);
+ if (ret != EOK) {
+ DEBUG(0, ("Failed to install sigterm handler\n"));
+ goto done;
+ }
+
+ sdap_service->kinit_service_name = talloc_strdup(sdap_service,
+ service->name);
+ if (sdap_service->kinit_service_name == NULL) {
+ ret = ENOMEM;
+ goto done;
+ }
+
+ ret = EOK;
+ *krb5_service = service;
+done:
+ if (ret != EOK) talloc_free(service);
+ return ret;
+}
+
int sdap_service_init(TALLOC_CTX *memctx, struct be_ctx *ctx,
const char *service_name, const char *dns_service_name,
const char *urls, struct sdap_service **_service)
diff --git a/src/providers/ldap/ldap_common.h b/src/providers/ldap/ldap_common.h
index 2a0e9767d..e2d74e411 100644
--- a/src/providers/ldap/ldap_common.h
+++ b/src/providers/ldap/ldap_common.h
@@ -26,6 +26,7 @@
#include "providers/ldap/sdap.h"
#include "providers/ldap/sdap_id_op.h"
#include "providers/fail_over.h"
+#include "providers/krb5/krb5_common.h"
#define PWD_POL_OPT_NONE "none"
#define PWD_POL_OPT_SHADOW "shadow"
@@ -44,6 +45,8 @@ struct sdap_id_ctx {
/* what rootDSE returns */
struct sysdb_attrs *rootDSE;
+ /* If using GSSAPI */
+ struct krb5_service *krb5_service;
/* LDAP connection cache */
struct sdap_id_conn_cache *conn_cache;
@@ -86,6 +89,23 @@ int sdap_service_init(TALLOC_CTX *memctx, struct be_ctx *ctx,
const char *service_name, const char *dns_service_name,
const char *urls, struct sdap_service **_service);
+int sdap_gssapi_init(TALLOC_CTX *mem_ctx,
+ struct dp_option *opts,
+ struct be_ctx *bectx,
+ struct sdap_service *sdap_service,
+ struct krb5_service **krb5_service);
+
+errno_t sdap_install_offline_callback(TALLOC_CTX *mem_ctx,
+ struct be_ctx *be_ctx,
+ const char *realm,
+ const char *service_name);
+
+errno_t sdap_install_sigterm_handler(TALLOC_CTX *mem_ctx,
+ struct tevent_context *ev,
+ const char *realm);
+
+void sdap_remove_kdcinfo_files_callback(void *pvt);
+
/* options parser */
int ldap_get_options(TALLOC_CTX *memctx,
struct confdb_ctx *cdb,
diff --git a/src/providers/ldap/ldap_init.c b/src/providers/ldap/ldap_init.c
index b0b967d07..86598cac9 100644
--- a/src/providers/ldap/ldap_init.c
+++ b/src/providers/ldap/ldap_init.c
@@ -98,6 +98,17 @@ int sssm_ldap_id_init(struct be_ctx *bectx,
goto done;
}
+ if (dp_opt_get_bool(ctx->opts->basic, SDAP_KRB5_KINIT)) {
+ ret = sdap_gssapi_init(ctx, ctx->opts->basic,
+ ctx->be, ctx->service,
+ &ctx->krb5_service);
+ if (ret != EOK) {
+ DEBUG(1, ("sdap_gssapi_init failed [%d][%s].\n",
+ ret, strerror(ret)));
+ goto done;
+ }
+ }
+
ret = setup_tls_config(ctx->opts->basic);
if (ret != EOK) {
DEBUG(1, ("setup_tls_config failed [%d][%s].\n",
diff --git a/src/providers/ldap/sdap.h b/src/providers/ldap/sdap.h
index a5fab7a92..2b4318e6a 100644
--- a/src/providers/ldap/sdap.h
+++ b/src/providers/ldap/sdap.h
@@ -106,6 +106,7 @@ struct sdap_handle {
struct sdap_service {
char *name;
char *uri;
+ char *kinit_service_name;
};
struct sdap_ppolicy_data {
diff --git a/src/providers/ldap/sdap_async.h b/src/providers/ldap/sdap_async.h
index e5a60daa0..20888011b 100644
--- a/src/providers/ldap/sdap_async.h
+++ b/src/providers/ldap/sdap_async.h
@@ -61,12 +61,15 @@ int sdap_get_groups_recv(struct tevent_req *req,
struct tevent_req *sdap_kinit_send(TALLOC_CTX *memctx,
struct tevent_context *ev,
+ struct be_ctx *be,
struct sdap_handle *sh,
+ const char *service_name,
int timeout,
const char *keytab,
const char *principal,
const char *realm,
int lifetime);
+
int sdap_kinit_recv(struct tevent_req *req,
enum sdap_result *result,
time_t *expire_time);
diff --git a/src/providers/ldap/sdap_async_connection.c b/src/providers/ldap/sdap_async_connection.c
index 3c536a474..b62050521 100644
--- a/src/providers/ldap/sdap_async_connection.c
+++ b/src/providers/ldap/sdap_async_connection.c
@@ -627,15 +627,30 @@ static int sasl_bind_recv(struct tevent_req *req, int *ldaperr)
/* ==Perform-Kinit-given-keytab-and-principal============================= */
struct sdap_kinit_state {
+ const char *keytab;
+ const char *principal;
+ const char *realm;
+ int timeout;
+ int lifetime;
+
+ const char *krb_service_name;
+ struct tevent_context *ev;
+ struct be_ctx *be;
+
+ struct fo_server *kdc_srv;
int result;
time_t expire_time;
};
static void sdap_kinit_done(struct tevent_req *subreq);
+static struct tevent_req *sdap_kinit_next_kdc(struct tevent_req *req);
+static void sdap_kinit_kdc_resolved(struct tevent_req *subreq);
struct tevent_req *sdap_kinit_send(TALLOC_CTX *memctx,
struct tevent_context *ev,
+ struct be_ctx *be,
struct sdap_handle *sh,
+ const char *krb_service_name,
int timeout,
const char *keytab,
const char *principal,
@@ -659,26 +674,83 @@ struct tevent_req *sdap_kinit_send(TALLOC_CTX *memctx,
if (!req) return NULL;
state->result = SDAP_AUTH_FAILED;
+ state->keytab = keytab;
+ state->principal = principal;
+ state->realm = realm;
+ state->ev = ev;
+ state->be = be;
+ state->timeout = timeout;
+ state->lifetime = lifetime;
+ state->krb_service_name = krb_service_name;
if (keytab) {
ret = setenv("KRB5_KTNAME", keytab, 1);
if (ret == -1) {
DEBUG(2, ("Failed to set KRB5_KTNAME to %s\n", keytab));
+ talloc_free(req);
return NULL;
}
}
- subreq = sdap_get_tgt_send(state, ev, realm, principal, keytab, lifetime,
- timeout);
+ subreq = sdap_kinit_next_kdc(req);
if (!subreq) {
- talloc_zfree(req);
+ talloc_free(req);
return NULL;
}
- tevent_req_set_callback(subreq, sdap_kinit_done, req);
return req;
}
+static struct tevent_req *sdap_kinit_next_kdc(struct tevent_req *req)
+{
+ struct tevent_req *next_req;
+ struct sdap_kinit_state *state = tevent_req_data(req,
+ struct sdap_kinit_state);
+
+ DEBUG(7, ("Resolving next KDC for service %s\n", state->krb_service_name));
+
+ next_req = be_resolve_server_send(state, state->ev,
+ state->be,
+ state->krb_service_name);
+ if (next_req == NULL) {
+ DEBUG(1, ("be_resolve_server_send failed.\n"));
+ return NULL;
+ }
+ tevent_req_set_callback(next_req, sdap_kinit_kdc_resolved, req);
+
+ return next_req;
+}
+
+static void sdap_kinit_kdc_resolved(struct tevent_req *subreq)
+{
+ struct tevent_req *req = tevent_req_callback_data(subreq,
+ struct tevent_req);
+ struct sdap_kinit_state *state = tevent_req_data(req,
+ struct sdap_kinit_state);
+ struct tevent_req *tgtreq;
+ int ret;
+
+ ret = be_resolve_server_recv(subreq, &state->kdc_srv);
+ talloc_zfree(subreq);
+ if (ret != EOK) {
+ /* all servers have been tried and none
+ * was found good, go offline */
+ tevent_req_error(req, EIO);
+ return;
+ }
+
+ DEBUG(7, ("KDC resolved, attempting to get TGT...\n"));
+
+ tgtreq = sdap_get_tgt_send(state, state->ev, state->realm,
+ state->principal, state->keytab,
+ state->lifetime, state->timeout);
+ if (!tgtreq) {
+ tevent_req_error(req, ENOMEM);
+ return;
+ }
+ tevent_req_set_callback(tgtreq, sdap_kinit_done, req);
+}
+
static void sdap_kinit_done(struct tevent_req *subreq)
{
struct tevent_req *req = tevent_req_callback_data(subreq,
@@ -691,6 +763,7 @@ static void sdap_kinit_done(struct tevent_req *subreq)
char *ccname = NULL;
time_t expire_time;
krb5_error_code kerr;
+ struct tevent_req *nextreq;
ret = sdap_get_tgt_recv(subreq, state, &result,
&kerr, &ccname, &expire_time);
@@ -714,6 +787,15 @@ static void sdap_kinit_done(struct tevent_req *subreq)
state->result = SDAP_AUTH_SUCCESS;
tevent_req_done(req);
return;
+ } else {
+ if (kerr == KRB5_KDC_UNREACH) {
+ nextreq = sdap_kinit_next_kdc(req);
+ if (!nextreq) {
+ tevent_req_error(req, ENOMEM);
+ }
+ return;
+ }
+
}
DEBUG(4, ("Could not get TGT: %d [%s]\n", result, strerror(result)));
@@ -1152,7 +1234,9 @@ static void sdap_cli_kinit_step(struct tevent_req *req)
struct tevent_req *subreq;
subreq = sdap_kinit_send(state, state->ev,
+ state->be,
state->sh,
+ state->service->kinit_service_name,
dp_opt_get_int(state->opts->basic,
SDAP_OPT_TIMEOUT),
dp_opt_get_string(state->opts->basic,