From ec39b832ff3921c6a38ac0a63c3cdb7e9b1a9c3c Mon Sep 17 00:00:00 2001 From: Jeffrey Altman Date: Fri, 20 Jan 2017 17:56:54 -0500 Subject: [PATCH] kdc: fix kx509 service principal match Each KDC is a kx509 server. The service principal must be of the form kca_service/@ where localhost.domain is the hostname returned by gethostname() and is one of the realms for which the KDC has a service principal "kca_service/". The matching code was broken by a5e77c578e2719d3e7e2e1d8c8ec117ac925fc62 when krb5_sname_to_principal() began to always return a referral principal. Since the second component is a host name update the default principal type for service "kca_service" to be KRB5_NT_SRV_HST. Change-Id: I6bd5f90b674ebb7220d8efafa6d339fdc21e1a07 --- kdc/kx509.c | 80 +++++++++++++++++++++++++++----------------- lib/krb5/principal.c | 2 ++ 2 files changed, 51 insertions(+), 31 deletions(-) diff --git a/kdc/kx509.c b/kdc/kx509.c index 2e1977837..6f61a8ea3 100644 --- a/kdc/kx509.c +++ b/kdc/kx509.c @@ -322,6 +322,53 @@ out: return ret; } +krb5_error_code +kdc_kx509_verify_service_principal(krb5_context context, + const char *cname, + krb5_principal sprincipal) +{ + krb5_error_code ret, aret; + krb5_boolean bret; + krb5_principal principal = NULL; + char *expected = NULL; + char localhost[MAXHOSTNAMELEN]; + + ret = gethostname(localhost, sizeof(localhost) - 1); + if (ret != 0) { + ret = errno; + krb5_set_error_message(context, ret, + N_("Failed to get local hostname", "")); + return ret; + } + localhost[sizeof(localhost) - 1] = '\0'; + + ret = krb5_make_principal(context, &principal, "", "kca_service", + localhost, NULL); + if (ret) + goto out; + + bret = krb5_principal_compare_any_realm(context, sprincipal, principal); + if (bret == TRUE) + goto out; /* found a match */ + + ret = KRB5KDC_ERR_SERVER_NOMATCH; + + aret = krb5_unparse_name(context, sprincipal, &expected); + if (aret) + goto out; + + krb5_set_error_message(context, ret, + "User %s used wrong Kx509 service " + "principal, expected: %s", + cname, expected); + + out: + krb5_xfree(expected); + krb5_free_principal(context, principal); + + return ret; +} + /* * */ @@ -338,7 +385,6 @@ _kdc_do_kx509(krb5_context context, krb5_auth_context ac = NULL; krb5_keytab id = NULL; krb5_principal sprincipal = NULL, cprincipal = NULL; - krb5_principal principal = NULL; char *cname = NULL; Kx509Response rep; size_t size; @@ -392,40 +438,14 @@ _kdc_do_kx509(krb5_context context, if (ret) goto out; - /* verify server principal */ - - ret = krb5_sname_to_principal(context, NULL, "kca_service", - KRB5_NT_UNKNOWN, &sprincipal); + ret = krb5_ticket_get_server(context, ticket, &sprincipal); if (ret) goto out; - ret = krb5_ticket_get_server(context, ticket, &principal); + ret = kdc_kx509_verify_service_principal(context, cname, sprincipal); if (ret) goto out; - ret = krb5_principal_compare(context, sprincipal, principal); - if (ret != TRUE) { - char *expected, *used; - - ret = krb5_unparse_name(context, sprincipal, &expected); - if (ret) - goto out; - ret = krb5_unparse_name(context, principal, &used); - if (ret) { - krb5_xfree(expected); - goto out; - } - - ret = KRB5KDC_ERR_SERVER_NOMATCH; - krb5_set_error_message(context, ret, - "User %s used wrong Kx509 service " - "principal, expected: %s, used %s", - cname, expected, used); - krb5_xfree(expected); - krb5_xfree(used); - goto out; - } - ret = krb5_auth_con_getkey(context, ac, &key); if (ret == 0 && key == NULL) ret = KRB5KDC_ERR_NULL_KEY; @@ -515,8 +535,6 @@ out: krb5_free_principal(context, sprincipal); if (cprincipal) krb5_free_principal(context, cprincipal); - if (principal) - krb5_free_principal(context, principal); if (key) krb5_free_keyblock (context, key); if (cname) diff --git a/lib/krb5/principal.c b/lib/krb5/principal.c index fac22ef6f..143dd6414 100644 --- a/lib/krb5/principal.c +++ b/lib/krb5/principal.c @@ -70,6 +70,8 @@ set_default_princ_type(krb5_principal p, NAME_TYPE defnt) princ_type(p) = KRB5_NT_SRV_INST; else if (princ_num_comp(p) > 1 && strcmp(princ_ncomp(p, 0), "host") == 0) princ_type(p) = KRB5_NT_SRV_HST; + else if (princ_num_comp(p) > 1 && strcmp(princ_ncomp(p, 0), "kca_service") == 0) + princ_type(p) = KRB5_NT_SRV_HST; else if (princ_num_comp(p) == 2 && strcmp(princ_ncomp(p, 0), KRB5_WELLKNOWN_NAME) == 0) princ_type(p) = KRB5_NT_WELLKNOWN;