diff --git a/lib/gssapi/gssapi/gssapi.h b/lib/gssapi/gssapi/gssapi.h index 6df4cf08c..48d1d14f3 100644 --- a/lib/gssapi/gssapi/gssapi.h +++ b/lib/gssapi/gssapi/gssapi.h @@ -261,12 +261,17 @@ typedef OM_uint32 gss_qop_t; #define GSS_IOV_BUFFER_TYPE_STREAM 10 #define GSS_IOV_BUFFER_TYPE_SIGN_ONLY 11 -#define GSS_IOV_BUFFER_TYPE_FLAG_MASK 0xffff0000 -#define GSS_IOV_BUFFER_TYPE_FLAG_ALLOCATE 0x00010000 -#define GSS_IOV_BUFFER_TYPE_FLAG_ALLOCATED 0x00020000 +#define GSS_IOV_BUFFER_FLAG_MASK 0xffff0000 +#define GSS_IOV_BUFFER_FLAG_ALLOCATE 0x00010000 +#define GSS_IOV_BUFFER_FLAG_ALLOCATED 0x00020000 -#define GSS_IOV_BUFFER_TYPE(_t) ((_t) & ~GSS_IOV_BUFFER_TYPE_FLAG_MASK) -#define GSS_IOV_BUFFER_FLAGS(_t) ((_t) & GSS_IOV_BUFFER_TYPE_FLAG_MASK) +#define GSS_IOV_BUFFER_TYPE(_t) ((_t) & ~GSS_IOV_BUFFER_FLAG_MASK) +#define GSS_IOV_BUFFER_FLAGS(_t) ((_t) & GSS_IOV_BUFFER_FLAG_MASK) + +/* compatibility macros; will be removed in the next release */ +#define GSS_IOV_BUFFER_TYPE_FLAG_MASK GSS_IOV_BUFFER_FLAG_MASK +#define GSS_IOV_BUFFER_TYPE_FLAG_ALLOCATE GSS_IOV_BUFFER_FLAG_ALLOCATE +#define GSS_IOV_BUFFER_TYPE_FLAG_ALLOCATED GSS_IOV_BUFFER_FLAG_ALLOCATED GSSAPI_CPP_START @@ -443,6 +448,11 @@ extern GSSAPI_LIB_VARIABLE gss_OID_desc __gss_c_nt_export_name_oid_desc; #define GSS_S_NAME_NOT_MN (18ul << GSS_C_ROUTINE_ERROR_OFFSET) #define GSS_S_BAD_MECH_ATTR (19ul << GSS_C_ROUTINE_ERROR_OFFSET) +/* + * Apparently awating spec fix. + */ +#define GSS_S_CRED_UNAVAIL GSS_S_FAILURE + /* * Supplementary info bits: */ diff --git a/lib/gssapi/gssapi_mech.h b/lib/gssapi/gssapi_mech.h index 8bfdb9674..4e2fc9e93 100644 --- a/lib/gssapi/gssapi_mech.h +++ b/lib/gssapi/gssapi_mech.h @@ -495,6 +495,27 @@ typedef OM_uint32 GSSAPI_CALLCONV _gss_release_any_name_mapping_t ( gss_any_t * /* input */ ); +typedef OM_uint32 GSSAPI_CALLCONV _gss_inquire_saslname_for_mech_t ( + OM_uint32 *, /* minor_status */ + const gss_OID, /* desired_mech */ + gss_buffer_t, /* sasl_mech_name */ + gss_buffer_t, /* mech_name */ + gss_buffer_t /* mech_description */ + ); + +typedef OM_uint32 GSSAPI_CALLCONV _gss_inquire_mech_for_saslname_t ( + OM_uint32 *, /* minor_status */ + const gss_buffer_t, /* sasl_mech_name */ + gss_OID * /* mech_type */ + ); + +typedef OM_uint32 GSSAPI_CALLCONV _gss_inquire_attrs_for_mech_t ( + OM_uint32 *, /* minor_status */ + gss_const_OID, /* mech */ + gss_OID_set *, /* mech_attrs */ + gss_OID_set * /* known_mech_attrs */ + ); + #define GMI_VERSION 5 /* gm_flags */ @@ -502,69 +523,72 @@ typedef OM_uint32 GSSAPI_CALLCONV _gss_release_any_name_mapping_t ( typedef struct gssapi_mech_interface_desc { - unsigned gm_version; - const char *gm_name; - gss_OID_desc gm_mech_oid; - unsigned gm_flags; - _gss_acquire_cred_t *gm_acquire_cred; - _gss_release_cred_t *gm_release_cred; - _gss_init_sec_context_t *gm_init_sec_context; - _gss_accept_sec_context_t *gm_accept_sec_context; - _gss_process_context_token_t *gm_process_context_token; - _gss_delete_sec_context_t *gm_delete_sec_context; - _gss_context_time_t *gm_context_time; - _gss_get_mic_t *gm_get_mic; - _gss_verify_mic_t *gm_verify_mic; - _gss_wrap_t *gm_wrap; - _gss_unwrap_t *gm_unwrap; - _gss_display_status_t *gm_display_status; - _gss_indicate_mechs_t *gm_indicate_mechs; - _gss_compare_name_t *gm_compare_name; - _gss_display_name_t *gm_display_name; - _gss_import_name_t *gm_import_name; - _gss_export_name_t *gm_export_name; - _gss_release_name_t *gm_release_name; - _gss_inquire_cred_t *gm_inquire_cred; - _gss_inquire_context_t *gm_inquire_context; - _gss_wrap_size_limit_t *gm_wrap_size_limit; - _gss_add_cred_t *gm_add_cred; - _gss_inquire_cred_by_mech_t *gm_inquire_cred_by_mech; - _gss_export_sec_context_t *gm_export_sec_context; - _gss_import_sec_context_t *gm_import_sec_context; - _gss_inquire_names_for_mech_t *gm_inquire_names_for_mech; - _gss_inquire_mechs_for_name_t *gm_inquire_mechs_for_name; - _gss_canonicalize_name_t *gm_canonicalize_name; - _gss_duplicate_name_t *gm_duplicate_name; - _gss_inquire_sec_context_by_oid *gm_inquire_sec_context_by_oid; - _gss_inquire_cred_by_oid *gm_inquire_cred_by_oid; - _gss_set_sec_context_option *gm_set_sec_context_option; - _gss_set_cred_option *gm_set_cred_option; - _gss_pseudo_random *gm_pseudo_random; - _gss_wrap_iov_t *gm_wrap_iov; - _gss_unwrap_iov_t *gm_unwrap_iov; - _gss_wrap_iov_length_t *gm_wrap_iov_length; - _gss_store_cred_t *gm_store_cred; - _gss_export_cred_t *gm_export_cred; - _gss_import_cred_t *gm_import_cred; - _gss_acquire_cred_ex_t *gm_acquire_cred_ex; - _gss_iter_creds_t *gm_iter_creds; - _gss_destroy_cred_t *gm_destroy_cred; - _gss_cred_hold_t *gm_cred_hold; - _gss_cred_unhold_t *gm_cred_unhold; - _gss_cred_label_get_t *gm_cred_label_get; - _gss_cred_label_set_t *gm_cred_label_set; - gss_mo_desc *gm_mo; - size_t gm_mo_num; - _gss_acquire_cred_with_password_t *gm_acquire_cred_with_password; - _gss_add_cred_with_password_t *gm_add_cred_with_password; - _gss_display_name_ext_t *gm_display_name_ext; - _gss_inquire_name_t *gm_inquire_name; - _gss_get_name_attribute_t *gm_get_name_attribute; - _gss_set_name_attribute_t *gm_set_name_attribute; - _gss_delete_name_attribute_t *gm_delete_name_attribute; - _gss_export_name_composite_t *gm_export_name_composite; - _gss_map_name_to_any_t *gm_map_name_to_any; - _gss_release_any_name_mapping_t *gm_release_any_name_mapping; + unsigned gm_version; + const char *gm_name; + gss_OID_desc gm_mech_oid; + unsigned gm_flags; + _gss_acquire_cred_t *gm_acquire_cred; + _gss_release_cred_t *gm_release_cred; + _gss_init_sec_context_t *gm_init_sec_context; + _gss_accept_sec_context_t *gm_accept_sec_context; + _gss_process_context_token_t *gm_process_context_token; + _gss_delete_sec_context_t *gm_delete_sec_context; + _gss_context_time_t *gm_context_time; + _gss_get_mic_t *gm_get_mic; + _gss_verify_mic_t *gm_verify_mic; + _gss_wrap_t *gm_wrap; + _gss_unwrap_t *gm_unwrap; + _gss_display_status_t *gm_display_status; + _gss_indicate_mechs_t *gm_indicate_mechs; + _gss_compare_name_t *gm_compare_name; + _gss_display_name_t *gm_display_name; + _gss_import_name_t *gm_import_name; + _gss_export_name_t *gm_export_name; + _gss_release_name_t *gm_release_name; + _gss_inquire_cred_t *gm_inquire_cred; + _gss_inquire_context_t *gm_inquire_context; + _gss_wrap_size_limit_t *gm_wrap_size_limit; + _gss_add_cred_t *gm_add_cred; + _gss_inquire_cred_by_mech_t *gm_inquire_cred_by_mech; + _gss_export_sec_context_t *gm_export_sec_context; + _gss_import_sec_context_t *gm_import_sec_context; + _gss_inquire_names_for_mech_t *gm_inquire_names_for_mech; + _gss_inquire_mechs_for_name_t *gm_inquire_mechs_for_name; + _gss_canonicalize_name_t *gm_canonicalize_name; + _gss_duplicate_name_t *gm_duplicate_name; + _gss_inquire_sec_context_by_oid *gm_inquire_sec_context_by_oid; + _gss_inquire_cred_by_oid *gm_inquire_cred_by_oid; + _gss_set_sec_context_option *gm_set_sec_context_option; + _gss_set_cred_option *gm_set_cred_option; + _gss_pseudo_random *gm_pseudo_random; + _gss_wrap_iov_t *gm_wrap_iov; + _gss_unwrap_iov_t *gm_unwrap_iov; + _gss_wrap_iov_length_t *gm_wrap_iov_length; + _gss_store_cred_t *gm_store_cred; + _gss_export_cred_t *gm_export_cred; + _gss_import_cred_t *gm_import_cred; + _gss_acquire_cred_ex_t *gm_acquire_cred_ex; + _gss_iter_creds_t *gm_iter_creds; + _gss_destroy_cred_t *gm_destroy_cred; + _gss_cred_hold_t *gm_cred_hold; + _gss_cred_unhold_t *gm_cred_unhold; + _gss_cred_label_get_t *gm_cred_label_get; + _gss_cred_label_set_t *gm_cred_label_set; + gss_mo_desc *gm_mo; + size_t gm_mo_num; + _gss_acquire_cred_with_password_t *gm_acquire_cred_with_password; + _gss_add_cred_with_password_t *gm_add_cred_with_password; + _gss_display_name_ext_t *gm_display_name_ext; + _gss_inquire_name_t *gm_inquire_name; + _gss_get_name_attribute_t *gm_get_name_attribute; + _gss_set_name_attribute_t *gm_set_name_attribute; + _gss_delete_name_attribute_t *gm_delete_name_attribute; + _gss_export_name_composite_t *gm_export_name_composite; + _gss_map_name_to_any_t *gm_map_name_to_any; + _gss_release_any_name_mapping_t *gm_release_any_name_mapping; + _gss_inquire_saslname_for_mech_t *gm_inquire_saslname_for_mech; + _gss_inquire_mech_for_saslname_t *gm_inquire_mech_for_saslname; + _gss_inquire_attrs_for_mech_t *gm_inquire_attrs_for_mech; } gssapi_mech_interface_desc, *gssapi_mech_interface; gssapi_mech_interface diff --git a/lib/gssapi/mech/gss_mech_switch.c b/lib/gssapi/mech/gss_mech_switch.c index 4b6aa7ed0..be61f8d0b 100644 --- a/lib/gssapi/mech/gss_mech_switch.c +++ b/lib/gssapi/mech/gss_mech_switch.c @@ -356,6 +356,9 @@ _gss_load_mech(void) OPTSYM(export_name_composite); OPTSYM(map_name_to_any); OPTSYM(release_any_name_mapping); + OPTSYM(inquire_saslname_for_mech); + OPTSYM(inquire_mech_for_saslname); + OPTSYM(inquire_attrs_for_mech); /* pick up the oid sets of names */ diff --git a/lib/gssapi/mech/gss_mo.c b/lib/gssapi/mech/gss_mo.c index cb24b764a..71da150e0 100644 --- a/lib/gssapi/mech/gss_mo.c +++ b/lib/gssapi/mech/gss_mo.c @@ -4,6 +4,7 @@ * All rights reserved. * * Portions Copyright (c) 2010 Apple Inc. All rights reserved. + * Portions Copyright (c) 2010 PADL Software Pty Ltd. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions @@ -35,6 +36,8 @@ #include "mech_locl.h" +#include + static int get_option_def(int def, gss_const_OID mech, gss_mo_desc *mo, gss_buffer_t value) { @@ -147,7 +150,8 @@ gss_mo_name(gss_const_OID mech, gss_const_OID option, gss_buffer_t name) for (n = 0; n < m->gm_mo_num; n++) { if (gss_oid_equal(option, m->gm_mo[n].option)) { /* - * If ther is no name, its because its a GSS_C_MA and there is already a table for that. + * If there is no name, its because its a GSS_C_MA and + * there is already a table for that. */ if (m->gm_mo[n].name) { name->value = strdup(m->gm_mo[n].name); @@ -181,8 +185,79 @@ mo_value(const gss_const_OID mech, gss_const_OID option, gss_buffer_t name) return GSS_S_COMPLETE; } +/* code derived from draft-ietf-cat-sasl-gssapi-01 */ +static char basis_32[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZ234567"; + +static OM_uint32 +make_sasl_name(OM_uint32 *minor, const gss_OID mech, char sasl_name[16]) +{ + EVP_MD_CTX *ctx; + char *p = sasl_name; + u_char hdr[2], hash[20], *h = hash; + + if (mech->length > 127) + return GSS_S_BAD_MECH; + + hdr[0] = 0x06; + hdr[1] = mech->length; + + ctx = EVP_MD_CTX_create(); + EVP_DigestInit_ex(ctx, EVP_sha1(), NULL); + EVP_DigestUpdate(ctx, hdr, 2); + EVP_DigestUpdate(ctx, mech->elements, mech->length); + EVP_DigestFinal(ctx, hash, NULL); + + memcpy(p, "GS2-", 4); + p += 4; + + *p++ = basis_32[h[0] >> 3]; + *p++ = basis_32[((h[0] & 7) << 2) | (h[1] >> 6)]; + *p++ = basis_32[(h[1] & 0x3f) >> 1]; + *p++ = basis_32[((h[1] & 1) << 4) | (h[2] >> 4)]; + *p++ = basis_32[((h[2] & 0xf) << 1) | (h[3] >> 7)]; + *p++ = basis_32[(h[3] & 0x7f) >> 2]; + *p++ = basis_32[((h[3] & 3) << 3) | (h[4] >> 5)]; + *p++ = basis_32[(h[4] & 0x1f)]; + *p++ = basis_32[h[5] >> 3]; + *p++ = basis_32[((h[5] & 7) << 2) | (h[6] >> 6)]; + *p++ = basis_32[(h[6] & 0x3f) >> 1]; + + *p = '\0'; + + return GSS_S_COMPLETE; +} + +/* + * gss_inquire_saslname_for_mech() wrapper that uses MIT SPI + */ +static OM_uint32 +inquire_saslname_for_mech_compat(OM_uint32 *minor, + const gss_OID desired_mech, + gss_buffer_t sasl_mech_name, + gss_buffer_t mech_name, + gss_buffer_t mech_description) +{ + gssapi_mech_interface m; + OM_uint32 major; + + m = __gss_get_mechanism(desired_mech); + if (m == NULL) + return GSS_S_BAD_MECH; + + if (m->gm_inquire_saslname_for_mech == NULL) + return GSS_S_UNAVAILABLE; + + major = m->gm_inquire_saslname_for_mech(minor, + desired_mech, + sasl_mech_name, + mech_name, + mech_description); + + return major; +} + /** - * Returns differnt protocol names and description of the mechanism. + * Returns different protocol names and description of the mechanism. * * @param minor_status minor status code * @param desired_mech mech list query @@ -214,16 +289,39 @@ gss_inquire_saslname_for_mech(OM_uint32 *minor_status, if (desired_mech == NULL) return GSS_S_BAD_MECH; + major = inquire_saslname_for_mech_compat(minor_status, + desired_mech, + sasl_mech_name, + mech_name, + mech_description); + if (major == GSS_S_COMPLETE) + return major; + major = mo_value(desired_mech, GSS_C_MA_SASL_MECH_NAME, sasl_mech_name); - if (major) return major; + if (major == GSS_S_COMPLETE) { + major = mo_value(desired_mech, GSS_C_MA_MECH_NAME, mech_name); + if (GSS_ERROR(major)) + return major; - major = mo_value(desired_mech, GSS_C_MA_MECH_NAME, mech_name); - if (major) return major; + major = mo_value(desired_mech, GSS_C_MA_MECH_DESCRIPTION, mech_description); + if (GSS_ERROR(major)) + return major; - major = mo_value(desired_mech, GSS_C_MA_MECH_DESCRIPTION, mech_description); - if (major) return major; + return major; + } else { + char buf[16]; + gss_buffer_desc tmp = { sizeof(buf) - 1, buf }; - return GSS_S_COMPLETE; + major = make_sasl_name(minor_status, desired_mech, buf); + if (GSS_ERROR(major)) + return major; + + major = _gss_copy_buffer(minor_status, &tmp, sasl_mech_name); + if (GSS_ERROR(major)) + return major; + } + + return major; } /** @@ -244,28 +342,80 @@ gss_inquire_mech_for_saslname(OM_uint32 *minor_status, struct _gss_mech_switch *m; gss_buffer_desc name; OM_uint32 major; + char buf[16]; _gss_load_mech(); *mech_type = NULL; HEIM_SLIST_FOREACH(m, &_gss_mechs, gm_link) { + if (m->gm_mech.gm_inquire_mech_for_saslname) { + major = m->gm_mech.gm_inquire_mech_for_saslname(minor_status, + sasl_mech_name, + mech_type); + if (major == GSS_S_COMPLETE) + return major; + } - major = mo_value(&m->gm_mech_oid, GSS_C_MA_SASL_MECH_NAME, &name); - if (major) - continue; - if (name.length == sasl_mech_name->length && - memcmp(name.value, sasl_mech_name->value, name.length) == 0) { - gss_release_buffer(&major, &name); - *mech_type = &m->gm_mech_oid; - return 0; + major = mo_value(&m->gm_mech_oid, GSS_C_MA_SASL_MECH_NAME, &name); + if (major == GSS_S_COMPLETE && + name.length == sasl_mech_name->length && + memcmp(name.value, sasl_mech_name->value, name.length) == 0) { + gss_release_buffer(&major, &name); + *mech_type = &m->gm_mech_oid; + return GSS_S_COMPLETE; } gss_release_buffer(&major, &name); + + if (sasl_mech_name->length == 16 && + make_sasl_name(minor_status, &m->gm_mech_oid, buf) == GSS_S_COMPLETE && + memcmp(buf, sasl_mech_name->value, 16) == 0) { + *mech_type = &m->gm_mech_oid; + return GSS_S_COMPLETE; + } } return GSS_S_BAD_MECH; } +/* + * Test mechanism against indicated attributes using both Heimdal and + * MIT SPIs. + */ +static int +test_mech_attrs(gssapi_mech_interface mi, + gss_const_OID_set mech_attrs, + gss_const_OID_set against_attrs, + int except) +{ + size_t n, m; + int eq; + + if (against_attrs == GSS_C_NO_OID_SET) + return 1; + + for (n = 0; n < against_attrs->count; n++) { + for (m = 0; m < mi->gm_mo_num; m++) { + eq = gss_oid_equal(mi->gm_mo[m].option, + &against_attrs->elements[n]); + if (eq) + break; + } + if (mech_attrs != GSS_C_NO_OID_SET) { + for (m = 0; m < mech_attrs->count; m++) { + eq = gss_oid_equal(&mech_attrs->elements[m], + &against_attrs->elements[n]); + if (eq) + break; + } + } + if (!eq ^ except) + return 0; + } + + return 1; +} + /** * Return set of mechanism that fullfill the criteria * @@ -286,57 +436,48 @@ gss_indicate_mechs_by_attrs(OM_uint32 * minor_status, gss_OID_set *mechs) { struct _gss_mech_switch *ms; + gss_OID_set mech_attrs = GSS_C_NO_OID_SET; + gss_OID_set known_mech_attrs = GSS_C_NO_OID_SET; OM_uint32 major; - size_t n, m; major = gss_create_empty_oid_set(minor_status, mechs); - if (major) + if (GSS_ERROR(major)) return major; _gss_load_mech(); HEIM_SLIST_FOREACH(ms, &_gss_mechs, gm_link) { gssapi_mech_interface mi = &ms->gm_mech; + OM_uint32 tmp; - if (desired_mech_attrs) { - for (n = 0; n < desired_mech_attrs->count; n++) { - for (m = 0; m < mi->gm_mo_num; m++) - if (gss_oid_equal(mi->gm_mo[m].option, &desired_mech_attrs->elements[n])) - break; - if (m == mi->gm_mo_num) - goto next; - } - } + if (mi->gm_inquire_attrs_for_mech != NULL) { + major = mi->gm_inquire_attrs_for_mech(minor_status, + &mi->gm_mech_oid, + &mech_attrs, + &known_mech_attrs); + if (GSS_ERROR(major)) + continue; + } - if (except_mech_attrs) { - for (n = 0; n < desired_mech_attrs->count; n++) { - for (m = 0; m < mi->gm_mo_num; m++) { - if (gss_oid_equal(mi->gm_mo[m].option, &desired_mech_attrs->elements[n])) - goto next; - } - } - } + /* + * Test mechanism supports all of desired_mech_attrs; + * none of except_mech_attrs; + * and knows of all critical_mech_attrs. + */ + if (test_mech_attrs(mi, mech_attrs, desired_mech_attrs, 0) && + test_mech_attrs(mi, mech_attrs, except_mech_attrs, 1) && + test_mech_attrs(mi, known_mech_attrs, critical_mech_attrs, 0)) { + major = gss_add_oid_set_member(minor_status, &mi->gm_mech_oid, mechs); + } - if (critical_mech_attrs) { - for (n = 0; n < desired_mech_attrs->count; n++) { - for (m = 0; m < mi->gm_mo_num; m++) { - if (mi->gm_mo[m].flags & GSS_MO_MA_CRITICAL) - continue; - if (gss_oid_equal(mi->gm_mo[m].option, &desired_mech_attrs->elements[n])) - break; - } - if (m == mi->gm_mo_num) - goto next; - } - } + gss_release_oid_set(&tmp, &mech_attrs); + gss_release_oid_set(&tmp, &known_mech_attrs); - - next: - do { } while(0); + if (GSS_ERROR(major)) + break; } - - return GSS_S_FAILURE; + return major; } /** @@ -361,6 +502,9 @@ gss_inquire_attrs_for_mech(OM_uint32 * minor_status, { OM_uint32 major, junk; + if (known_mech_attrs) + *known_mech_attrs = GSS_C_NO_OID_SET; + if (mech_attr && mech) { gssapi_mech_interface m; @@ -369,22 +513,31 @@ gss_inquire_attrs_for_mech(OM_uint32 * minor_status, return GSS_S_BAD_MECH; } - major = gss_create_empty_oid_set(minor_status, mech_attr); - if (major != GSS_S_COMPLETE) + if (m->gm_inquire_attrs_for_mech != NULL) { + major = m->gm_inquire_attrs_for_mech(minor_status, + mech, + mech_attr, + known_mech_attrs); + } else { + major = gss_create_empty_oid_set(minor_status, mech_attr); + if (major == GSS_S_COMPLETE) + add_all_mo(m, mech_attr, GSS_MO_MA); + } + if (GSS_ERROR(major)) return major; - - add_all_mo(m, mech_attr, GSS_MO_MA); - } + } if (known_mech_attrs) { struct _gss_mech_switch *m; - major = gss_create_empty_oid_set(minor_status, known_mech_attrs); - if (major) { - if (mech_attr) - gss_release_oid_set(&junk, mech_attr); - return major; - } + if (*known_mech_attrs == GSS_C_NO_OID_SET) { + major = gss_create_empty_oid_set(minor_status, known_mech_attrs); + if (GSS_ERROR(major)) { + if (mech_attr) + gss_release_oid_set(&junk, mech_attr); + return major; + } + } _gss_load_mech();