/* Copyright (C) 2011 the GSS-PROXY contributors, see COPYING for license */
#include "gssapi_gpm.h"
OM_uint32 gpm_display_name(OM_uint32 *minor_status,
gssx_name *in_name,
gss_buffer_t output_name_buffer,
gss_OID *output_name_type)
{
gss_buffer_desc input_name_buffer = GSS_C_EMPTY_BUFFER;
gssx_name *output_name = NULL;
uint32_t ret_maj;
uint32_t ret_min;
uint32_t discard;
int ret;
if (!minor_status) {
return GSS_S_CALL_INACCESSIBLE_WRITE;
}
*minor_status = 0;
if (!in_name) {
return GSS_S_CALL_INACCESSIBLE_READ;
}
if (!output_name_buffer) {
return GSS_S_CALL_INACCESSIBLE_WRITE;
}
if (in_name->display_name.octet_string_len == 0) {
if (in_name->exported_name.octet_string_len == 0) {
return GSS_S_BAD_NAME;
}
gp_conv_gssx_to_buffer(&in_name->exported_name, &input_name_buffer);
ret_maj = gpm_import_name(&ret_min, &input_name_buffer,
GSS_C_NT_EXPORT_NAME, &output_name);
if (ret_maj) {
goto done;
}
/* steal display_name and name_type */
in_name->display_name = output_name->display_name;
output_name->display_name.octet_string_len = 0;
output_name->display_name.octet_string_val = NULL;
in_name->name_type = output_name->name_type;
output_name->name_type.octet_string_len = 0;
output_name->name_type.octet_string_val = NULL;
}
ret = gp_copy_gssx_to_string_buffer(&in_name->display_name,
output_name_buffer);
if (ret) {
ret_min = ret;
ret_maj = GSS_S_FAILURE;
goto done;
}
if (output_name_type) {
ret = gp_conv_gssx_to_oid_alloc(&in_name->name_type, output_name_type);
if (ret) {
gss_release_buffer(&discard, output_name_buffer);
ret_min = ret;
ret_maj = GSS_S_FAILURE;
goto done;
}
}
ret_min = 0;
ret_maj = GSS_S_COMPLETE;
done:
if (output_name) {
xdr_free((xdrproc_t)xdr_gssx_name, (char *)output_name);
free(output_name);
}
*minor_status = ret_min;
return ret_maj;
}
OM_uint32 gpm_import_name(OM_uint32 *minor_status,
gss_buffer_t input_name_buffer,
gss_OID input_name_type,
gssx_name **output_name)
{
gssx_name *name;
uint32_t maj, min;
int ret;
if (!minor_status) {
return GSS_S_CALL_INACCESSIBLE_WRITE;
}
*minor_status = 0;
if (!input_name_buffer || !input_name_type) {
return GSS_S_CALL_INACCESSIBLE_READ;
}
if (!output_name) {
return GSS_S_CALL_INACCESSIBLE_WRITE;
}
/* ignore call_ctx for now */
maj = GSS_S_FAILURE;
name = calloc(1, sizeof(gssx_name));
if (!name) {
ret = ENOMEM;
goto done;
}
ret = gp_conv_buffer_to_gssx(input_name_buffer, &name->display_name);
if (ret) {
goto done;
}
ret = gp_conv_oid_to_gssx(input_name_type, &name->name_type);
if (ret) {
goto done;
}
maj = GSS_S_COMPLETE;
done:
*minor_status = ret;
if (maj == GSS_S_COMPLETE) {
*output_name = name;
} else {
(void)gpm_release_name(&min, &name);
}
return maj;
}
OM_uint32 gpm_export_name(OM_uint32 *minor_status,
gssx_name *input_name,
gss_buffer_t exported_name)
{
int ret;
if (!minor_status) {
return GSS_S_CALL_INACCESSIBLE_WRITE;
}
*minor_status = 0;
if (!input_name) {
return GSS_S_CALL_INACCESSIBLE_READ;
}
if (input_name->exported_name.octet_string_len == 0) {
return GSS_S_NAME_NOT_MN;
}
ret = gp_copy_gssx_to_buffer(&input_name->exported_name, exported_name);
if (ret) {
*minor_status = ret;
return GSS_S_FAILURE;
}
return GSS_S_COMPLETE;
}
OM_uint32 gpm_export_name_composite(OM_uint32 *minor_status,
gssx_name *input_name,
gss_buffer_t exported_composite_name)
{
int ret;
if (!minor_status) {
return GSS_S_CALL_INACCESSIBLE_WRITE;
}
*minor_status = 0;
if (!input_name) {
return GSS_S_CALL_INACCESSIBLE_READ;
}
if (input_name->exported_composite_name.octet_string_len == 0) {
return GSS_S_NAME_NOT_MN;
}
ret = gp_copy_gssx_to_buffer(&input_name->exported_composite_name,
exported_composite_name);
if (ret) {
*minor_status = ret;
return GSS_S_FAILURE;
}
return GSS_S_COMPLETE;
}
OM_uint32 gpm_duplicate_name(OM_uint32 *minor_status,
gssx_name *input_name,
gssx_name **dest_name)
{
int ret;
ret = gp_copy_gssx_name_alloc(input_name, dest_name);
if (ret) {
*minor_status = ret;
return GSS_S_FAILURE;
}
return GSS_S_COMPLETE;
}
OM_uint32 gpm_canonicalize_name(OM_uint32 *minor_status,
gssx_name *input_name,
const gss_OID mech_type,
gssx_name **output_name)
{
union gp_rpc_arg uarg;
union gp_rpc_res ures;
gssx_arg_import_and_canon_name *arg = &uarg.import_and_canon_name;
gssx_res_import_and_canon_name *res = &ures.import_and_canon_name;
uint32_t ret_maj;
uint32_t ret_min;
int ret;
if (!minor_status) {
return GSS_S_CALL_INACCESSIBLE_WRITE;
}
*minor_status = 0;
if (!input_name || !mech_type) {
return GSS_S_CALL_INACCESSIBLE_READ;
}
if (!output_name) {
return GSS_S_CALL_INACCESSIBLE_WRITE;
}
memset(arg, 0, sizeof(gssx_arg_import_and_canon_name));
memset(res, 0, sizeof(gssx_res_import_and_canon_name));
/* ignore call_ctx for now */
ret = gp_copy_gssx_name(input_name, &arg->input_name);
if (ret) {
goto done;
}
ret = gp_conv_oid_to_gssx(mech_type, &arg->mech);
if (ret) {
goto done;
}
/* execute proxy request */
ret = gpm_make_call(GSSX_IMPORT_AND_CANON_NAME, &uarg, &ures);
if (ret) {
goto done;
}
ret_min = res->status.minor_status;
ret_maj = res->status.major_status;
if (res->status.major_status) {
gpm_save_status(&res->status);
ret = 0;
goto done;
}
/* steal output_name */
*output_name = res->output_name;
res->output_name = NULL;
done:
if (ret) {
ret_min = ret;
ret_maj = GSS_S_FAILURE;
}
gpm_free_xdrs(GSSX_IMPORT_AND_CANON_NAME, &uarg, &ures);
*minor_status = ret_min;
return ret_maj;
}
OM_uint32 gpm_inquire_name(OM_uint32 *minor_status,
gssx_name *name,
int *name_is_MN,
gss_OID *MN_mech,
gss_buffer_set_t *attrs)
{
gss_buffer_set_t xattrs = GSS_C_NO_BUFFER_SET;
int ret;
*minor_status = 0;
if (name->exported_name.octet_string_len != 0) {
if (name_is_MN != NULL) {
*name_is_MN = 1;
}
}
if (MN_mech != NULL) {
ret = gp_conv_gssx_to_oid_alloc(&name->name_type, MN_mech);
if (ret) {
*minor_status = ret;
return GSS_S_FAILURE;
}
}
if (name->name_attributes.name_attributes_len != 0) {
xattrs = calloc(1, sizeof(gss_buffer_set_desc));
if (!xattrs) {
*minor_status = ENOMEM;
return GSS_S_FAILURE;
}
xattrs->count = name->name_attributes.name_attributes_len;
xattrs->elements = calloc(xattrs->count, sizeof(gss_buffer_desc));
if (!xattrs->elements) {
free(xattrs);
*minor_status = ENOMEM;
return GSS_S_FAILURE;
}
for (unsigned i = 0; i < xattrs->count; i++) {
ret = gp_copy_gssx_to_buffer(
&name->name_attributes.name_attributes_val[i].attr,
&xattrs->elements[i]);
if (ret) {
for (; i > 0; i--) {
free(xattrs->elements[i-1].value);
}
free(xattrs->elements);
free(xattrs);
*minor_status = ENOMEM;
return GSS_S_FAILURE;
}
}
}
*attrs = xattrs;
return GSS_S_COMPLETE;
}
OM_uint32 gpm_release_name(OM_uint32 *minor_status,
gssx_name **input_name)
{
*minor_status = 0;
if (*input_name != NULL) {
xdr_free((xdrproc_t)xdr_gssx_name, (char *)(*input_name));
free(*input_name);
*input_name = NULL;
}
return GSS_S_COMPLETE;
}
OM_uint32 gpm_compare_name(OM_uint32 *minor_status,
gssx_name *name1,
gssx_name *name2,
int *name_equal)
{
gss_buffer_desc buf1 = {0};
gss_buffer_desc buf2 = {0};
gss_OID type1 = GSS_C_NO_OID;
gss_OID type2 = GSS_C_NO_OID;
uint32_t ret_maj;
uint32_t ret_min;
int c;
*name_equal = 0;
ret_maj = gpm_display_name(&ret_min, name1, &buf1, &type1);
if (ret_maj != GSS_S_COMPLETE) {
goto done;
}
ret_maj = gpm_display_name(&ret_min, name2, &buf2, &type2);
if (ret_maj != GSS_S_COMPLETE) {
goto done;
}
c = buf1.length - buf2.length;
if (c == 0) {
c = memcmp(buf1.value, buf2.value, buf1.length);
if (c == 0) {
c = gss_oid_equal(type1, type2);
}
}
if (c != 0) {
*name_equal = 1;
}
ret_min = 0;
ret_maj = GSS_S_COMPLETE;
done:
*minor_status = ret_min;
gss_release_buffer(&ret_min, &buf1);
gss_release_buffer(&ret_min, &buf2);
gss_release_oid(&ret_min, &type1);
gss_release_oid(&ret_min, &type2);
return ret_maj;
}