1226031Sstas#include "mech_locl.h" 2226031Sstas#include "heim_threads.h" 3226031Sstas 4226031Sstasstruct mg_thread_ctx { 5226031Sstas gss_OID mech; 6226031Sstas OM_uint32 maj_stat; 7226031Sstas OM_uint32 min_stat; 8226031Sstas gss_buffer_desc maj_error; 9226031Sstas gss_buffer_desc min_error; 10226031Sstas}; 11226031Sstas 12226031Sstasstatic HEIMDAL_MUTEX context_mutex = HEIMDAL_MUTEX_INITIALIZER; 13226031Sstasstatic int created_key; 14226031Sstasstatic HEIMDAL_thread_key context_key; 15226031Sstas 16226031Sstas 17226031Sstasstatic void 18226031Sstasdestroy_context(void *ptr) 19226031Sstas{ 20226031Sstas struct mg_thread_ctx *mg = ptr; 21226031Sstas OM_uint32 junk; 22226031Sstas 23226031Sstas if (mg == NULL) 24226031Sstas return; 25226031Sstas 26226031Sstas gss_release_buffer(&junk, &mg->maj_error); 27226031Sstas gss_release_buffer(&junk, &mg->min_error); 28226031Sstas free(mg); 29226031Sstas} 30226031Sstas 31226031Sstas 32226031Sstasstatic struct mg_thread_ctx * 33226031Sstas_gss_mechglue_thread(void) 34226031Sstas{ 35226031Sstas struct mg_thread_ctx *ctx; 36226031Sstas int ret = 0; 37226031Sstas 38226031Sstas HEIMDAL_MUTEX_lock(&context_mutex); 39226031Sstas 40226031Sstas if (!created_key) { 41226031Sstas HEIMDAL_key_create(&context_key, destroy_context, ret); 42226031Sstas if (ret) { 43226031Sstas HEIMDAL_MUTEX_unlock(&context_mutex); 44226031Sstas return NULL; 45226031Sstas } 46226031Sstas created_key = 1; 47226031Sstas } 48226031Sstas HEIMDAL_MUTEX_unlock(&context_mutex); 49226031Sstas 50226031Sstas ctx = HEIMDAL_getspecific(context_key); 51226031Sstas if (ctx == NULL) { 52226031Sstas 53226031Sstas ctx = calloc(1, sizeof(*ctx)); 54226031Sstas if (ctx == NULL) 55226031Sstas return NULL; 56226031Sstas HEIMDAL_setspecific(context_key, ctx, ret); 57226031Sstas if (ret) { 58226031Sstas free(ctx); 59226031Sstas return NULL; 60226031Sstas } 61226031Sstas } 62226031Sstas return ctx; 63226031Sstas} 64226031Sstas 65226031SstasOM_uint32 66226031Sstas_gss_mg_get_error(const gss_OID mech, OM_uint32 type, 67226031Sstas OM_uint32 value, gss_buffer_t string) 68226031Sstas{ 69226031Sstas struct mg_thread_ctx *mg; 70226031Sstas 71226031Sstas mg = _gss_mechglue_thread(); 72226031Sstas if (mg == NULL) 73226031Sstas return GSS_S_BAD_STATUS; 74226031Sstas 75226031Sstas#if 0 76226031Sstas /* 77226031Sstas * We cant check the mech here since a pseudo-mech might have 78226031Sstas * called an lower layer and then the mech info is all broken 79226031Sstas */ 80226031Sstas if (mech != NULL && gss_oid_equal(mg->mech, mech) == 0) 81226031Sstas return GSS_S_BAD_STATUS; 82226031Sstas#endif 83226031Sstas 84226031Sstas switch (type) { 85226031Sstas case GSS_C_GSS_CODE: { 86226031Sstas if (value != mg->maj_stat || mg->maj_error.length == 0) 87226031Sstas break; 88226031Sstas string->value = malloc(mg->maj_error.length + 1); 89226031Sstas string->length = mg->maj_error.length; 90226031Sstas memcpy(string->value, mg->maj_error.value, mg->maj_error.length); 91226031Sstas ((char *) string->value)[string->length] = '\0'; 92226031Sstas return GSS_S_COMPLETE; 93226031Sstas } 94226031Sstas case GSS_C_MECH_CODE: { 95226031Sstas if (value != mg->min_stat || mg->min_error.length == 0) 96226031Sstas break; 97226031Sstas string->value = malloc(mg->min_error.length + 1); 98226031Sstas string->length = mg->min_error.length; 99226031Sstas memcpy(string->value, mg->min_error.value, mg->min_error.length); 100226031Sstas ((char *) string->value)[string->length] = '\0'; 101226031Sstas return GSS_S_COMPLETE; 102226031Sstas } 103226031Sstas } 104226031Sstas string->value = NULL; 105226031Sstas string->length = 0; 106226031Sstas return GSS_S_BAD_STATUS; 107226031Sstas} 108226031Sstas 109226031Sstasvoid 110226031Sstas_gss_mg_error(gssapi_mech_interface m, OM_uint32 maj, OM_uint32 min) 111226031Sstas{ 112226031Sstas OM_uint32 major_status, minor_status; 113226031Sstas OM_uint32 message_content; 114226031Sstas struct mg_thread_ctx *mg; 115226031Sstas 116226031Sstas /* 117226031Sstas * Mechs without gss_display_status() does 118226031Sstas * gss_mg_collect_error() by themself. 119226031Sstas */ 120226031Sstas if (m->gm_display_status == NULL) 121226031Sstas return ; 122226031Sstas 123226031Sstas mg = _gss_mechglue_thread(); 124226031Sstas if (mg == NULL) 125226031Sstas return; 126226031Sstas 127226031Sstas gss_release_buffer(&minor_status, &mg->maj_error); 128226031Sstas gss_release_buffer(&minor_status, &mg->min_error); 129226031Sstas 130226031Sstas mg->mech = &m->gm_mech_oid; 131226031Sstas mg->maj_stat = maj; 132226031Sstas mg->min_stat = min; 133226031Sstas 134226031Sstas major_status = m->gm_display_status(&minor_status, 135226031Sstas maj, 136226031Sstas GSS_C_GSS_CODE, 137226031Sstas &m->gm_mech_oid, 138226031Sstas &message_content, 139226031Sstas &mg->maj_error); 140226031Sstas if (GSS_ERROR(major_status)) { 141226031Sstas mg->maj_error.value = NULL; 142226031Sstas mg->maj_error.length = 0; 143226031Sstas } 144226031Sstas major_status = m->gm_display_status(&minor_status, 145226031Sstas min, 146226031Sstas GSS_C_MECH_CODE, 147226031Sstas &m->gm_mech_oid, 148226031Sstas &message_content, 149226031Sstas &mg->min_error); 150226031Sstas if (GSS_ERROR(major_status)) { 151226031Sstas mg->min_error.value = NULL; 152226031Sstas mg->min_error.length = 0; 153226031Sstas } 154226031Sstas} 155226031Sstas 156226031Sstasvoid 157226031Sstasgss_mg_collect_error(gss_OID mech, OM_uint32 maj, OM_uint32 min) 158226031Sstas{ 159226031Sstas gssapi_mech_interface m = __gss_get_mechanism(mech); 160226031Sstas if (m == NULL) 161226031Sstas return; 162226031Sstas _gss_mg_error(m, maj, min); 163226031Sstas} 164