summaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
authorGreg Hudson <ghudson@mit.edu>2012-04-19 17:55:14 +0000
committerGreg Hudson <ghudson@mit.edu>2012-04-19 17:55:14 +0000
commit8230c4b7b7323cdef2a6c877deb710a15380f40f (patch)
treecbcf6d5238b03f9990c674e5f6026d2b7056c290 /src
parentd1da158f47ea604bed4d5db5e98a976a9e54ccd0 (diff)
downloadkrb5-8230c4b7b7323cdef2a6c877deb710a15380f40f.tar.gz
krb5-8230c4b7b7323cdef2a6c877deb710a15380f40f.tar.xz
krb5-8230c4b7b7323cdef2a6c877deb710a15380f40f.zip
Use etypes from keytab in krb5_gic_keytab
When getting initial credentials with a keytab, filter the list of request enctypes based on the keys in the keytab. Based on a patch from Stef Walter. ticket: 2131 git-svn-id: svn://anonsvn.mit.edu/krb5/trunk@25818 dc483132-0cff-0310-8789-dd5450dbe970
Diffstat (limited to 'src')
-rw-r--r--src/include/k5-trace.h4
-rw-r--r--src/lib/krb5/krb/gic_keytab.c118
-rw-r--r--src/tests/t_keytab.py7
3 files changed, 128 insertions, 1 deletions
diff --git a/src/include/k5-trace.h b/src/include/k5-trace.h
index 3749cf900..36eb23bb3 100644
--- a/src/include/k5-trace.h
+++ b/src/include/k5-trace.h
@@ -187,6 +187,10 @@
#define TRACE_INIT_CREDS_GAK(c, salt, s2kparams) \
TRACE(c, (c, "Getting AS key, salt \"{data}\", params \"{data}\"", \
salt, s2kparams))
+#define TRACE_INIT_CREDS_KEYTAB_LOOKUP(c, etypes) \
+ TRACE(c, (c, "Looked up etypes in keytab: {etypes}", etypes))
+#define TRACE_INIT_CREDS_KEYTAB_LOOKUP_FAILED(c, code) \
+ TRACE(c, (c, "Couldn't lookup etypes in keytab: {kerr}", code))
#define TRACE_INIT_CREDS_PREAUTH_DECRYPT_FAIL(c, code) \
TRACE(c, (c, "Decrypt with preauth AS key failed: {kerr}", code))
#define TRACE_INIT_CREDS_RESTART_FAST(c) \
diff --git a/src/lib/krb5/krb/gic_keytab.c b/src/lib/krb5/krb/gic_keytab.c
index e59177fda..3554b257c 100644
--- a/src/lib/krb5/krb/gic_keytab.c
+++ b/src/lib/krb5/krb/gic_keytab.c
@@ -77,14 +77,132 @@ get_as_key_keytab(krb5_context context,
return(ret);
}
+/* Return the list of etypes available for client in keytab. */
+static krb5_error_code
+lookup_etypes_for_keytab(krb5_context context, krb5_keytab keytab,
+ krb5_principal client, krb5_enctype **etypes_out)
+{
+ krb5_kt_cursor cursor;
+ krb5_keytab_entry entry;
+ krb5_enctype *p, *etypes = NULL;
+ krb5_kvno max_kvno = 0;
+ krb5_error_code ret;
+ size_t count = 0;
+
+ *etypes_out = NULL;
+
+ if (keytab->ops->start_seq_get == NULL)
+ return EINVAL;
+ ret = krb5_kt_start_seq_get(context, keytab, &cursor);
+ if (ret != 0)
+ return ret;
+
+ for (;;) {
+ ret = krb5_kt_next_entry(context, keytab, &entry, &cursor);
+ if (ret == KRB5_KT_END)
+ break;
+ if (ret)
+ goto cleanup;
+
+ if (!krb5_c_valid_enctype(entry.key.enctype))
+ continue;
+ if (!krb5_principal_compare(context, entry.principal, client))
+ continue;
+ /* Make sure our list is for the highest kvno found for client. */
+ if (entry.vno > max_kvno) {
+ free(etypes);
+ etypes = NULL;
+ count = 0;
+ max_kvno = entry.vno;
+ } else if (entry.vno != max_kvno)
+ continue;
+
+ /* Leave room for the terminator and possibly a second entry. */
+ p = realloc(etypes, (count + 3) * sizeof(*etypes));
+ if (p == NULL) {
+ ret = ENOMEM;
+ goto cleanup;
+ }
+ etypes = p;
+ etypes[count++] = entry.key.enctype;
+ /* All DES key types work with des-cbc-crc, which is more likely to be
+ * accepted by the KDC (since MIT KDCs refuse des-cbc-md5). */
+ if (entry.key.enctype == ENCTYPE_DES_CBC_MD5 ||
+ entry.key.enctype == ENCTYPE_DES_CBC_MD4)
+ etypes[count++] = ENCTYPE_DES_CBC_CRC;
+ etypes[count] = 0;
+ }
+
+ ret = 0;
+ *etypes_out = etypes;
+ etypes = NULL;
+cleanup:
+ krb5_kt_end_seq_get(context, keytab, &cursor);
+ free(etypes);
+ return ret;
+}
+
+/* Return true if search_for is in etype_list. */
+static krb5_boolean
+check_etypes_have(krb5_enctype *etype_list, krb5_enctype search_for)
+{
+ int i;
+
+ if (!etype_list)
+ return FALSE;
+
+ for (i = 0; etype_list[i] != 0; i++) {
+ if (etype_list[i] == search_for)
+ return TRUE;
+ }
+
+ return FALSE;
+}
+
krb5_error_code KRB5_CALLCONV
krb5_init_creds_set_keytab(krb5_context context,
krb5_init_creds_context ctx,
krb5_keytab keytab)
{
+ krb5_enctype *etype_list;
+ krb5_error_code ret;
+ int i, j;
+ char *name;
+
ctx->gak_fct = get_as_key_keytab;
ctx->gak_data = keytab;
+ ret = lookup_etypes_for_keytab(context, keytab, ctx->request->client,
+ &etype_list);
+ if (ret) {
+ TRACE_INIT_CREDS_KEYTAB_LOOKUP_FAILED(context, ret);
+ return 0;
+ }
+
+ TRACE_INIT_CREDS_KEYTAB_LOOKUP(context, etype_list);
+
+ /* Filter the ktypes list based on what's in the keytab */
+ for (i = 0, j = 0; i < ctx->request->nktypes; i++) {
+ if (check_etypes_have(etype_list, ctx->request->ktype[i])) {
+ ctx->request->ktype[j] = ctx->request->ktype[i];
+ j++;
+ }
+ }
+ ctx->request->nktypes = j;
+ free(etype_list);
+
+ /* Error out now if there's no overlap. */
+ if (ctx->request->nktypes == 0) {
+ ret = krb5_unparse_name(context, ctx->request->client, &name);
+ if (ret == 0) {
+ krb5_set_error_message(context, KRB5_KT_NOTFOUND,
+ _("Keytab contains no suitable keys for "
+ "%s"), name);
+ }
+ krb5_free_unparsed_name(context, name);
+ return KRB5_KT_NOTFOUND;
+ }
+
return 0;
}
diff --git a/src/tests/t_keytab.py b/src/tests/t_keytab.py
index b45bfa6d9..7faf23cbf 100644
--- a/src/tests/t_keytab.py
+++ b/src/tests/t_keytab.py
@@ -10,7 +10,12 @@ realm.kinit(realm.host_princ, flags=['-k'])
pkeytab = realm.keytab + '.partial'
realm.run_as_master([ktutil], input=('rkt %s\ndelent 1\nwkt %s\n' %
(realm.keytab, pkeytab)))
-realm.kinit(realm.host_princ, flags=['-k', '-t', pkeytab], expected_code=1)
+realm.kinit(realm.host_princ, flags=['-k', '-t', pkeytab])
+
+# Test kinit with no keys for client in keytab.
+output = realm.kinit(realm.user_princ, flags=['-k'], expected_code=1)
+if 'no suitable keys' not in output:
+ fail('Expected error not seen in kinit output')
# Test handling of kvno values beyond 255.
princ = 'foo/bar@%s' % realm.realm