| //+build gssapi |
| //+build linux darwin |
| |
| #include <string.h> |
| #include <stdio.h> |
| #include "gss_wrapper.h" |
| |
| OM_uint32 gssapi_canonicalize_name( |
| OM_uint32* minor_status, |
| char *input_name, |
| gss_OID input_name_type, |
| gss_name_t *output_name |
| ) |
| { |
| OM_uint32 major_status; |
| gss_name_t imported_name = GSS_C_NO_NAME; |
| gss_buffer_desc buffer = GSS_C_EMPTY_BUFFER; |
| |
| buffer.value = input_name; |
| buffer.length = strlen(input_name); |
| major_status = gss_import_name(minor_status, &buffer, input_name_type, &imported_name); |
| if (GSS_ERROR(major_status)) { |
| return major_status; |
| } |
| |
| major_status = gss_canonicalize_name(minor_status, imported_name, (gss_OID)gss_mech_krb5, output_name); |
| if (imported_name != GSS_C_NO_NAME) { |
| OM_uint32 ignored; |
| gss_release_name(&ignored, &imported_name); |
| } |
| |
| return major_status; |
| } |
| |
| int gssapi_error_desc( |
| OM_uint32 maj_stat, |
| OM_uint32 min_stat, |
| char **desc |
| ) |
| { |
| OM_uint32 stat = maj_stat; |
| int stat_type = GSS_C_GSS_CODE; |
| if (min_stat != 0) { |
| stat = min_stat; |
| stat_type = GSS_C_MECH_CODE; |
| } |
| |
| OM_uint32 local_maj_stat, local_min_stat; |
| OM_uint32 msg_ctx = 0; |
| gss_buffer_desc desc_buffer; |
| do |
| { |
| local_maj_stat = gss_display_status( |
| &local_min_stat, |
| stat, |
| stat_type, |
| GSS_C_NO_OID, |
| &msg_ctx, |
| &desc_buffer |
| ); |
| if (GSS_ERROR(local_maj_stat)) { |
| return GSSAPI_ERROR; |
| } |
| |
| if (*desc) { |
| free(*desc); |
| } |
| |
| *desc = malloc(desc_buffer.length+1); |
| memcpy(*desc, desc_buffer.value, desc_buffer.length+1); |
| |
| gss_release_buffer(&local_min_stat, &desc_buffer); |
| } |
| while(msg_ctx != 0); |
| |
| return GSSAPI_OK; |
| } |
| |
| int gssapi_client_init( |
| gssapi_client_state *client, |
| char* spn, |
| char* username, |
| char* password |
| ) |
| { |
| client->cred = GSS_C_NO_CREDENTIAL; |
| client->ctx = GSS_C_NO_CONTEXT; |
| |
| client->maj_stat = gssapi_canonicalize_name(&client->min_stat, spn, GSS_C_NT_HOSTBASED_SERVICE, &client->spn); |
| if (GSS_ERROR(client->maj_stat)) { |
| return GSSAPI_ERROR; |
| } |
| |
| if (username) { |
| gss_name_t name; |
| client->maj_stat = gssapi_canonicalize_name(&client->min_stat, username, GSS_C_NT_USER_NAME, &name); |
| if (GSS_ERROR(client->maj_stat)) { |
| return GSSAPI_ERROR; |
| } |
| |
| if (password) { |
| gss_buffer_desc password_buffer; |
| password_buffer.value = password; |
| password_buffer.length = strlen(password); |
| client->maj_stat = gss_acquire_cred_with_password(&client->min_stat, name, &password_buffer, GSS_C_INDEFINITE, GSS_C_NO_OID_SET, GSS_C_INITIATE, &client->cred, NULL, NULL); |
| } else { |
| client->maj_stat = gss_acquire_cred(&client->min_stat, name, GSS_C_INDEFINITE, GSS_C_NO_OID_SET, GSS_C_INITIATE, &client->cred, NULL, NULL); |
| } |
| |
| if (GSS_ERROR(client->maj_stat)) { |
| return GSSAPI_ERROR; |
| } |
| |
| OM_uint32 ignored; |
| gss_release_name(&ignored, &name); |
| } |
| |
| return GSSAPI_OK; |
| } |
| |
| int gssapi_client_username( |
| gssapi_client_state *client, |
| char** username |
| ) |
| { |
| OM_uint32 ignored; |
| gss_name_t name = GSS_C_NO_NAME; |
| |
| client->maj_stat = gss_inquire_context(&client->min_stat, client->ctx, &name, NULL, NULL, NULL, NULL, NULL, NULL); |
| if (GSS_ERROR(client->maj_stat)) { |
| return GSSAPI_ERROR; |
| } |
| |
| gss_buffer_desc name_buffer; |
| client->maj_stat = gss_display_name(&client->min_stat, name, &name_buffer, NULL); |
| if (GSS_ERROR(client->maj_stat)) { |
| gss_release_name(&ignored, &name); |
| return GSSAPI_ERROR; |
| } |
| |
| *username = malloc(name_buffer.length+1); |
| memcpy(*username, name_buffer.value, name_buffer.length+1); |
| |
| gss_release_buffer(&ignored, &name_buffer); |
| gss_release_name(&ignored, &name); |
| return GSSAPI_OK; |
| } |
| |
| int gssapi_client_negotiate( |
| gssapi_client_state *client, |
| void* input, |
| size_t input_length, |
| void** output, |
| size_t* output_length |
| ) |
| { |
| gss_buffer_desc input_buffer = GSS_C_EMPTY_BUFFER; |
| gss_buffer_desc output_buffer = GSS_C_EMPTY_BUFFER; |
| |
| if (input) { |
| input_buffer.value = input; |
| input_buffer.length = input_length; |
| } |
| |
| client->maj_stat = gss_init_sec_context( |
| &client->min_stat, |
| client->cred, |
| &client->ctx, |
| client->spn, |
| GSS_C_NO_OID, |
| GSS_C_MUTUAL_FLAG | GSS_C_SEQUENCE_FLAG, |
| 0, |
| GSS_C_NO_CHANNEL_BINDINGS, |
| &input_buffer, |
| NULL, |
| &output_buffer, |
| NULL, |
| NULL |
| ); |
| |
| if (output_buffer.length) { |
| *output = malloc(output_buffer.length); |
| *output_length = output_buffer.length; |
| memcpy(*output, output_buffer.value, output_buffer.length); |
| |
| OM_uint32 ignored; |
| gss_release_buffer(&ignored, &output_buffer); |
| } |
| |
| if (GSS_ERROR(client->maj_stat)) { |
| return GSSAPI_ERROR; |
| } else if (client->maj_stat == GSS_S_CONTINUE_NEEDED) { |
| return GSSAPI_CONTINUE; |
| } |
| |
| return GSSAPI_OK; |
| } |
| |
| int gssapi_client_wrap_msg( |
| gssapi_client_state *client, |
| void* input, |
| size_t input_length, |
| void** output, |
| size_t* output_length |
| ) |
| { |
| gss_buffer_desc input_buffer = GSS_C_EMPTY_BUFFER; |
| gss_buffer_desc output_buffer = GSS_C_EMPTY_BUFFER; |
| |
| input_buffer.value = input; |
| input_buffer.length = input_length; |
| |
| client->maj_stat = gss_wrap(&client->min_stat, client->ctx, 0, GSS_C_QOP_DEFAULT, &input_buffer, NULL, &output_buffer); |
| |
| if (output_buffer.length) { |
| *output = malloc(output_buffer.length); |
| *output_length = output_buffer.length; |
| memcpy(*output, output_buffer.value, output_buffer.length); |
| |
| gss_release_buffer(&client->min_stat, &output_buffer); |
| } |
| |
| if (GSS_ERROR(client->maj_stat)) { |
| return GSSAPI_ERROR; |
| } |
| |
| return GSSAPI_OK; |
| } |
| |
| int gssapi_client_destroy( |
| gssapi_client_state *client |
| ) |
| { |
| OM_uint32 ignored; |
| if (client->ctx != GSS_C_NO_CONTEXT) { |
| gss_delete_sec_context(&ignored, &client->ctx, GSS_C_NO_BUFFER); |
| } |
| |
| if (client->spn != GSS_C_NO_NAME) { |
| gss_release_name(&ignored, &client->spn); |
| } |
| |
| if (client->cred != GSS_C_NO_CREDENTIAL) { |
| gss_release_cred(&ignored, &client->cred); |
| } |
| |
| return GSSAPI_OK; |
| } |