/* GSS-PROXY Copyright (C) 2012 Red Hat, Inc. Copyright (C) 2012 Simo Sorce Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ #include "gss_plugin.h" #include #define KRB5_OID_LEN 9 #define KRB5_OID "\052\206\110\206\367\022\001\002\002" #define KRB5_OLD_OID_LEN 5 #define KRB5_OLD_OID "\053\005\001\005\002" /* Incorrect krb5 mech OID emitted by MS. */ #define KRB5_WRONG_OID_LEN 9 #define KRB5_WRONG_OID "\052\206\110\202\367\022\001\002\002" #define IAKERB_OID_LEN 6 #define IAKERB_OID "\053\006\001\005\002\005" const gss_OID_desc gpoid_krb5 = { .length = KRB5_OID_LEN, .elements = KRB5_OID }; const gss_OID_desc gpoid_krb5_old = { .length = KRB5_OLD_OID_LEN, .elements = KRB5_OLD_OID }; const gss_OID_desc gpoid_krb5_wrong = { .length = KRB5_WRONG_OID_LEN, .elements = KRB5_WRONG_OID }; const gss_OID_desc gpoid_iakerb = { .length = IAKERB_OID_LEN, .elements = IAKERB_OID }; /* 2.16.840.1.113730.3.8.15.1 */ const gss_OID_desc gssproxy_mech_interposer = { .length = 11, .elements = "\140\206\110\001\206\370\102\003\010\017\001" }; gss_OID_set gss_mech_interposer(gss_OID mech_type) { gss_OID_set interposed_mechs; OM_uint32 maj, min; char *envval; /* avoid looping in the gssproxy daemon by avoiding to interpose * any mechanism */ envval = getenv("_GSSPROXY_LOOPS"); if (envval && strcmp(envval, "NO") == 0) { return NULL; } interposed_mechs = NULL; maj = 0; if (gss_oid_equal(&gssproxy_mech_interposer, mech_type)) { maj = gss_create_empty_oid_set(&min, &interposed_mechs); if (maj != 0) { return NULL; } maj = gss_add_oid_set_member(&min, no_const(&gpoid_krb5), &interposed_mechs); if (maj != 0) { goto done; } maj = gss_add_oid_set_member(&min, no_const(&gpoid_krb5_old), &interposed_mechs); if (maj != 0) { goto done; } maj = gss_add_oid_set_member(&min, no_const(&gpoid_krb5_wrong), &interposed_mechs); if (maj != 0) { goto done; } maj = gss_add_oid_set_member(&min, no_const(&gpoid_iakerb), &interposed_mechs); if (maj != 0) { goto done; } } done: if (maj != 0) { (void)gss_release_oid_set(&min, &interposed_mechs); interposed_mechs = NULL; } return interposed_mechs; } #define SP_KRB5_OID_LEN (KRB5_OID_LEN + 1) #define SP_KRB5_OID "\377" KRB5_OID #define SP_KRB5_OLD_OID_LEN (KRB5_OLD_OID_LEN + 1) #define SP_KRB5_OLD_OID "\377" KRB5_OLD_OID #define SP_KRB5_WRONG_OID_LEN (KRB5_WRONG_OID_LEN + 1) #define SP_KRB5_WRONG_OID "\377" KRB5_WRONG_OID #define SP_IAKERB_OID_LEN (IAKERB_OID_LEN + 1) #define SP_IAKERB_OID "\377" IAKERB_OID const gss_OID_desc gpoid_sp_krb5 = { .length = SP_KRB5_OID_LEN, .elements = SP_KRB5_OID }; const gss_OID_desc gpoid_sp_krb5_old = { .length = SP_KRB5_OLD_OID_LEN, .elements = SP_KRB5_OLD_OID }; const gss_OID_desc gpoid_sp_krb5_wrong = { .length = SP_KRB5_WRONG_OID_LEN, .elements = SP_KRB5_WRONG_OID }; const gss_OID_desc gpoid_sp_iakerb = { .length = SP_IAKERB_OID_LEN, .elements = SP_IAKERB_OID }; /* In future we may want to make this structure dynamic so we can proxy * arbitrary mechanisms based on what the server returns. */ struct gpm_mechs { gss_OID_desc const * real; gss_OID_desc const * special; } gpm_mechs[] = { { &gpoid_krb5, &gpoid_sp_krb5, }, { &gpoid_krb5_old, &gpoid_sp_krb5_old, }, { &gpoid_krb5_wrong, &gpoid_sp_krb5_wrong, }, { &gpoid_iakerb, &gpoid_sp_iakerb, }, { NULL, NULL } }; const gss_OID gpm_special_mech(const gss_OID mech_type) { int i; if (mech_type == GSS_C_NO_OID) { /* return the first special one if none specified */ return (const gss_OID)gpm_mechs[0].special; } for (i = 0; gpm_mechs[i].real != NULL; i++) { if (gss_oid_equal(gpm_mechs[i].real, mech_type)) { return (const gss_OID)gpm_mechs[i].special; } } return mech_type; } gss_OID_set gpm_special_available_mechs(const gss_OID_set mechs) { gss_OID_set amechs = GSS_C_NO_OID_SET; uint32_t maj, min; unsigned i, j; maj = gss_create_empty_oid_set(&min, &amechs); if (maj) { return GSS_C_NO_OID_SET; } for (i = 0; i < mechs->count; i++) { for (j = 0; gpm_mechs[j].real != NULL; j++) { if (gss_oid_equal(gpm_mechs[i].real, &mechs->elements[i])) { maj = gss_add_oid_set_member(&min, no_const(gpm_mechs[i].special), &amechs); if (maj) { goto done; } break; } } /* none of the ones we intercept */ if (gpm_mechs[j].real == NULL) { /* check if one is our own OID */ if (gss_oid_equal(&gssproxy_mech_interposer, &mechs->elements[i])) { /* just skip */ continue; } /* If nothing matched just copy verbatim */ maj = gss_add_oid_set_member(&min, &mechs->elements[i], &amechs); if (maj) { goto done; } } } if (amechs->count == 0) { maj = GSS_S_FAILURE; } else { maj = GSS_S_COMPLETE; } done: if (maj) { (void)gss_release_oid_set(&min, &amechs); } return amechs; } #define MAP_ERROR_BASE 0x04200000 uint32_t gpm_map_error(uint32_t err) { /* placeholder, * we will need an actual map but to speed up testing just make a sum with * a special base and hope no conflicts will happen in the mechglue */ if (err) { err += MAP_ERROR_BASE; } return err; } uint32_t gpm_unmap_error(uint32_t err) { /* placeholder, * we will need an actual map but to speed up testing just make a sum with * a special base and hope no conflicts will happen in the mechglue */ if (err) { err -= MAP_ERROR_BASE; } return err; } /* gssi_acquire_cred gssi_release_cred gssi_init_sec_context gssi_accept_sec_context gssi_process_context_token gssi_delete_sec_context gssi_context_time gssi_get_mic gssi_verify_mic gssi_wrap gssi_unwrap gssi_display_status gssi_indicate_mechs gssi_compare_name gssi_display_name gssi_import_name gssi_release_name gssi_inquire_cred gssi_add_cred gssi_export_sec_context gssi_import_sec_context gssi_inquire_cred_by_mech gssi_inquire_names_for_mech gssi_inquire_context gssi_internal_release_oid gssi_wrap_size_limit gssi_localname gssi_authorize_localname gssi_export_name gssi_duplicate_name gssi_store_cred gssi_inquire_sec_context_by_oid gssi_inquire_cred_by_oid gssi_set_sec_context_option gssi_set_cred_option gssi_mech_invoke gssi_wrap_aead gssi_unwrap_aead gssi_wrap_iov gssi_unwrap_iov gssi_wrap_iov_length gssi_complete_auth_token gssi_acquire_cred_impersonate_name gssi_add_cred_impersonate_name gssi_display_name_ext gssi_inquire_name gssi_get_name_attribute gssi_set_name_attribute gssi_delete_name_attribute gssi_export_name_composite gssi_map_name_to_any gssi_release_any_name_mapping gssi_pseudo_random gssi_set_neg_mechs gssi_inquire_saslname_for_mech gssi_inquire_mech_for_saslname gssi_inquire_attrs_for_mech */