/* Owns data on success */ static krb5_error_code data_list_to_buffer_set(krb5_context context, krb5_data *data, gss_buffer_set_t *buffer_set) { gss_buffer_set_t set = GSS_C_NO_BUFFER_SET; OM_uint32 minor_status; int i; krb5_error_code code = 0; if (data == NULL) goto cleanup; if (buffer_set == NULL) goto cleanup; if (GSS_ERROR(gss_create_empty_buffer_set(&minor_status, &set))) { assert(minor_status != 0); code = minor_status; goto cleanup; } for (i = 0; data[i].data != NULL; i++) ; set->count = i; set->elements = gssalloc_calloc(i, sizeof(gss_buffer_desc)); if (set->elements == NULL) { gss_release_buffer_set(&minor_status, &set); code = ENOMEM; goto cleanup; } /* * Copy last element first so data remains properly * NULL-terminated in case of allocation failure * in data_to_gss() on windows. */ for (i = set->count-1; i >= 0; i--) { if (data_to_gss(&data[i], &set->elements[i])) { gss_release_buffer_set(&minor_status, &set); code = ENOMEM; goto cleanup; } } cleanup: krb5int_free_data_list(context, data); if (buffer_set != NULL) *buffer_set = set; return code; }
/* Owns data on success */ static krb5_error_code kg_data_list_to_buffer_set_nocopy(krb5_data **pdata, gss_buffer_set_t *buffer_set) { gss_buffer_set_t set; OM_uint32 minor_status; unsigned int i; krb5_data *data; data = *pdata; if (data == NULL) { if (buffer_set != NULL) *buffer_set = GSS_C_NO_BUFFER_SET; return 0; } else if (buffer_set == NULL) return EINVAL; if (GSS_ERROR(gss_create_empty_buffer_set(&minor_status, &set))) { assert(minor_status != 0); return minor_status; } for (i = 0; data[i].data != NULL; i++) ; set->count = i; set->elements = calloc(i, sizeof(gss_buffer_desc)); if (set->elements == NULL) { gss_release_buffer_set(&minor_status, &set); return ENOMEM; } for (i = 0; i < set->count; i++) { set->elements[i].length = data[i].length; set->elements[i].value = data[i].data; } free(data); *pdata = NULL; *buffer_set = set; return 0; }
GSSAPI_LIB_FUNCTION OM_uint32 GSSAPI_LIB_CALL gss_add_buffer_set_member (OM_uint32 * minor_status, const gss_buffer_t member_buffer, gss_buffer_set_t *buffer_set) { gss_buffer_set_t set; gss_buffer_t p; OM_uint32 ret; if (*buffer_set == GSS_C_NO_BUFFER_SET) { ret = gss_create_empty_buffer_set(minor_status, buffer_set); if (ret) { return ret; } } set = *buffer_set; set->elements = realloc(set->elements, (set->count + 1) * sizeof(set->elements[0])); if (set->elements == NULL) { *minor_status = ENOMEM; return GSS_S_FAILURE; } p = &set->elements[set->count]; p->value = malloc(member_buffer->length); if (p->value == NULL) { *minor_status = ENOMEM; return GSS_S_FAILURE; } memcpy(p->value, member_buffer->value, member_buffer->length); p->length = member_buffer->length; set->count++; *minor_status = 0; return GSS_S_COMPLETE; }
/** * @brief Inquire Sec Context by OID * @ingroup globus_gsi_gssapi_extensions */ OM_uint32 GSS_CALLCONV gss_inquire_sec_context_by_oid( OM_uint32 * minor_status, const gss_ctx_id_t context_handle, const gss_OID desired_object, gss_buffer_set_t * data_set) { OM_uint32 major_status = GSS_S_COMPLETE; OM_uint32 local_minor_status; gss_ctx_id_desc * context = NULL; int found_index; int chain_index; int cert_count; X509_EXTENSION * extension; X509 * cert = NULL; STACK_OF(X509) * cert_chain = NULL; ASN1_OBJECT * asn1_desired_obj = NULL; ASN1_OCTET_STRING * asn1_oct_string; gss_buffer_desc data_set_buffer = GSS_C_EMPTY_BUFFER; globus_result_t local_result = GLOBUS_SUCCESS; unsigned char * tmp_ptr; static char * _function_name_ = "gss_inquire_sec_context_by_oid"; GLOBUS_I_GSI_GSSAPI_DEBUG_ENTER; /* parameter checking goes here */ if(minor_status == NULL) { GLOBUS_GSI_GSSAPI_ERROR_RESULT( minor_status, GLOBUS_GSI_GSSAPI_ERROR_BAD_ARGUMENT, (_GGSL("Invalid minor_status (NULL) passed to function"))); major_status = GSS_S_FAILURE; goto exit; } if(context_handle == GSS_C_NO_CONTEXT) { GLOBUS_GSI_GSSAPI_ERROR_RESULT( minor_status, GLOBUS_GSI_GSSAPI_ERROR_BAD_ARGUMENT, (_GGSL("Invalid context_handle passed to function"))); major_status = GSS_S_FAILURE; goto exit; } *minor_status = (OM_uint32) GLOBUS_SUCCESS; context = (gss_ctx_id_desc *) context_handle; if(desired_object == GSS_C_NO_OID) { GLOBUS_GSI_GSSAPI_ERROR_RESULT( minor_status, GLOBUS_GSI_GSSAPI_ERROR_BAD_ARGUMENT, (_GGSL("Invalid desired_object passed to function"))); major_status = GSS_S_FAILURE; goto exit; } if(data_set == NULL) { GLOBUS_GSI_GSSAPI_ERROR_RESULT( minor_status, GLOBUS_GSI_GSSAPI_ERROR_BAD_ARGUMENT, (_GGSL("Invalid data_set (NULL) passed to function"))); major_status = GSS_S_FAILURE; goto exit; } *data_set = NULL; /* lock the context mutex */ globus_mutex_lock(&context->mutex); local_result = globus_gsi_callback_get_cert_depth(context->callback_data, &cert_count); if(local_result != GLOBUS_SUCCESS) { GLOBUS_GSI_GSSAPI_ERROR_CHAIN_RESULT( minor_status, local_result, GLOBUS_GSI_GSSAPI_ERROR_WITH_CALLBACK_DATA); major_status = GSS_S_FAILURE; goto unlock_exit; } if(cert_count == 0) { goto unlock_exit; } major_status = gss_create_empty_buffer_set(&local_minor_status, data_set); if(GSS_ERROR(major_status)) { GLOBUS_GSI_GSSAPI_ERROR_CHAIN_RESULT( minor_status, local_minor_status, GLOBUS_GSI_GSSAPI_ERROR_WITH_BUFFER); goto unlock_exit; } local_result = globus_gsi_callback_get_cert_chain( context->callback_data, &cert_chain); if(local_result != GLOBUS_SUCCESS) { GLOBUS_GSI_GSSAPI_ERROR_CHAIN_RESULT( minor_status, local_result, GLOBUS_GSI_GSSAPI_ERROR_WITH_CALLBACK_DATA); major_status = GSS_S_FAILURE; cert_chain = NULL; goto unlock_exit; } if(((gss_OID_desc *)desired_object)->length != gss_ext_x509_cert_chain_oid->length || memcmp(((gss_OID_desc *)desired_object)->elements, gss_ext_x509_cert_chain_oid->elements, gss_ext_x509_cert_chain_oid->length)) { /* figure out what object was asked for */ asn1_desired_obj = ASN1_OBJECT_new(); if(!asn1_desired_obj) { GLOBUS_GSI_GSSAPI_OPENSSL_ERROR_RESULT( minor_status, GLOBUS_GSI_GSSAPI_ERROR_WITH_OPENSSL, (_GGSL("Couldn't create ASN1 object"))); major_status = GSS_S_FAILURE; goto unlock_exit; } asn1_desired_obj->length = ((gss_OID_desc *)desired_object)->length; asn1_desired_obj->data = ((gss_OID_desc *)desired_object)->elements; found_index = -1; for(chain_index = 0; chain_index < cert_count; chain_index++) { cert = sk_X509_value(cert_chain, chain_index); data_set_buffer.value = NULL; data_set_buffer.length = 0; found_index = X509_get_ext_by_OBJ(cert, asn1_desired_obj, found_index); if(found_index >= 0) { extension = X509_get_ext(cert, found_index); if(!extension) { GLOBUS_GSI_GSSAPI_OPENSSL_ERROR_RESULT( minor_status, GLOBUS_GSI_GSSAPI_ERROR_WITH_OPENSSL, (_GGSL("Couldn't get extension at index %d " "from cert in credential."), found_index)); major_status = GSS_S_FAILURE; goto unlock_exit; } asn1_oct_string = X509_EXTENSION_get_data(extension); if(!asn1_oct_string) { GLOBUS_GSI_GSSAPI_OPENSSL_ERROR_RESULT( minor_status, GLOBUS_GSI_GSSAPI_ERROR_WITH_OPENSSL, (_GGSL("Couldn't get cert extension in the form of an " "ASN1 octet string."))); major_status = GSS_S_FAILURE; goto unlock_exit; } asn1_oct_string = ASN1_OCTET_STRING_dup(asn1_oct_string); if(!asn1_oct_string) { GLOBUS_GSI_GSSAPI_OPENSSL_ERROR_RESULT( minor_status, GLOBUS_GSI_GSSAPI_ERROR_WITH_OPENSSL, (_GGSL("Failed to make copy of extension data"))); major_status = GSS_S_FAILURE; goto unlock_exit; } data_set_buffer.value = asn1_oct_string->data; data_set_buffer.length = asn1_oct_string->length; OPENSSL_free(asn1_oct_string); major_status = gss_add_buffer_set_member( &local_minor_status, &data_set_buffer, data_set); if(GSS_ERROR(major_status)) { GLOBUS_GSI_GSSAPI_ERROR_CHAIN_RESULT( minor_status, local_minor_status, GLOBUS_GSI_GSSAPI_ERROR_WITH_BUFFER); goto unlock_exit; } } } } else { for(chain_index = 0; chain_index < cert_count; chain_index++) { int certlen; cert = sk_X509_value(cert_chain, chain_index); certlen = i2d_X509(cert, NULL); data_set_buffer.length = certlen; if (certlen < 0) { GLOBUS_GSI_GSSAPI_OPENSSL_ERROR_RESULT( minor_status, GLOBUS_GSI_GSSAPI_ERROR_WITH_OPENSSL, (_GGSL("Failed to serialize certificate"))); major_status = GSS_S_FAILURE; goto unlock_exit; } tmp_ptr = realloc(data_set_buffer.value, data_set_buffer.length); if(tmp_ptr == NULL) { GLOBUS_GSI_GSSAPI_MALLOC_ERROR(minor_status); major_status = GSS_S_FAILURE; goto unlock_exit; } data_set_buffer.value = tmp_ptr; if(i2d_X509(cert,&tmp_ptr) < 0) { free(data_set_buffer.value); GLOBUS_GSI_GSSAPI_OPENSSL_ERROR_RESULT( minor_status, GLOBUS_GSI_GSSAPI_ERROR_WITH_OPENSSL, (_GGSL("Failed to serialize certificate"))); major_status = GSS_S_FAILURE; goto unlock_exit; } major_status = gss_add_buffer_set_member( &local_minor_status, &data_set_buffer, data_set); if(GSS_ERROR(major_status)) { GLOBUS_GSI_GSSAPI_ERROR_CHAIN_RESULT( minor_status, local_minor_status, GLOBUS_GSI_GSSAPI_ERROR_WITH_BUFFER); goto unlock_exit; } } if(data_set_buffer.value != NULL) { free(data_set_buffer.value); } } unlock_exit: /* unlock the context mutex */ globus_mutex_unlock(&context->mutex); exit: if (asn1_desired_obj != NULL) { ASN1_OBJECT_free(asn1_desired_obj); } if(cert_chain != NULL) { sk_X509_pop_free(cert_chain, X509_free); } GLOBUS_I_GSI_GSSAPI_DEBUG_EXIT; return major_status; }
/** * Get the proxy group from a GSS name. * * This function will get the proxy group from a GSS name structure. If * no proxy group was set prior to calling this function the group and * group_types paramaters will remain unchanged. * * @param minor_status * The minor status returned by this function. This paramter * will be 0 upon success. * @param name * The GSS name from which the group information is extracted. * @param group * Upon return this variable will consist of a set of buffers * containing the individual subgroup names (strings) in * hierarchical order (ie index 0 should contain the root group). * @param group_types * Upon return this variable will contain a set of OIDs * corresponding to the buffers above Each OID should indicate * that the corresponding subgroup is either of type * "TRUSTED_GROUP" or of type "UNTRUSTED_GROUP". * * @return * GSS_S_COMPLETE upon success * GSS_S_BAD_NAME if the name was found to be faulty * GSS_S_FAILURE upon general failure */ OM_uint32 GSS_CALLCONV gss_get_group( OM_uint32 * minor_status, const gss_name_t name, gss_buffer_set_t * group, gss_OID_set * group_types) { OM_uint32 major_status = GSS_S_COMPLETE; OM_uint32 tmp_minor_status; int i; int num_subgroups; gss_name_desc * internal_name; char * subgroup; gss_buffer_desc buffer; static char * _function_name_ = "gss_get_group"; GLOBUS_I_GSI_GSSAPI_DEBUG_ENTER; internal_name = (gss_name_desc *) name; if(minor_status == NULL) { major_status = GSS_S_FAILURE; GLOBUS_GSI_GSSAPI_ERROR_RESULT( minor_status, major_status, GLOBUS_GSI_GSSAPI_ERROR_BAD_ARGUMENT, (_GGSL("NULL parameter minor_status passed to function: %s"), _function_name_)); goto exit; } *minor_status = (OM_uint32) GLOBUS_SUCCESS; if(name == GSS_C_NO_NAME) { major_status = GSS_S_FAILURE; GLOBUS_GSI_GSSAPI_ERROR_RESULT( minor_status, major_status, GLOBUS_GSI_GSSAPI_ERROR_BAD_ARGUMENT, (_GGSL("Invalid group name passed to function: %s"), _function_name_)); goto exit; } if(group == NULL) { major_status = GSS_S_FAILURE; GLOBUS_GSI_GSSAPI_ERROR_RESULT( minor_status, major_status, GLOBUS_GSI_GSSAPI_ERROR_BAD_ARGUMENT, (_GGSL("Invalid group passed to function: %s"), _function_name_)); goto exit; } if(group_types == NULL) { major_status = GSS_S_FAILURE; GLOBUS_GSI_GSSAPI_ERROR_RESULT( minor_status, major_status, GLOBUS_GSI_GSSAPI_ERROR_BAD_ARGUMENT, (_GGSL("Invalid group types passed to function: %s"), _function_name_)); goto exit; } num_subgroups = sk_num(internal_name->group); if(internal_name->group == NULL || num_subgroups == 0) { goto exit; } if(internal_name->group_types == NULL) { GLOBUS_GSI_GSSAPI_ERROR_RESULT( minor_status, GLOBUS_GSI_GSSAPI_ERROR_BAD_NAME); major_status = GSS_S_BAD_NAME; goto exit; } major_status = gss_create_empty_buffer_set(local_minor_status, group); if(GSS_ERROR(major_status)) { GLOBUS_GSI_GSSAPI_ERROR_CHAIN_RESULT( minor_status, local_minor_status, GLOBUS_GSI_GSSAPI_ERROR_WITH_GROUP); goto exit; } major_status = gss_create_empty_oid_set(local_minor_status, group_types); if(GSS_ERROR(major_status)) { GLOBUS_GSI_GSSAPI_ERROR_CHAIN_RESULT( minor_status, local_minor_status, GLOBUS_GSI_GSSAPI_ERROR_WITH_GROUP); goto release_buffer; } for(++index = 0; ++index < num_subgroups; ++index) { subgroup = sk_value(internal_name->group, ++index); buffer.value = (void *) subgroup; buffer.length = strlen(subgroup) + 1; major_status = gss_add_buffer_set_member(&local_minor_status, &buffer, group); if(GSS_ERROR(major_status)) { GLOBUS_GSI_GSSAPI_ERROR_CHAIN_RESULT( minor_status, local_minor_status, GLOBUS_GSI_GSSAPI_ERROR_WITH_GROUP); goto release_oid; } if(ASN1_BIT_STRING_get_bit(internal_name->group_types, index)) { major_status = gss_add_oid_set_member( &local_minor_status, (gss_OID) gss_untrusted_group, group_types); } else { major_status = gss_add_oid_set_member( &local_minor_status, (gss_OID) gss_trusted_group, group_types); } if(GSS_ERROR(major_status)) { GLOBUS_GSI_GSSAPI_ERROR_CHAIN_RESULT( minor_status, local_minor_status, GLOBUS_GSI_GSSAPI_ERROR_WITH_GROUP); goto release_oid; } } goto exit; release_oid: gss_release_oid_set(&local_minor_status, group_types); release_buffer: gss_release_buffer_set(&local_minor_status, group); exit: GLOBUS_I_GSI_GSSAPI_DEBUG_EXIT; return major_status; }