/* -*- mode: c; c-basic-offset: 4; indent-tabs-mode: nil -*- */
/* lib/gssapi/mechglue/g_mechattr.c */
/*
* Copyright (C) 2010 by the Massachusetts Institute of Technology.
* All rights reserved.
*
* Export of this software from the United States of America may
* require a specific license from the United States Government.
* It is the responsibility of any person or organization contemplating
* export to obtain such a license before exporting.
*
* WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
* distribute this software and its documentation for any purpose and
* without fee is hereby granted, provided that the above copyright
* notice appear in all copies and that both that copyright notice and
* this permission notice appear in supporting documentation, and that
* the name of M.I.T. not be used in advertising or publicity pertaining
* to distribution of the software without specific, written prior
* permission. Furthermore if you modify this software you must label
* your software as modified software and not distribute it in such a
* fashion that it might be confused with the original M.I.T. software.
* M.I.T. makes no representations about the suitability of
* this software for any purpose. It is provided "as is" without express
* or implied warranty.
*/
#include "mglueP.h"
static int
testMechAttr(gss_const_OID attr,
gss_const_OID_set against)
{
int present = 0;
OM_uint32 minor;
if (GSS_ERROR(generic_gss_test_oid_set_member(&minor, attr,
(gss_OID_set)against,
&present)))
return 0;
return present;
}
/*
* Return TRUE iff all the elements of desired and none of the elements
* of except exist in available.
*/
static int
testMechAttrsOffered(gss_const_OID_set desired,
gss_const_OID_set except,
gss_const_OID_set available)
{
size_t i;
if (desired != GSS_C_NO_OID_SET) {
for (i = 0; i < desired->count; i++) {
if (!testMechAttr(&desired->elements[i], available))
return 0;
}
}
if (except != GSS_C_NO_OID_SET) {
for (i = 0; i < except->count; i++) {
if (testMechAttr(&except->elements[i], available))
return 0;
}
}
return 1;
}
/*
* Return TRUE iff all the elements of critical exist in known.
*/
static int
testMechAttrsKnown(gss_const_OID_set critical,
gss_const_OID_set known)
{
size_t i;
if (critical != GSS_C_NO_OID_SET) {
for (i = 0; i < critical->count; i++) {
if (!testMechAttr(&critical->elements[i], known))
return 0;
}
}
return 1;
}
OM_uint32 KRB5_CALLCONV
gss_indicate_mechs_by_attrs(
OM_uint32 *minor,
gss_const_OID_set desired_mech_attrs,
gss_const_OID_set except_mech_attrs,
gss_const_OID_set critical_mech_attrs,
gss_OID_set *mechs)
{
OM_uint32 status, tmpMinor;
gss_OID_set allMechs = GSS_C_NO_OID_SET;
size_t i;
if (minor != NULL)
*minor = 0;
if (mechs != NULL)
*mechs = GSS_C_NO_OID_SET;
if (minor == NULL || mechs == NULL)
return GSS_S_CALL_INACCESSIBLE_WRITE;
status = gss_indicate_mechs(minor, &allMechs);
if (GSS_ERROR(status))
goto cleanup;
status = generic_gss_create_empty_oid_set(minor, mechs);
if (GSS_ERROR(status))
goto cleanup;
for (i = 0; i < allMechs->count; i++) {
gss_OID_set supportedAttrs = GSS_C_NO_OID_SET;
gss_OID_set knownAttrs = GSS_C_NO_OID_SET;
status = gss_inquire_attrs_for_mech(minor, &allMechs->elements[i],
&supportedAttrs, &knownAttrs);
if (GSS_ERROR(status))
continue;
if (testMechAttrsOffered(desired_mech_attrs,
except_mech_attrs, supportedAttrs) &&
testMechAttrsKnown(critical_mech_attrs, knownAttrs)) {
status = gss_add_oid_set_member(minor, &allMechs->elements[i],
mechs);
if (GSS_ERROR(status)) {
gss_release_oid_set(&tmpMinor, &supportedAttrs);
gss_release_oid_set(&tmpMinor, &knownAttrs);
goto cleanup;
}
}
gss_release_oid_set(&tmpMinor, &supportedAttrs);
gss_release_oid_set(&tmpMinor, &knownAttrs);
}
*minor = 0;
status = GSS_S_COMPLETE;
cleanup:
gss_release_oid_set(&tmpMinor, &allMechs);
return status;
}
OM_uint32 KRB5_CALLCONV
gss_inquire_attrs_for_mech(
OM_uint32 *minor,
gss_const_OID mech_oid,
gss_OID_set *mech_attrs,
gss_OID_set *known_mech_attrs)
{
OM_uint32 status, tmpMinor;
gss_OID selected_mech, public_mech;
gss_mechanism mech;
if (minor != NULL)
*minor = 0;
if (mech_attrs != NULL)
*mech_attrs = GSS_C_NO_OID_SET;
if (known_mech_attrs != NULL)
*known_mech_attrs = GSS_C_NO_OID_SET;
if (minor == NULL)
return GSS_S_CALL_INACCESSIBLE_WRITE;
status = gssint_select_mech_type(minor, mech_oid, &selected_mech);
if (status != GSS_S_COMPLETE)
return status;
mech = gssint_get_mechanism(selected_mech);
if (mech == NULL)
return GSS_S_BAD_MECH;
/* If the mech does not implement RFC 5587, return success with an empty
* mech_attrs and known_mech_attrs. */
if (mech->gss_inquire_attrs_for_mech == NULL)
return GSS_S_COMPLETE;
public_mech = gssint_get_public_oid(selected_mech);
status = mech->gss_inquire_attrs_for_mech(minor, public_mech, mech_attrs,
known_mech_attrs);
if (GSS_ERROR(status)) {
map_error(minor, mech);
return status;
}
if (known_mech_attrs != NULL && *known_mech_attrs == GSS_C_NO_OID_SET) {
status = generic_gss_copy_oid_set(minor,
gss_ma_known_attrs,
known_mech_attrs);
if (GSS_ERROR(status)) {
gss_release_oid_set(&tmpMinor, mech_attrs);
if (mech_attrs != NULL)
*mech_attrs = GSS_C_NO_OID_SET;
}
}
return GSS_S_COMPLETE;
}
OM_uint32 KRB5_CALLCONV
gss_display_mech_attr(
OM_uint32 *minor,
gss_const_OID mech_attr,
gss_buffer_t name,
gss_buffer_t short_desc,
gss_buffer_t long_desc)
{
return generic_gss_display_mech_attr(minor, mech_attr,
name, short_desc, long_desc);
}