#
# Patch to fix the issue where the token expansion for the default client
# keytab path could fail and cause a core dump. Now the error is returned to
# krb5_kt_client_default() but in order for acquire_init_cred() to function
# properly it has to ignore the error returned by krb5_kt_client_default().
# This in turn means that a NULL value in the client_keytab field of a cred
# struct must be handled appropriately.
#
# I have submitted a pull request to MIT with these changes
# https://github.com/krb5/krb5/pull/487
# The final commit was
# https://github.com/krb5/krb5/commit/bd2c2a02e22c609b3c7e9f92d6634e151d14e478
#
# Patch source: in-house
#
--- a/src/include/k5-trace.h
+++ b/src/include/k5-trace.h
@@ -180,6 +180,9 @@ void krb5int_trace(krb5_context context, const char *fmt, ...);
#define TRACE_GIC_PWD_MASTER(c) \
TRACE(c, "Retrying AS request with master KDC")
+#define TRACE_GSS_CLIENT_KEYTAB_FAIL(c, ret) \
+ TRACE(c, "Unable to resolve default client keytab: {kerr}", ret)
+
#define TRACE_ENCTYPE_LIST_UNKNOWN(c, profvar, name) \
TRACE(c, "Unrecognized enctype name in {str}: {str}", profvar, name)
--- a/src/lib/gssapi/krb5/acquire_cred.c
+++ b/src/lib/gssapi/krb5/acquire_cred.c
@@ -348,6 +348,9 @@ can_get_initial_creds(krb5_context context, krb5_gss_cred_id_rec *cred)
if (cred->password != NULL)
return TRUE;
+ if (cred->client_keytab == NULL)
+ return FALSE;
+
/* If we don't know the client principal yet, check for any keytab keys. */
if (cred->name == NULL)
return !krb5_kt_have_content(context, cred->client_keytab);
@@ -522,6 +525,10 @@ get_name_from_client_keytab(krb5_context context, krb5_gss_cred_id_rec *cred)
krb5_principal princ;
assert(cred->name == NULL);
+
+ if (cred->client_keytab == NULL)
+ return KRB5_KT_NOTFOUND;
+
code = k5_kt_get_principal(context, cred->client_keytab, &princ);
if (code)
return code;
@@ -601,9 +608,11 @@ get_initial_cred(krb5_context context, krb5_gss_cred_id_rec *cred)
code = krb5_get_init_creds_password(context, &creds, cred->name->princ,
cred->password, NULL, NULL, 0,
NULL, opt);
- } else {
+ } else if (cred->client_keytab != NULL) {
code = krb5_get_init_creds_keytab(context, &creds, cred->name->princ,
cred->client_keytab, 0, NULL, opt);
+ } else {
+ code = KRB5_KT_NOTFOUND;
}
if (code)
goto cleanup;
@@ -680,10 +689,18 @@ acquire_init_cred(krb5_context context,
goto error;
}
- if (client_keytab != NULL)
+ if (client_keytab != NULL) {
code = krb5_kt_dup(context, client_keytab, &cred->client_keytab);
- else
+ } else {
code = krb5_kt_client_default(context, &cred->client_keytab);
+ if (code) {
+ /* Treat resolution failure similarly to a client keytab which
+ * resolves but doesn't exist or has no content. */
+ TRACE_GSS_CLIENT_KEYTAB_FAIL(context, code);
+ krb5_clear_error_message(context);
+ code = 0;
+ }
+ }
if (code)
goto error;
--- a/src/lib/gssapi/krb5/iakerb.c
+++ b/src/lib/gssapi/krb5/iakerb.c
@@ -454,9 +454,11 @@ iakerb_init_creds_ctx(iakerb_ctx_id_t ctx,
if (cred->password != NULL) {
code = krb5_init_creds_set_password(ctx->k5c, ctx->icc,
cred->password);
- } else {
+ } else if (cred->client_keytab != NULL) {
code = krb5_init_creds_set_keytab(ctx->k5c, ctx->icc,
cred->client_keytab);
+ } else {
+ code = KRB5_KT_NOTFOUND;
}
if (code != 0)
goto cleanup;
--- a/src/tests/gssapi/t_client_keytab.py
+++ b/src/tests/gssapi/t_client_keytab.py
@@ -141,4 +141,14 @@ if 'No credentials cache found' not in out:
fail('Expected error not seen')
realm.run([kdestroy, '-A'])
+# Test 16: default client keytab cannot be resolved, but valid
+# credentials exist in ccache.
+conf = {'libdefaults': {'default_client_keytab_name': '%{'}}
+bad_cktname = realm.special_env('bad_cktname', False, krb5_conf=conf)
+del bad_cktname['KRB5_CLIENT_KTNAME']
+realm.kinit(realm.user_princ, password('user'))
+out = realm.run(['./t_ccselect', phost], env=bad_cktname)
+if realm.user_princ not in out:
+ fail('Expected principal not seen for bad client keytab name')
+
success('Client keytab tests')