From 5ae9bc98f23aeaa2ce17debe5a9b0cf1130e54ed Mon Sep 17 00:00:00 2001 From: Greg Hudson Date: Mon, 7 Jun 2021 13:27:29 -0400 Subject: [PATCH] Fix some principal realm canonicalization cases The no_hostrealm and subst_defrealm flags in struct canonprinc were only applied when dns_canonicalize_hostname=fallback; in the other cases, the initial krb5_sname_to_principal() result is treated as canonical. For no_hostrealm this limitation doesn't currently matter, because all uses pass a principal with no realm as input. However, subst_defrealm is used to convert the referral realm to the default realm in krb5_get_init_creds_keytab(), krb5_cc_cache_match(), and gss_acquire_cred() when it needs to check the desired name against a specified ccache. In k5_canonprinc(), if the input principal is a krb5_sname_to_principal() result and fallback isn't in effect, apply subst_defrealm. Document in os-proto.h that no_hostrealm doesn't remove an existing realm and that krb5_sname_to_principal() may already have looked one up. ticket: 9011 (new) (cherry picked from commit c077d0c6430c4ac163443aacc03d14d206a4cbb8) --- src/lib/krb5/os/os-proto.h | 13 +++++++++---- src/lib/krb5/os/sn2princ.c | 24 +++++++++++++++++++++--- 2 files changed, 30 insertions(+), 7 deletions(-) diff --git a/src/lib/krb5/os/os-proto.h b/src/lib/krb5/os/os-proto.h index 7d5e7978f..a985f2aec 100644 --- a/src/lib/krb5/os/os-proto.h +++ b/src/lib/krb5/os/os-proto.h @@ -85,10 +85,15 @@ struct sendto_callback_info { /* * Initialize with all zeros except for princ. Set no_hostrealm to disable - * host-to-realm lookup, which ordinarily happens after canonicalizing the host - * part. Set subst_defrealm to substitute the default realm for the referral - * realm after realm lookup (this has no effect if no_hostrealm is set). Free - * with free_canonprinc() when done. + * host-to-realm lookup, which ordinarily happens during fallback processing + * after canonicalizing the host part. Set subst_defrealm to substitute the + * default realm for the referral realm after realm lookup. Do not set both + * flags. Free with free_canonprinc() when done. + * + * no_hostrealm only applies if fallback processing is in use + * (dns_canonicalize_hostname = fallback). It will not remove the realm if + * krb5_sname_to_principal() already canonicalized the hostname and looked up a + * realm. subst_defrealm applies whether or not fallback processing is in use. */ struct canonprinc { krb5_const_principal princ; diff --git a/src/lib/krb5/os/sn2princ.c b/src/lib/krb5/os/sn2princ.c index c99b7da17..93c155932 100644 --- a/src/lib/krb5/os/sn2princ.c +++ b/src/lib/krb5/os/sn2princ.c @@ -271,18 +271,36 @@ krb5_error_code k5_canonprinc(krb5_context context, struct canonprinc *iter, krb5_const_principal *princ_out) { + krb5_error_code ret; int step = ++iter->step; *princ_out = NULL; - /* If we're not doing fallback, the input principal is canonical. */ - if (context->dns_canonicalize_hostname != CANONHOST_FALLBACK || - iter->princ->type != KRB5_NT_SRV_HST || iter->princ->length != 2 || + /* If the hostname isn't from krb5_sname_to_principal(), the input + * principal is canonical. */ + if (iter->princ->type != KRB5_NT_SRV_HST || iter->princ->length != 2 || iter->princ->data[1].length == 0) { *princ_out = (step == 1) ? iter->princ : NULL; return 0; } + /* If we're not doing fallback, the hostname is canonical, but we may need + * to substitute the default realm. */ + if (context->dns_canonicalize_hostname != CANONHOST_FALLBACK) { + if (step > 1) + return 0; + iter->copy = *iter->princ; + if (iter->subst_defrealm && iter->copy.realm.length == 0) { + ret = krb5_get_default_realm(context, &iter->realm); + if (ret) + return ret; + iter->copy = *iter->princ; + iter->copy.realm = string2data(iter->realm); + } + *princ_out = &iter->copy; + return 0; + } + /* Canonicalize without DNS at step 1, with DNS at step 2. */ if (step > 2) return 0;