summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--Makefile.am1
-rw-r--r--src/config/SSSDConfig.py1
-rwxr-xr-xsrc/config/SSSDConfigTest.py9
-rw-r--r--src/config/etc/sssd.api.d/sssd-krb5.conf1
-rw-r--r--src/external/krb5.m44
-rw-r--r--src/man/sssd-krb5.5.xml35
-rw-r--r--src/providers/ipa/ipa_common.c3
-rw-r--r--src/providers/ipa/ipa_common.h2
-rw-r--r--src/providers/ipa/ipa_init.c3
-rw-r--r--src/providers/krb5/krb5_auth.c12
-rw-r--r--src/providers/krb5/krb5_child.c313
-rw-r--r--src/providers/krb5/krb5_common.c24
-rw-r--r--src/providers/krb5/krb5_common.h6
-rw-r--r--src/providers/krb5/krb5_init.c2
-rw-r--r--src/util/sss_krb5.c48
-rw-r--r--src/util/sss_krb5.h14
16 files changed, 458 insertions, 20 deletions
diff --git a/Makefile.am b/Makefile.am
index 6a12fe40c..e354de99c 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -520,6 +520,7 @@ krb5_utils_tests_SOURCES = \
src/tests/krb5_utils-tests.c \
src/providers/krb5/krb5_utils.c \
src/providers/krb5/krb5_common.c \
+ src/util/sss_krb5.c \
src/providers/data_provider_fo.c \
src/providers/data_provider_opts.c \
src/providers/data_provider_callbacks.c \
diff --git a/src/config/SSSDConfig.py b/src/config/SSSDConfig.py
index 9584de176..18d8e9d3d 100644
--- a/src/config/SSSDConfig.py
+++ b/src/config/SSSDConfig.py
@@ -107,6 +107,7 @@ option_strings = {
'krb5_renewable_lifetime' : _("Renewable lifetime of the TGT"),
'krb5_lifetime' : _("Lifetime of the TGT"),
'krb5_renew_interval' : _("Time between two checks for renewal"),
+ 'krb5_use_fast' : _("Enables FAST"),
# [provider/krb5/chpass]
'krb5_kpasswd' : _('Server where the change password service is running if not on the KDC'),
diff --git a/src/config/SSSDConfigTest.py b/src/config/SSSDConfigTest.py
index b51614da6..8991f3655 100755
--- a/src/config/SSSDConfigTest.py
+++ b/src/config/SSSDConfigTest.py
@@ -552,7 +552,8 @@ class SSSDConfigTestSSSDDomain(unittest.TestCase):
'krb5_auth_timeout',
'krb5_renewable_lifetime',
'krb5_lifetime',
- 'krb5_renew_interval'])
+ 'krb5_renew_interval',
+ 'krb5_use_fast'])
options = domain.list_options()
@@ -729,7 +730,8 @@ class SSSDConfigTestSSSDDomain(unittest.TestCase):
'krb5_auth_timeout',
'krb5_renewable_lifetime',
'krb5_lifetime',
- 'krb5_renew_interval']
+ 'krb5_renew_interval',
+ 'krb5_use_fast']
self.assertTrue(type(options) == dict,
"Options should be a dictionary")
@@ -880,7 +882,8 @@ class SSSDConfigTestSSSDDomain(unittest.TestCase):
'krb5_auth_timeout',
'krb5_renewable_lifetime',
'krb5_lifetime',
- 'krb5_renew_interval'])
+ 'krb5_renew_interval',
+ 'krb5_use_fast'])
options = domain.list_options()
diff --git a/src/config/etc/sssd.api.d/sssd-krb5.conf b/src/config/etc/sssd.api.d/sssd-krb5.conf
index 86eff20e6..bb3a077d2 100644
--- a/src/config/etc/sssd.api.d/sssd-krb5.conf
+++ b/src/config/etc/sssd.api.d/sssd-krb5.conf
@@ -14,6 +14,7 @@ krb5_store_password_if_offline = bool, None, false
krb5_renewable_lifetime = str, None, false
krb5_lifetime = str, None, false
krb5_renew_interval = int, None, false
+krb5_use_fast = str, None, false
[provider/krb5/chpass]
diff --git a/src/external/krb5.m4 b/src/external/krb5.m4
index d4f563fa2..d248cd7d0 100644
--- a/src/external/krb5.m4
+++ b/src/external/krb5.m4
@@ -39,7 +39,9 @@ LIBS="$LIBS $KRB5_LIBS"
AC_CHECK_HEADERS([krb5.h krb5/krb5.h])
AC_CHECK_FUNCS([krb5_get_init_creds_opt_alloc krb5_get_error_message \
krb5_free_unparsed_name \
- krb5_get_init_creds_opt_set_expire_callback])
+ krb5_get_init_creds_opt_set_expire_callback \
+ krb5_get_init_creds_opt_set_fast_ccache_name \
+ krb5_get_init_creds_opt_set_fast_flags])
CFLAGS=$SAVE_CFLAGS
LIBS=$SAVE_LIBS
diff --git a/src/man/sssd-krb5.5.xml b/src/man/sssd-krb5.5.xml
index d1341d9b2..5219086b2 100644
--- a/src/man/sssd-krb5.5.xml
+++ b/src/man/sssd-krb5.5.xml
@@ -358,6 +358,41 @@
</listitem>
</varlistentry>
+ <varlistentry>
+ <term>krb5_use_fast (string)</term>
+ <listitem>
+ <para>
+ Enables flexible authentication secure tunneling
+ (FAST) for Kerberos pre-authentication. The
+ following options are supported:
+ </para>
+ <para>
+ <emphasis>never</emphasis> use FAST, this is
+ equivalent to not set this option at all.
+ </para>
+ <para>
+ <emphasis>try</emphasis> to use FAST, if the server
+ does not support fast continue without.
+ </para>
+ <para>
+ <emphasis>demand</emphasis> to use FAST, fail if the
+ server does not require fast.
+ </para>
+ <para>
+ Default: not set, i.e. FAST is not used.
+ </para>
+ <para>
+ Please note that a keytab is required to use fast.
+ </para>
+ <para>
+ Please note also that sssd supports fast only with
+ MIT Kerberos version 1.8 and above. If sssd used
+ used with an older version using this option is a
+ configuration error.
+ </para>
+ </listitem>
+ </varlistentry>
+
</variablelist>
</para>
</refsect1>
diff --git a/src/providers/ipa/ipa_common.c b/src/providers/ipa/ipa_common.c
index 8da83ee08..35583af21 100644
--- a/src/providers/ipa/ipa_common.c
+++ b/src/providers/ipa/ipa_common.c
@@ -146,7 +146,8 @@ struct dp_option ipa_def_krb5_opts[] = {
{ "krb5_store_password_if_offline", DP_OPT_BOOL, BOOL_FALSE, BOOL_FALSE },
{ "krb5_renewable_lifetime", DP_OPT_STRING, NULL_STRING, NULL_STRING },
{ "krb5_lifetime", DP_OPT_STRING, NULL_STRING, NULL_STRING },
- { "krb5_renew_interval", DP_OPT_NUMBER, NULL_NUMBER, NULL_NUMBER }
+ { "krb5_renew_interval", DP_OPT_NUMBER, NULL_NUMBER, NULL_NUMBER },
+ { "krb5_use_fast", DP_OPT_STRING, NULL_STRING, NULL_STRING }
};
int ipa_get_options(TALLOC_CTX *memctx,
diff --git a/src/providers/ipa/ipa_common.h b/src/providers/ipa/ipa_common.h
index 451a1534d..4d79c03c5 100644
--- a/src/providers/ipa/ipa_common.h
+++ b/src/providers/ipa/ipa_common.h
@@ -40,7 +40,7 @@ struct ipa_service {
/* the following define is used to keep track of the options in the krb5
* module, so that if they change and ipa is not updated correspondingly
* this will trigger a runtime abort error */
-#define IPA_KRB5_OPTS_TEST 12
+#define IPA_KRB5_OPTS_TEST 13
enum ipa_basic_opt {
IPA_DOMAIN = 0,
diff --git a/src/providers/ipa/ipa_init.c b/src/providers/ipa/ipa_init.c
index c172eac13..f6769eebb 100644
--- a/src/providers/ipa/ipa_init.c
+++ b/src/providers/ipa/ipa_init.c
@@ -289,7 +289,8 @@ int sssm_ipa_auth_init(struct be_ctx *bectx,
}
}
- ret = check_and_export_options(krb5_auth_ctx->opts, bectx->domain);
+ ret = check_and_export_options(krb5_auth_ctx->opts, bectx->domain,
+ krb5_auth_ctx);
if (ret != EOK) {
DEBUG(1, ("check_and_export_opts failed.\n"));
goto done;
diff --git a/src/providers/krb5/krb5_auth.c b/src/providers/krb5/krb5_auth.c
index 515c181bc..e6b680eaf 100644
--- a/src/providers/krb5/krb5_auth.c
+++ b/src/providers/krb5/krb5_auth.c
@@ -646,14 +646,16 @@ static void krb5_find_ccache_step(struct tevent_req *req)
}
/* We need to keep the root privileges to read the keytab file if
- * validation is enabled, otherwise we can drop them and run krb5_child
- * with user privileges.
+ * validation or FAST is enabled, otherwise we can drop them and run
+ * krb5_child with user privileges.
* If we are offline we want to create an empty ccache file. In this
* case we can drop the privileges, too. */
- if (!dp_opt_get_bool(kr->krb5_ctx->opts, KRB5_VALIDATE) || kr->is_offline) {
- kr->run_as_user = true;
- } else {
+ if ((dp_opt_get_bool(kr->krb5_ctx->opts, KRB5_VALIDATE) ||
+ kr->krb5_ctx->use_fast) &&
+ !kr->is_offline) {
kr->run_as_user = false;
+ } else {
+ kr->run_as_user = true;
}
subreq = handle_child_send(state, state->ev, kr);
diff --git a/src/providers/krb5/krb5_child.c b/src/providers/krb5/krb5_child.c
index 861159573..44853e76d 100644
--- a/src/providers/krb5/krb5_child.c
+++ b/src/providers/krb5/krb5_child.c
@@ -90,6 +90,7 @@ struct krb5_req {
char *ccname;
char *keytab;
bool validate;
+ char *fast_ccname;
const char *upn;
uid_t uid;
@@ -491,6 +492,85 @@ static errno_t add_ticket_times_to_response(struct krb5_req *kr)
return ret;
}
+static krb5_error_code find_principal_in_keytab(krb5_context ctx,
+ krb5_keytab keytab,
+ const char *realm,
+ krb5_principal *princ)
+{
+ krb5_error_code kerr;
+ krb5_error_code kt_err;
+ krb5_error_code kerr_d;
+ krb5_kt_cursor cursor;
+ krb5_keytab_entry entry;
+ bool principal_found = false;
+
+ memset(&cursor, 0, sizeof(cursor));
+ kerr = krb5_kt_start_seq_get(ctx, keytab, &cursor);
+ if (kerr != 0) {
+ DEBUG(1, ("krb5_kt_start_seq_get failed.\n"));
+ KRB5_DEBUG(1, kerr);
+ return kerr;
+ }
+
+ /* We look for the first entry from our realm or take the last one */
+ memset(&entry, 0, sizeof(entry));
+ while ((kt_err = krb5_kt_next_entry(ctx, keytab, &entry, &cursor)) == 0) {
+ if (krb5_princ_realm(ctx, entry.principal)->length == strlen(realm) &&
+ strncmp(krb5_princ_realm(ctx, entry.principal)->data, realm,
+ krb5_princ_realm(ctx, entry.principal)->length) == 0) {
+ DEBUG(9, ("Found keytab entry with the realm of the credential.\n"));
+ principal_found = true;
+ break;
+ }
+
+ kerr = krb5_free_keytab_entry_contents(ctx, &entry);
+ if (kerr != 0) {
+ DEBUG(1, ("Failed to free keytab entry.\n"));
+ }
+ memset(&entry, 0, sizeof(entry));
+ }
+
+ /* Close the keytab here. Even though we're using cursors, the file
+ * handle is stored in the krb5_keytab structure, and it gets
+ * overwritten by other keytab calls, creating a leak. */
+ kerr = krb5_kt_end_seq_get(ctx, keytab, &cursor);
+ if (kerr != 0) {
+ DEBUG(1, ("krb5_kt_end_seq_get failed.\n"));
+ goto done;
+ }
+
+ if (!principal_found) {
+ kerr = KRB5_KT_NOTFOUND;
+ DEBUG(1, ("No principal from realm [%s] found in keytab.\n", realm));
+ goto done;
+ }
+
+ /* check if we got any errors from krb5_kt_next_entry */
+ if (kt_err != 0 && kt_err != KRB5_KT_END) {
+ DEBUG(1, ("Error while reading keytab.\n"));
+ KRB5_DEBUG(1, kerr);
+ goto done;
+ }
+
+ kerr = krb5_copy_principal(ctx, entry.principal, princ);
+ if (kerr != 0) {
+ DEBUG(1, ("krb5_copy_principal failed.\n"));
+ KRB5_DEBUG(1, kerr);
+ goto done;
+ }
+
+ kerr = 0;
+
+done:
+ kerr_d = krb5_free_keytab_entry_contents(ctx, &entry);
+ if (kerr_d != 0) {
+ DEBUG(1, ("Failed to free keytab entry.\n"));
+ KRB5_DEBUG(1, kerr_d);
+ }
+
+ return kerr;
+}
+
static krb5_error_code validate_tgt(struct krb5_req *kr)
{
krb5_error_code kerr;
@@ -584,6 +664,43 @@ done:
}
+static krb5_error_code get_and_save_tgt_with_keytab(krb5_context ctx,
+ krb5_principal princ,
+ krb5_keytab keytab,
+ char *ccname)
+{
+ krb5_error_code kerr = 0;
+ krb5_creds creds;
+ krb5_get_init_creds_opt options;
+
+ memset(&creds, 0, sizeof(creds));
+ memset(&options, 0, sizeof(options));
+
+ krb5_get_init_creds_opt_set_address_list(&options, NULL);
+ krb5_get_init_creds_opt_set_forwardable(&options, 0);
+ krb5_get_init_creds_opt_set_proxiable(&options, 0);
+
+ kerr = krb5_get_init_creds_keytab(ctx, &creds, princ, keytab, 0, NULL,
+ &options);
+ if (kerr != 0) {
+ KRB5_DEBUG(1, kerr);
+ return kerr;
+ }
+
+ kerr = create_ccache_file(ctx, princ, ccname, &creds);
+ if (kerr != 0) {
+ KRB5_DEBUG(1, kerr);
+ goto done;
+ }
+ kerr = 0;
+
+done:
+ krb5_free_cred_contents(ctx, &creds);
+
+ return kerr;
+
+}
+
static krb5_error_code get_and_save_tgt(struct krb5_req *kr,
char *password)
{
@@ -612,16 +729,19 @@ static krb5_error_code get_and_save_tgt(struct krb5_req *kr,
return kerr;
}
+ } else {
+ DEBUG(9, ("TGT validation is disabled.\n"));
+ }
+
+ if (kr->validate || kr->fast_ccname != NULL) {
/* We drop root privileges which were needed to read the keytab file
- * for the validation validation of the credentials here to run the
+ * for the validation of the credentials or for FAST here to run the
* ccache I/O operations with user privileges. */
ret = become_user(kr->uid, kr->gid);
if (ret != EOK) {
DEBUG(1, ("become_user failed.\n"));
return ret;
}
- } else {
- DEBUG(9, ("TGT validation is disabled.\n"));
}
kerr = create_ccache_file(kr->ctx, kr->princ, kr->ccname, kr->creds);
@@ -958,7 +1078,7 @@ static errno_t renew_tgt_child(int fd, struct krb5_req *kr)
DEBUG(9, ("TGT validation is disabled.\n"));
}
- if (kr->validate) {
+ if (kr->validate || kr->fast_ccname != NULL) {
/* We drop root privileges which were needed to read the keytab file
* for the validation of the credentials or for FAST here to run the
* ccache I/O operations with user privileges. */
@@ -1126,10 +1246,153 @@ static int krb5_cleanup(void *ptr)
return EOK;
}
+static krb5_error_code get_tgt_times(krb5_context ctx, const char *ccname,
+ krb5_principal server_principal,
+ krb5_principal client_principal,
+ krb5_ticket_times *tgtt)
+{
+ krb5_error_code krberr;
+ krb5_ccache ccache = NULL;
+ krb5_creds mcred;
+ krb5_creds cred;
+
+ krberr = krb5_cc_resolve(ctx, ccname, &ccache);
+ if (krberr != 0) {
+ DEBUG(1, ("krb5_cc_resolve failed.\n"));
+ goto done;
+ }
+
+ memset(&mcred, 0, sizeof(mcred));
+ memset(&cred, 0, sizeof(mcred));
+
+ mcred.server = server_principal;
+ mcred.client = client_principal;
+
+ krberr = krb5_cc_retrieve_cred(ctx, ccache, 0, &mcred, &cred);
+ if (krberr != 0) {
+ DEBUG(1, ("krb5_cc_retrieve_cred failed.\n"));
+ krberr = 0;
+ goto done;
+ }
+
+ tgtt->authtime = cred.times.authtime;
+ tgtt->starttime = cred.times.starttime;
+ tgtt->endtime = cred.times.endtime;
+ tgtt->renew_till = cred.times.renew_till;
+
+ krb5_free_cred_contents(ctx, &cred);
+
+ krberr = 0;
+
+done:
+ if (ccache != NULL) {
+ krb5_cc_close(ctx, ccache);
+ }
+
+ return krberr;
+}
+
+static krb5_error_code check_fast_ccache(krb5_context ctx, const char *realm,
+ const char *keytab_name,
+ TALLOC_CTX *mem_ctx,
+ char **fast_ccname)
+{
+ TALLOC_CTX *tmp_ctx = NULL;
+ krb5_error_code kerr;
+ char *ccname;
+ char *server_name;
+ krb5_ticket_times tgtt;
+ krb5_keytab keytab = NULL;
+ krb5_principal client_princ = NULL;
+ krb5_principal server_princ = NULL;
+
+ tmp_ctx = talloc_new(NULL);
+ if (tmp_ctx == NULL) {
+ DEBUG(1, ("talloc_new failed.\n"));
+ kerr = ENOMEM;
+ goto done;
+ }
+
+ ccname = talloc_asprintf(tmp_ctx, "FILE:%s/fast_ccache_%s", DB_PATH, realm);
+ if (ccname == NULL) {
+ DEBUG(1, ("talloc_asprintf failed.\n"));
+ kerr = ENOMEM;
+ goto done;
+ }
+
+ if (keytab_name != NULL) {
+ kerr = krb5_kt_resolve(ctx, keytab_name, &keytab);
+ } else {
+ kerr = krb5_kt_default(ctx, &keytab);
+ }
+ if (kerr) {
+ DEBUG(0, ("Failed to read keytab file [%s].\n",
+ keytab_name != NULL ? keytab_name : "(default)"));
+ goto done;
+ }
+
+ kerr = find_principal_in_keytab(ctx, keytab, realm, &client_princ);
+ if (kerr != 0) {
+ DEBUG(1, ("find_principal_in_keytab 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"));
+ kerr = ENOMEM;
+ goto done;
+ }
+
+ kerr = krb5_parse_name(ctx, server_name, &server_princ);
+ if (kerr != 0) {
+ DEBUG(1, ("krb5_parse_name failed.\n"));
+ goto done;
+ }
+
+ memset(&tgtt, 0, sizeof(tgtt));
+ kerr = get_tgt_times(ctx, ccname, server_princ, client_princ, &tgtt);
+ if (kerr == 0) {
+ if (tgtt.endtime > time(NULL)) {
+ DEBUG(5, ("FAST TGT is still valid.\n"));
+ goto done;
+ }
+ }
+
+ kerr = get_and_save_tgt_with_keytab(ctx, client_princ, keytab, ccname);
+ if (kerr != 0) {
+ DEBUG(1, ("get_and_save_tgt_with_keytab failed.\n"));
+ goto done;
+ }
+
+
+ kerr = 0;
+
+done:
+ if (client_princ != NULL) {
+ krb5_free_principal(ctx, client_princ);
+ }
+ if (server_princ != NULL) {
+ krb5_free_principal(ctx, server_princ);
+ }
+
+ if (kerr == 0) {
+ *fast_ccname = talloc_steal(mem_ctx, ccname);
+ }
+ talloc_free(tmp_ctx);
+
+ if (keytab != NULL) {
+ krb5_kt_close(ctx, keytab);
+ }
+
+ return kerr;
+}
+
static int krb5_child_setup(struct krb5_req *kr, uint32_t offline)
{
krb5_error_code kerr = 0;
char *lifetime_str;
+ char *use_fast_str;
krb5_deltat lifetime;
kr->krb5_ctx = talloc_zero(kr, struct krb5_child_ctx);
@@ -1239,6 +1502,48 @@ static int krb5_child_setup(struct krb5_req *kr, uint32_t offline)
krb5_get_init_creds_opt_set_tkt_life(kr->options, lifetime);
}
+ if (!offline) {
+ use_fast_str = getenv(SSSD_KRB5_USE_FAST);
+ if (use_fast_str == NULL || strcasecmp(use_fast_str, "never") == 0) {
+ DEBUG(9, ("Not using FAST.\n"));
+ } else if (strcasecmp(use_fast_str, "try") == 0 ||
+ strcasecmp(use_fast_str, "demand") == 0) {
+ kerr = check_fast_ccache(kr->ctx, kr->krb5_ctx->realm, kr->keytab,
+ kr, &kr->fast_ccname);
+ if (kerr != 0) {
+ DEBUG(1, ("check_fast_ccache failed.\n"));
+ KRB5_DEBUG(1, kerr);
+ goto failed;
+ }
+
+ kerr = sss_krb5_get_init_creds_opt_set_fast_ccache_name(kr->ctx,
+ kr->options,
+ kr->fast_ccname);
+ if (kerr != 0) {
+ DEBUG(1, ("sss_krb5_get_init_creds_opt_set_fast_ccache_name "
+ "failed.\n"));
+ KRB5_DEBUG(1, kerr);
+ goto failed;
+ }
+
+ if (strcasecmp(use_fast_str, "demand") == 0) {
+ kerr = sss_krb5_get_init_creds_opt_set_fast_flags(kr->ctx,
+ kr->options,
+ KRB5_FAST_REQUIRED);
+ if (kerr != 0) {
+ DEBUG(1, ("sss_krb5_get_init_creds_opt_set_fast_flags "
+ "failed.\n"));
+ KRB5_DEBUG(1, kerr);
+ goto failed;
+ }
+ }
+ } else {
+ DEBUG(1, ("Unsupported value [%s] for krb5_use_fast.\n"));
+ kerr = EINVAL;
+ goto failed;
+ }
+ }
+
/* TODO: set options, e.g.
* krb5_get_init_creds_opt_set_forwardable
* krb5_get_init_creds_opt_set_proxiable
diff --git a/src/providers/krb5/krb5_common.c b/src/providers/krb5/krb5_common.c
index 43535c1ed..25188c5f8 100644
--- a/src/providers/krb5/krb5_common.c
+++ b/src/providers/krb5/krb5_common.c
@@ -43,7 +43,8 @@ struct dp_option default_krb5_opts[] = {
{ "krb5_store_password_if_offline", DP_OPT_BOOL, BOOL_FALSE, BOOL_FALSE },
{ "krb5_renewable_lifetime", DP_OPT_STRING, NULL_STRING, NULL_STRING },
{ "krb5_lifetime", DP_OPT_STRING, NULL_STRING, NULL_STRING },
- { "krb5_renew_interval", DP_OPT_NUMBER, NULL_NUMBER, NULL_NUMBER }
+ { "krb5_renew_interval", DP_OPT_NUMBER, NULL_NUMBER, NULL_NUMBER },
+ { "krb5_use_fast", DP_OPT_STRING, NULL_STRING, NULL_STRING }
};
errno_t check_and_export_lifetime(struct dp_option *opts, const int opt_id,
@@ -100,11 +101,13 @@ done:
errno_t check_and_export_options(struct dp_option *opts,
- struct sss_domain_info *dom)
+ struct sss_domain_info *dom,
+ struct krb5_ctx *krb5_ctx)
{
int ret;
const char *realm;
const char *dummy;
+ char *use_fast_str;
realm = dp_opt_get_cstring(opts, KRB5_REALM);
if (realm == NULL) {
@@ -138,6 +141,23 @@ errno_t check_and_export_options(struct dp_option *opts,
return ret;
}
+
+ use_fast_str = dp_opt_get_string(opts, KRB5_USE_FAST);
+ if (use_fast_str != NULL) {
+ ret = check_fast(use_fast_str, &krb5_ctx->use_fast);
+ if (ret != EOK) {
+ DEBUG(1, ("check_fast failed.\n"));
+ return ret;
+ }
+
+ if (krb5_ctx->use_fast) {
+ ret = setenv(SSSD_KRB5_USE_FAST, use_fast_str, 1);
+ if (ret != EOK) {
+ DEBUG(2, ("setenv [%s] failed.\n", SSSD_KRB5_USE_FAST));
+ }
+ }
+ }
+
dummy = dp_opt_get_cstring(opts, KRB5_KDC);
if (dummy == NULL) {
DEBUG(1, ("No KDC explicitly configured, using defaults.\n"));
diff --git a/src/providers/krb5/krb5_common.h b/src/providers/krb5/krb5_common.h
index c20c7b336..9ca014674 100644
--- a/src/providers/krb5/krb5_common.h
+++ b/src/providers/krb5/krb5_common.h
@@ -37,6 +37,7 @@
#define SSSD_KRB5_REALM "SSSD_KRB5_REALM"
#define SSSD_KRB5_RENEWABLE_LIFETIME "SSSD_KRB5_RENEWABLE_LIFETIME"
#define SSSD_KRB5_LIFETIME "SSSD_KRB5_LIFETIME"
+#define SSSD_KRB5_USE_FAST "SSSD_KRB5_USE_FAST"
#define KDCINFO_TMPL PUBCONF_PATH"/kdcinfo.%s"
#define KPASSWDINFO_TMPL PUBCONF_PATH"/kpasswdinfo.%s"
@@ -57,6 +58,7 @@ enum krb5_opts {
KRB5_RENEWABLE_LIFETIME,
KRB5_LIFETIME,
KRB5_RENEW_INTERVAL,
+ KRB5_USE_FAST,
KRB5_OPTS
};
@@ -114,6 +116,7 @@ struct krb5_ctx {
struct deferred_auth_ctx *deferred_auth_ctx;
struct renew_tgt_ctx *renew_tgt_ctx;
+ bool use_fast;
};
struct remove_info_files_ctx {
@@ -124,7 +127,8 @@ struct remove_info_files_ctx {
};
errno_t check_and_export_options(struct dp_option *opts,
- struct sss_domain_info *dom);
+ struct sss_domain_info *dom,
+ struct krb5_ctx *krb5_ctx);
errno_t krb5_try_kdcip(TALLOC_CTX *memctx, struct confdb_ctx *cdb,
const char *conf_path, struct dp_option *opts);
diff --git a/src/providers/krb5/krb5_init.c b/src/providers/krb5/krb5_init.c
index 0f1ed41fc..525ba4dfc 100644
--- a/src/providers/krb5/krb5_init.c
+++ b/src/providers/krb5/krb5_init.c
@@ -138,7 +138,7 @@ int sssm_krb5_auth_init(struct be_ctx *bectx,
}
}
- ret = check_and_export_options(ctx->opts, bectx->domain);
+ ret = check_and_export_options(ctx->opts, bectx->domain, ctx);
if (ret != EOK) {
DEBUG(1, ("check_and_export_options failed.\n"));
goto fail;
diff --git a/src/util/sss_krb5.c b/src/util/sss_krb5.c
index 7fad32e85..174b6d9fa 100644
--- a/src/util/sss_krb5.c
+++ b/src/util/sss_krb5.c
@@ -361,3 +361,51 @@ krb5_error_code KRB5_CALLCONV sss_krb5_get_init_creds_opt_set_expire_callback(
return 0;
#endif
}
+
+errno_t check_fast(const char *str, bool *use_fast)
+{
+#if HAVE_KRB5_GET_INIT_CREDS_OPT_SET_FAST_FLAGS
+ if (strcasecmp(str, "never") == 0 ) {
+ *use_fast = false;
+ } else if (strcasecmp(str, "try") == 0 || strcasecmp(str, "demand") == 0) {
+ *use_fast = true;
+ } else {
+ sss_log(SSS_LOG_ALERT, "Unsupported value [%s] for option krb5_use_fast,"
+ "please use never, try, or demand.\n");
+ return EINVAL;
+ }
+
+ return EOK;
+#else
+ sss_log(SSS_LOG_ALERT, "This build of sssd done not support FAST. "
+ "Please remove option krb5_use_fast.\n");
+ return EINVAL;
+#endif
+}
+
+krb5_error_code KRB5_CALLCONV sss_krb5_get_init_creds_opt_set_fast_ccache_name(
+ krb5_context context,
+ krb5_get_init_creds_opt *opt,
+ const char *fast_ccache_name)
+{
+#ifdef HAVE_KRB5_GET_INIT_CREDS_OPT_SET_FAST_CCACHE_NAME
+ return krb5_get_init_creds_opt_set_fast_ccache_name(context, opt,
+ fast_ccache_name);
+#else
+ DEBUG(5, ("krb5_get_init_creds_opt_set_fast_ccache_name not available.\n"));
+ return 0;
+#endif
+}
+
+krb5_error_code KRB5_CALLCONV sss_krb5_get_init_creds_opt_set_fast_flags(
+ krb5_context context,
+ krb5_get_init_creds_opt *opt,
+ krb5_flags flags)
+{
+#ifdef HAVE_KRB5_GET_INIT_CREDS_OPT_SET_FAST_FLAGS
+ return krb5_get_init_creds_opt_set_fast_flags(context, opt, flags);
+#else
+ DEBUG(5, ("krb5_get_init_creds_opt_set_fast_flags not available.\n"));
+ return 0;
+#endif
+}
diff --git a/src/util/sss_krb5.h b/src/util/sss_krb5.h
index cf6fedafb..d74df832e 100644
--- a/src/util/sss_krb5.h
+++ b/src/util/sss_krb5.h
@@ -32,6 +32,8 @@
#include <krb5.h>
#endif
+#include "util/util.h"
+
const char * KRB5_CALLCONV sss_krb5_get_error_message (krb5_context,
krb5_error_code);
@@ -67,4 +69,16 @@ krb5_error_code KRB5_CALLCONV sss_krb5_get_init_creds_opt_set_expire_callback(
krb5_get_init_creds_opt *opt,
krb5_expire_callback_func cb,
void *data);
+
+errno_t check_fast(const char *str, bool *use_fast);
+
+krb5_error_code KRB5_CALLCONV sss_krb5_get_init_creds_opt_set_fast_ccache_name(
+ krb5_context context,
+ krb5_get_init_creds_opt *opt,
+ const char *fast_ccache_name);
+
+krb5_error_code KRB5_CALLCONV sss_krb5_get_init_creds_opt_set_fast_flags(
+ krb5_context context,
+ krb5_get_init_creds_opt *opt,
+ krb5_flags flags);
#endif /* __SSS_KRB5_H__ */