#include "mglueP.h"
#include "gss_libinit.h"
#ifdef HAVE_STDLIB_H
#include <stdlib.h>
#endif
#include <stdio.h>
#include <string.h>
#include <ctype.h>
#include <errno.h>
#define M_DEFAULT "default"
#include "k5-thread.h"
static gss_mech_info searchMechList(const gss_OID);
static void updateMechList(void);
static void register_mech(gss_mechanism, const char *, void *);
static OM_uint32 build_mechSet(void);
static void init_hardcoded(void);
static gss_mech_info g_mechList = NULL;
static gss_mech_info g_mechListTail = NULL;
static k5_mutex_t g_mechListLock = K5_MUTEX_PARTIAL_INITIALIZER;
static gss_OID_set_desc g_mechSet = { 0, NULL };
static k5_mutex_t g_mechSetLock = K5_MUTEX_PARTIAL_INITIALIZER;
int
gssint_mechglue_init(void)
{
int err;
err = k5_mutex_finish_init(&g_mechSetLock);
return k5_mutex_finish_init(&g_mechListLock);
}
void
gssint_mechglue_fini(void)
{
k5_mutex_destroy(&g_mechSetLock);
k5_mutex_destroy(&g_mechListLock);
}
OM_uint32 KRB5_CALLCONV
gss_release_oid(minor_status, oid)
OM_uint32 *minor_status;
gss_OID *oid;
{
OM_uint32 major;
gss_mech_info aMech;
if (gssint_initialize_library())
return GSS_S_FAILURE;
if (minor_status == NULL)
return (GSS_S_CALL_INACCESSIBLE_WRITE);
*minor_status = 0;
k5_mutex_lock(&g_mechListLock);
aMech = g_mechList;
while (aMech != NULL) {
if (aMech->mech && aMech->mech->gss_internal_release_oid) {
major = aMech->mech->gss_internal_release_oid(
aMech->mech->context,
minor_status, oid);
if (major == GSS_S_COMPLETE) {
k5_mutex_unlock(&g_mechListLock);
return (GSS_S_COMPLETE);
}
}
aMech = aMech->next;
}
k5_mutex_unlock(&g_mechListLock);
return (generic_gss_release_oid(minor_status, oid));
}
OM_uint32 KRB5_CALLCONV
gss_indicate_mechs(minorStatus, mechSet)
OM_uint32 *minorStatus;
gss_OID_set *mechSet;
{
int i, j;
gss_OID curItem;
if (minorStatus != NULL)
*minorStatus = 0;
if (mechSet != NULL)
*mechSet = GSS_C_NO_OID_SET;
if (minorStatus == NULL || mechSet == NULL)
return (GSS_S_CALL_INACCESSIBLE_WRITE);
if (gssint_initialize_library())
return GSS_S_FAILURE;
if (build_mechSet())
return GSS_S_FAILURE;
if ((*mechSet =
(gss_OID_set) malloc(sizeof (gss_OID_set_desc))) == NULL)
{
return (GSS_S_FAILURE);
}
(void) k5_mutex_lock(&g_mechSetLock);
if (((*mechSet)->elements =
(void*) calloc(g_mechSet.count, sizeof (gss_OID_desc)))
== NULL)
{
(void) k5_mutex_unlock(&g_mechSetLock);
free(*mechSet);
*mechSet = NULL;
return (GSS_S_FAILURE);
}
(void) memcpy((*mechSet)->elements, g_mechSet.elements,
g_mechSet.count * sizeof (gss_OID_desc));
(*mechSet)->count = g_mechSet.count;
for (i = 0; i < (*mechSet)->count; i++) {
curItem = &((*mechSet)->elements[i]);
curItem->elements =
(void *) malloc(g_mechSet.elements[i].length);
if (curItem->elements == NULL) {
(void) k5_mutex_unlock(&g_mechSetLock);
for (j = 0; j < i; j++) {
free((*mechSet)->elements[j].elements);
}
free((*mechSet)->elements);
free(mechSet);
*mechSet = NULL;
return (GSS_S_FAILURE);
}
g_OID_copy(curItem, &g_mechSet.elements[i]);
}
(void) k5_mutex_unlock(&g_mechSetLock);
return (GSS_S_COMPLETE);
}
static OM_uint32
build_mechSet(void)
{
gss_mech_info mList;
int i, count;
gss_OID curItem;
(void) k5_mutex_lock(&g_mechListLock);
updateMechList();
(void) k5_mutex_lock(&g_mechSetLock);
if (g_mechSet.count != 0) {
for (i = 0; i < g_mechSet.count; i++)
free(g_mechSet.elements[i].elements);
free(g_mechSet.elements);
g_mechSet.elements = NULL;
g_mechSet.count = 0;
}
mList = g_mechList;
count = 0;
while (mList != NULL) {
count++;
mList = mList->next;
}
if (count > 0) {
g_mechSet.elements =
(gss_OID) calloc(count, sizeof (gss_OID_desc));
if (g_mechSet.elements == NULL) {
(void) k5_mutex_unlock(&g_mechSetLock);
(void) k5_mutex_unlock(&g_mechListLock);
return (GSS_S_FAILURE);
}
(void) memset(g_mechSet.elements, 0,
count * sizeof (gss_OID_desc));
g_mechSet.count = count;
count = 0;
mList = g_mechList;
while (mList != NULL) {
curItem = &(g_mechSet.elements[count]);
curItem->elements = (void*)
malloc(mList->mech_type->length);
if (curItem->elements == NULL) {
for (i = 0; i < count; i++) {
free(g_mechSet.elements[i].
elements);
}
free(g_mechSet.elements);
g_mechSet.count = 0;
g_mechSet.elements = NULL;
(void) k5_mutex_unlock(&g_mechSetLock);
(void) k5_mutex_unlock(&g_mechListLock);
return (GSS_S_FAILURE);
}
g_OID_copy(curItem, mList->mech_type);
count++;
mList = mList->next;
}
}
(void) k5_mutex_unlock(&g_mechSetLock);
(void) k5_mutex_unlock(&g_mechListLock);
return GSS_S_COMPLETE;
}
char *
gssint_get_modOptions(oid)
const gss_OID oid;
{
gss_mech_info aMech;
char *modOptions = NULL;
(void) k5_mutex_lock(&g_mechListLock);
updateMechList();
if ((aMech = searchMechList(oid)) == NULL ||
aMech->optionStr == NULL) {
(void) k5_mutex_unlock(&g_mechListLock);
return (NULL);
}
if (aMech->optionStr)
modOptions = strdup(aMech->optionStr);
(void) k5_mutex_unlock(&g_mechListLock);
return (modOptions);
}
OM_uint32
gssint_mech_to_oid(const char *mechStr, gss_OID* oid)
{
gss_mech_info aMech;
if (oid == NULL)
return (GSS_S_CALL_INACCESSIBLE_WRITE);
*oid = GSS_C_NULL_OID;
if ((mechStr == NULL) || (strlen(mechStr) == 0) ||
(strcasecmp(mechStr, M_DEFAULT) == 0))
return (GSS_S_COMPLETE);
(void) k5_mutex_lock(&g_mechListLock);
updateMechList();
(void) k5_mutex_unlock(&g_mechListLock);
aMech = g_mechList;
while (aMech != NULL) {
if ((aMech->mechNameStr) &&
strcmp(aMech->mechNameStr, mechStr) == 0) {
*oid = aMech->mech_type;
return (GSS_S_COMPLETE);
}
aMech = aMech->next;
}
return (GSS_S_FAILURE);
}
const char *
gssint_oid_to_mech(const gss_OID oid)
{
gss_mech_info aMech;
if (oid == GSS_C_NULL_OID)
return (M_DEFAULT);
(void) k5_mutex_lock(&g_mechListLock);
updateMechList();
aMech = searchMechList(oid);
(void) k5_mutex_unlock(&g_mechListLock);
if (aMech == NULL)
return (NULL);
return (aMech->mechNameStr);
}
OM_uint32
gssint_get_mechanisms(char *mechArray[], int arrayLen)
{
gss_mech_info aMech;
int i;
if (gssint_initialize_library())
return GSS_S_FAILURE;
if (mechArray == NULL || arrayLen < 1)
return (GSS_S_CALL_INACCESSIBLE_WRITE);
(void) k5_mutex_lock(&g_mechListLock);
updateMechList();
(void) k5_mutex_unlock(&g_mechListLock);
aMech = g_mechList;
for (i = 1; i < arrayLen; i++) {
if (aMech != NULL) {
*mechArray = aMech->mechNameStr;
mechArray++;
aMech = aMech->next;
} else
break;
}
*mechArray = NULL;
return (GSS_S_COMPLETE);
}
static void
updateMechList(void)
{
init_hardcoded();
}
static void
register_mech(gss_mechanism mech, const char *namestr, void *dl_handle)
{
gss_mech_info cf, new_cf;
new_cf = malloc(sizeof(*new_cf));
if (new_cf == NULL)
return;
memset(new_cf, 0, sizeof(*new_cf));
new_cf->kmodName = NULL;
new_cf->uLibName = strdup(namestr);
new_cf->mechNameStr = strdup(mech->mechNameStr);
new_cf->mech_type = &mech->mech_type;
new_cf->mech = mech;
new_cf->next = NULL;
if (g_mechList == NULL) {
g_mechList = new_cf;
g_mechListTail = new_cf;
return;
} else if (mech->priority < g_mechList->mech->priority) {
new_cf->next = g_mechList;
g_mechList = new_cf;
return;
}
for (cf = g_mechList; cf != NULL; cf = cf->next) {
if (cf->next == NULL ||
mech->priority < cf->next->mech->priority) {
new_cf->next = cf->next;
cf->next = new_cf;
if (g_mechListTail == cf) {
g_mechListTail = new_cf;
}
break;
}
}
}
static void
init_hardcoded(void)
{
extern gss_mechanism *krb5_gss_get_mech_configs(void);
extern gss_mechanism *spnego_gss_get_mech_configs(void);
gss_mechanism *cflist;
static int inited;
if (inited)
return;
cflist = krb5_gss_get_mech_configs();
if (cflist == NULL)
return;
for ( ; *cflist != NULL; cflist++) {
register_mech(*cflist, "<builtin krb5>", NULL);
}
cflist = spnego_gss_get_mech_configs();
if (cflist == NULL)
return;
for ( ; *cflist != NULL; cflist++) {
register_mech(*cflist, "<builtin spnego>", NULL);
}
inited = 1;
}
gss_mechanism
gssint_get_mechanism(gss_OID oid)
{
gss_mech_info aMech;
if (gssint_initialize_library())
return NULL;
(void) k5_mutex_lock(&g_mechListLock);
if ((aMech = searchMechList(oid)) != NULL && aMech->mech) {
(void) k5_mutex_unlock(&g_mechListLock);
return (aMech->mech);
}
updateMechList();
aMech = searchMechList(oid);
if (aMech == NULL) {
(void) k5_mutex_unlock(&g_mechListLock);
return ((gss_mechanism)NULL);
}
if (aMech->mech) {
(void) k5_mutex_unlock(&g_mechListLock);
return (aMech->mech);
} else {
return NULL;
}
}
static gss_mech_info searchMechList(oid)
const gss_OID oid;
{
gss_mech_info aMech = g_mechList;
if (oid == GSS_C_NULL_OID)
return (aMech);
while (aMech != NULL) {
if (g_OID_equal(aMech->mech_type, oid))
return (aMech);
aMech = aMech->next;
}
return ((gss_mech_info) NULL);
}