krb5: fail krb5_verify_user() early if service key missing

Fixes #1157.
This commit is contained in:
Roland C. Dowdeswell
2026-05-25 14:48:55 +01:00
committed by Nico Williams
parent 73bab3fea5
commit 3ff4191ba9
2 changed files with 134 additions and 1 deletions
+90
View File
@@ -63,6 +63,89 @@ test_empty_keytab(krb5_context context, const char *keytab)
krb5_err(context, 1, ret, "krb5_kt_close");
}
static void
test_verify_user_empty_keytab(krb5_context context, const char *keytab)
{
krb5_error_code ret;
krb5_keytab id;
krb5_principal principal;
krb5_verify_opt opt;
ret = krb5_kt_resolve(context, keytab, &id);
if (ret)
krb5_err(context, 1, ret, "krb5_kt_resolve");
ret = krb5_parse_name(context, "lha@SU.SE", &principal);
if (ret)
krb5_err(context, 1, ret, "krb5_parse_name");
krb5_verify_opt_init(&opt);
krb5_verify_opt_set_keytab(&opt, id);
ret = krb5_verify_user_opt(context, principal, "password", &opt);
if (ret != KRB5_KT_NOTFOUND)
krb5_errx(context, 1,
"krb5_verify_user_opt returned %d, expected %d",
(int)ret, (int)KRB5_KT_NOTFOUND);
krb5_free_principal(context, principal);
ret = krb5_kt_close(context, id);
if (ret)
krb5_err(context, 1, ret, "krb5_kt_close");
}
static void
test_verify_user_wrong_keytab(krb5_context context, const char *keytab)
{
krb5_error_code ret;
krb5_keytab id;
krb5_keytab_entry entry;
krb5_principal principal;
krb5_verify_opt opt;
ret = krb5_kt_resolve(context, keytab, &id);
if (ret)
krb5_err(context, 1, ret, "krb5_kt_resolve");
memset(&entry, 0, sizeof(entry));
ret = krb5_parse_name(context, "not-host/foo@SU.SE", &entry.principal);
if (ret)
krb5_err(context, 1, ret, "krb5_parse_name");
entry.vno = 1;
ret = krb5_generate_random_keyblock(context,
ETYPE_AES256_CTS_HMAC_SHA1_96,
&entry.keyblock);
if (ret)
krb5_err(context, 1, ret, "krb5_generate_random_keyblock");
ret = krb5_kt_add_entry(context, id, &entry);
if (ret)
krb5_err(context, 1, ret, "krb5_kt_add_entry");
ret = krb5_parse_name(context, "lha@SU.SE", &principal);
if (ret)
krb5_err(context, 1, ret, "krb5_parse_name");
krb5_verify_opt_init(&opt);
krb5_verify_opt_set_keytab(&opt, id);
ret = krb5_verify_user_opt(context, principal, "password", &opt);
if (ret != KRB5_KT_NOTFOUND)
krb5_errx(context, 1,
"krb5_verify_user_opt returned %d, expected %d",
(int)ret, (int)KRB5_KT_NOTFOUND);
krb5_free_principal(context, principal);
krb5_kt_remove_entry(context, id, &entry);
krb5_free_principal(context, entry.principal);
krb5_free_keyblock_contents(context, &entry.keyblock);
ret = krb5_kt_close(context, id);
if (ret)
krb5_err(context, 1, ret, "krb5_kt_close");
}
/*
* Test that memory keytab are refcounted.
*/
@@ -281,6 +364,13 @@ main(int argc, char **argv)
test_empty_keytab(context, "MEMORY:foo");
test_empty_keytab(context, "FILE:foo");
ret = krb5_set_default_realm(context, "SU.SE");
if (ret)
krb5_err(context, 1, ret, "krb5_set_default_realm");
test_verify_user_empty_keytab(context, "MEMORY:verify-user-empty");
test_verify_user_wrong_keytab(context, "MEMORY:verify-user-wrong");
test_memory_keytab(context, "MEMORY:foo", "MEMORY:foo2");
}
+44 -1
View File
@@ -33,6 +33,40 @@
#include "krb5_locl.h"
static krb5_error_code
check_server_keytab(krb5_context context, krb5_keytab keytab,
const char *service)
{
krb5_error_code ret, ret2;
krb5_keytab_entry entry;
krb5_keytab kt = keytab;
krb5_principal server;
ret = krb5_sname_to_principal(context, NULL, service, KRB5_NT_SRV_HST,
&server);
if (ret)
return ret;
if (kt == NULL) {
ret = krb5_kt_default(context, &kt);
if (ret)
goto out;
}
ret = krb5_kt_get_entry(context, kt, server, 0, 0, &entry);
if (ret == 0)
krb5_kt_free_entry(context, &entry);
if (keytab == NULL) {
ret2 = krb5_kt_close(context, kt);
if (ret == 0)
ret = ret2;
}
out:
krb5_free_principal(context, server);
return ret;
}
static krb5_error_code
verify_common (krb5_context context,
krb5_principal principal,
@@ -185,7 +219,16 @@ krb5_verify_user_opt(krb5_context context,
const char *password,
krb5_verify_opt *opt)
{
krb5_error_code ret;
krb5_error_code ret = 0;
#define OPT(V, D) ((opt && (opt->V)) ? (opt->V) : (D))
if (opt == NULL || opt->secure) {
ret = check_server_keytab(context, OPT(keytab, NULL),
OPT(service, "host"));
}
#undef OPT
if (ret)
return ret;
if(opt && (opt->flags & KRB5_VERIFY_LREALMS)) {
krb5_realm *realms, *r;