From 18c18d84b1f1ed3f0169991cda462d73af38712d Mon Sep 17 00:00:00 2001 From: Luke Howard Date: Sun, 8 Aug 2021 11:28:32 +1000 Subject: [PATCH] gss: merge gss_name_to_oid and gss_mg_name_to_oid The recently introduced gss_mg_name_to_oid() function supported looking up dynamically loaded mechanisms by name, but did not support partial matches or the legacy "Kerberos 5" name as supported by gss_name_to_oid(). Consolidate these into a single function, and also add support for dynamically loaded mechanisms to gss_oid_to_name(). API behavior difference: the Kerberos mechanism is now referred to by "krb5" rather tha "Kerberos 5", although for legacy compatibility gss_name_to_oid() will recognize the old name. However, gss_oid_to_name() will return "krb5". The anticipated impact is minimal as these are not standard GSS-APIs and do not appear to have any public usage outside Heimdal. --- lib/gssapi/gssapi/gssapi.h | 3 + lib/gssapi/gssapi_mech.h | 3 - lib/gssapi/krb5/external.c | 2 +- lib/gssapi/libgssapi-exports.def | 1 - lib/gssapi/mech/gss_mech_switch.c | 67 +++++++++++++++++-- lib/gssapi/mech/gss_oid_to_str.c | 31 --------- lib/gssapi/test_context.c | 103 +++++++++--------------------- lib/gssapi/version-script.map | 1 - 8 files changed, 97 insertions(+), 114 deletions(-) diff --git a/lib/gssapi/gssapi/gssapi.h b/lib/gssapi/gssapi/gssapi.h index afaaa35dd..05d96c347 100644 --- a/lib/gssapi/gssapi/gssapi.h +++ b/lib/gssapi/gssapi/gssapi.h @@ -1144,9 +1144,12 @@ GSSAPI_LIB_FUNCTION OM_uint32 GSSAPI_LIB_CALL gss_duplicate_cred ( gss_const_cred_id_t /*input_cred_handle*/, gss_cred_id_t * /*output_cred_handle*/ ); + +/* Return a mechanism short name from an OID */ GSSAPI_LIB_FUNCTION const char * GSSAPI_LIB_CALL gss_oid_to_name(gss_const_OID oid); +/* Return a mechanism OID from a short name or dotted OID */ GSSAPI_LIB_FUNCTION gss_OID GSSAPI_LIB_CALL gss_name_to_oid(const char *name); diff --git a/lib/gssapi/gssapi_mech.h b/lib/gssapi/gssapi_mech.h index e6179ba11..634e16b32 100644 --- a/lib/gssapi/gssapi_mech.h +++ b/lib/gssapi/gssapi_mech.h @@ -701,9 +701,6 @@ gss_cred_id_t _gss_mg_find_mech_cred(gss_const_cred_id_t cred_handle, gss_const_OID mech_type); -GSSAPI_LIB_FUNCTION gss_const_OID -GSSAPI_CALLCONV gss_mg_name_to_oid(const char *); - #include /* diff --git a/lib/gssapi/krb5/external.c b/lib/gssapi/krb5/external.c index 045d55497..855547059 100644 --- a/lib/gssapi/krb5/external.c +++ b/lib/gssapi/krb5/external.c @@ -328,7 +328,7 @@ static gss_mo_desc krb5_mo[] = { static gssapi_mech_interface_desc krb5_mech = { GMI_VERSION, - "kerberos 5", + "krb5", {9, rk_UNCONST("\x2a\x86\x48\x86\xf7\x12\x01\x02\x02") }, 0, NULL, /* gm_acquire_cred */ diff --git a/lib/gssapi/libgssapi-exports.def b/lib/gssapi/libgssapi-exports.def index 00ef309b1..10e487f13 100644 --- a/lib/gssapi/libgssapi-exports.def +++ b/lib/gssapi/libgssapi-exports.def @@ -69,7 +69,6 @@ EXPORTS gss_krb5_set_allowable_enctypes gss_localname gss_mg_collect_error - gss_mg_name_to_oid gss_mo_get gss_mo_set gss_mo_list diff --git a/lib/gssapi/mech/gss_mech_switch.c b/lib/gssapi/mech/gss_mech_switch.c index 2db9dbb69..0102a233f 100644 --- a/lib/gssapi/mech/gss_mech_switch.c +++ b/lib/gssapi/mech/gss_mech_switch.c @@ -491,20 +491,77 @@ _gss_mg_support_mechanism(gss_const_OID mech) return NULL; } -GSSAPI_LIB_FUNCTION gss_const_OID GSSAPI_CALLCONV -gss_mg_name_to_oid(const char *name) +enum mech_name_match { + MATCH_NONE = 0, + MATCH_COMPLETE, + MATCH_PARTIAL +}; + +static enum mech_name_match +match_mech_name(const char *gm_mech_name, + const char *name, + size_t namelen) { - struct _gss_mech_switch *m; + if (gm_mech_name == NULL) + return MATCH_NONE; + else if (strcasecmp(gm_mech_name, name) == 0) + return MATCH_COMPLETE; + else if (strncasecmp(gm_mech_name, name, namelen) == 0) + return MATCH_PARTIAL; + else + return MATCH_NONE; +} + +/* + * Return an OID for a built-in or dynamically loaded mechanism. For + * API compatibility with previous versions, we treat "Kerberos 5" + * as an alias for "krb5". Unique partial matches are supported. + */ +GSSAPI_LIB_FUNCTION gss_OID GSSAPI_CALLCONV +gss_name_to_oid(const char *name) +{ + struct _gss_mech_switch *m, *partial = NULL; gss_OID oid = GSS_C_NO_OID; + size_t namelen = strlen(name); if (isdigit(name[0]) && _gss_string_to_oid(name, &oid) == 0) return oid; _gss_load_mech(); HEIM_TAILQ_FOREACH(m, &_gss_mechs, gm_link) { - if (m->gm_mech.gm_name && - strcmp(m->gm_mech.gm_name, name) == 0) + enum mech_name_match match; + + match = match_mech_name(m->gm_mech.gm_name, name, namelen); + if (match == MATCH_NONE && + gss_oid_equal(m->gm_mech_oid, GSS_KRB5_MECHANISM)) + match = match_mech_name("Kerberos 5", name, namelen); + + if (match == MATCH_COMPLETE) return m->gm_mech_oid; + else if (match == MATCH_PARTIAL) { + if (partial) + return NULL; + else + partial = m; + } } + + if (partial) + return partial->gm_mech_oid; + + return NULL; +} + +GSSAPI_LIB_FUNCTION const char * GSSAPI_LIB_CALL +gss_oid_to_name(gss_const_OID oid) +{ + struct _gss_mech_switch *m; + + _gss_load_mech(); + HEIM_TAILQ_FOREACH(m, &_gss_mechs, gm_link) { + if (gss_oid_equal(m->gm_mech_oid, oid)) + return m->gm_mech.gm_name; + } + return NULL; } diff --git a/lib/gssapi/mech/gss_oid_to_str.c b/lib/gssapi/mech/gss_oid_to_str.c index a1d776877..d8e188da0 100644 --- a/lib/gssapi/mech/gss_oid_to_str.c +++ b/lib/gssapi/mech/gss_oid_to_str.c @@ -65,34 +65,3 @@ gss_oid_to_str(OM_uint32 *minor_status, gss_OID oid, gss_buffer_t oid_str) *minor_status = 0; return GSS_S_COMPLETE; } - -GSSAPI_LIB_FUNCTION const char * GSSAPI_LIB_CALL -gss_oid_to_name(gss_const_OID oid) -{ - size_t i; - - for (i = 0; _gss_ont_mech[i].oid; i++) { - if (gss_oid_equal(oid, _gss_ont_mech[i].oid)) - return _gss_ont_mech[i].name; - } - return NULL; -} - -GSSAPI_LIB_FUNCTION gss_OID GSSAPI_LIB_CALL -gss_name_to_oid(const char *name) -{ - size_t i, partial = (size_t)-1; - - for (i = 0; _gss_ont_mech[i].oid; i++) { - if (strcasecmp(name, _gss_ont_mech[i].short_desc) == 0) - return _gss_ont_mech[i].oid; - if (strncasecmp(name, _gss_ont_mech[i].short_desc, strlen(name)) == 0) { - if (partial != (size_t)-1) - return NULL; - partial = i; - } - } - if (partial != (size_t)-1) - return _gss_ont_mech[partial].oid; - return NULL; -} diff --git a/lib/gssapi/test_context.c b/lib/gssapi/test_context.c index cc2789636..5a2e95207 100644 --- a/lib/gssapi/test_context.c +++ b/lib/gssapi/test_context.c @@ -87,49 +87,10 @@ static char *a_channel_bindings = NULL; static krb5_context context; static krb5_enctype limit_enctype = 0; -static gss_OID_desc test_negoex_1_mech = { 6, "\x69\x85\xa2\xc0\xac\x66" }; -static gss_OID_desc test_negoex_2_mech = { 6, "\x69\x84\xb0\xd1\xa8\x2c" }; - -static struct { - const char *name; - gss_OID oid; -} o2n[] = { - { "krb5", NULL /* GSS_KRB5_MECHANISM */ }, - { "spnego", NULL /* GSS_SPNEGO_MECHANISM */ }, - { "ntlm", NULL /* GSS_NTLM_MECHANISM */ }, - { "sasl-digest-md5", NULL /* GSS_SASL_DIGEST_MD5_MECHANISM */ }, - { "sanon-x25519", NULL /* GSS_SASL_SANON_X25519_MECHANISM */ }, - { "test_negoex_1", NULL }, - { "test_negoex_2", NULL }, -}; - static void -init_o2n(void) -{ - o2n[0].oid = GSS_KRB5_MECHANISM; - o2n[1].oid = GSS_SPNEGO_MECHANISM; - o2n[2].oid = GSS_NTLM_MECHANISM; - o2n[3].oid = GSS_SASL_DIGEST_MD5_MECHANISM; - o2n[4].oid = GSS_SANON_X25519_MECHANISM; - o2n[5].oid = &test_negoex_1_mech; - o2n[6].oid = &test_negoex_2_mech; -} - -static gss_OID -string_to_oid(const char *name) -{ - size_t i; - for (i = 0; i < sizeof(o2n)/sizeof(o2n[0]); i++) - if (strcasecmp(name, o2n[i].name) == 0) - return o2n[i].oid; - errx(1, "name '%s' not known", name); -} - -static void -string_to_oids(gss_OID_set *oidsetp, gss_OID_set oidset, - gss_OID_desc *oidarray, size_t oidarray_len, - char *names) +string_to_oids(gss_OID_set *oidsetp, char *names) { + OM_uint32 maj_stat, min_stat; char *name; char *s; @@ -138,32 +99,31 @@ string_to_oids(gss_OID_set *oidsetp, gss_OID_set oidset, return; } - oidset->elements = &oidarray[0]; if (strcasecmp(names, "all") == 0) { - if (sizeof(o2n)/sizeof(o2n[0]) > oidarray_len) - errx(1, "internal error: oidarray must be enlarged"); - for (oidset->count = 0; oidset->count < oidarray_len; oidset->count++) - oidset->elements[oidset->count] = *o2n[oidset->count].oid; + maj_stat = gss_indicate_mechs(&min_stat, oidsetp); + if (GSS_ERROR(maj_stat)) + errx(1, "gss_indicate_mechs: %s", + gssapi_err(maj_stat, min_stat, GSS_C_NO_OID)); } else { - for (oidset->count = 0, name = strtok_r(names, ", ", &s); + maj_stat = gss_create_empty_oid_set(&min_stat, oidsetp); + if (GSS_ERROR(maj_stat)) + errx(1, "gss_create_empty_oid_set: %s", + gssapi_err(maj_stat, min_stat, GSS_C_NO_OID)); + + for (name = strtok_r(names, ", ", &s); name != NULL; - oidset->count++, name = strtok_r(NULL, ", ", &s)) { - if (oidset->count >= oidarray_len) - errx(1, "too many mech names given"); - oidset->elements[oidset->count] = *string_to_oid(name); + name = strtok_r(NULL, ", ", &s)) { + gss_OID oid = gss_name_to_oid(name); + + if (oid == GSS_C_NO_OID) + errx(1, "gss_name_to_oid: unknown mech %s", name); + + maj_stat = gss_add_oid_set_member(&min_stat, oid, oidsetp); + if (GSS_ERROR(maj_stat)) + errx(1, "gss_add_oid_set_member: %s", + gssapi_err(maj_stat, min_stat, GSS_C_NO_OID)); } } - *oidsetp = oidset; -} - -static const char * -oid_to_string(const gss_OID oid) -{ - size_t i; - for (i = 0; i < sizeof(o2n)/sizeof(o2n[0]); i++) - if (gss_oid_equal(oid, o2n[i].oid)) - return o2n[i].name; - return "unknown oid"; } static void @@ -817,8 +777,6 @@ main(int argc, char **argv) setprogname(argv[0]); - init_o2n(); - if (krb5_init_context(&context)) errx(1, "krb5_init_context"); @@ -856,7 +814,7 @@ main(int argc, char **argv) if (mech_string == NULL) mechoid = GSS_KRB5_MECHANISM; else - mechoid = string_to_oid(mech_string); + mechoid = gss_name_to_oid(mech_string); if (mechs_string == NULL) { /* @@ -885,8 +843,7 @@ main(int argc, char **argv) mechoid_descs.count = 1; mechoids = &mechoid_descs; } else { - string_to_oids(&mechoids, &mechoid_descs, - oids, sizeof(oids)/sizeof(oids[0]), mechs_string); + string_to_oids(&mechoids, mechs_string); } if (gsskrb5_acceptor_identity) { @@ -976,7 +933,7 @@ main(int argc, char **argv) printf("cred mechs:"); for (i = 0; i < actual_mechs->count; i++) - printf(" %s", oid_to_string(&actual_mechs->elements[i])); + printf(" %s", gss_oid_to_name(&actual_mechs->elements[i])); printf("\n"); } @@ -1036,12 +993,12 @@ main(int argc, char **argv) &sctx, &cctx, &actual_mech, &deleg_cred); if (verbose_flag) - printf("resulting mech: %s\n", oid_to_string(actual_mech)); + printf("resulting mech: %s\n", gss_oid_to_name(actual_mech)); if (ret_mech_string) { gss_OID retoid; - retoid = string_to_oid(ret_mech_string); + retoid = gss_name_to_oid(ret_mech_string); if (gss_oid_equal(retoid, actual_mech) == 0) errx(1, "actual_mech mech is not the expected type %s", @@ -1393,7 +1350,7 @@ main(int argc, char **argv) if (verbose_flag) printf("checking actual mech (%s) on delegated cred\n", - oid_to_string(actual_mech)); + gss_oid_to_name(actual_mech)); loop(actual_mech, nameoid, argv[0], deleg_cred, &sctx, &cctx, &actual_mech2, &cred2); gss_delete_sec_context(&min_stat, &cctx, NULL); @@ -1438,7 +1395,7 @@ main(int argc, char **argv) if (verbose_flag) printf("checking actual mech (%s) on export/imported cred\n", - oid_to_string(actual_mech)); + gss_oid_to_name(actual_mech)); loop(actual_mech, nameoid, argv[0], cred2, &sctx, &cctx, &actual_mech2, &deleg_cred); @@ -1471,6 +1428,8 @@ main(int argc, char **argv) gss_release_cred(&min_stat, &client_cred); gss_release_oid_set(&min_stat, &actual_mechs); + if (mechoids != GSS_C_NO_OID_SET && mechoids != &mechoid_descs) + gss_release_oid_set(&min_stat, &mechoids); empty_release(); krb5_free_context(context); diff --git a/lib/gssapi/version-script.map b/lib/gssapi/version-script.map index b44581b52..0a731c430 100644 --- a/lib/gssapi/version-script.map +++ b/lib/gssapi/version-script.map @@ -69,7 +69,6 @@ HEIMDAL_GSS_2.0 { gss_krb5_set_allowable_enctypes; gss_localname; gss_mg_collect_error; - gss_mg_name_to_oid; gss_oid_equal; gss_oid_to_str; gss_pname_to_uid;