#include <stdlib.h>
#include <unistd.h>
#include <sys/queue.h>
#include <string.h>
#include "EAPClientModule.h"
typedef struct {
EAPType eap_type;
const char * eap_name;
EAPClientPluginFuncIntrospect * introspect;
EAPClientPluginFuncVersion * version;
EAPClientPluginFuncInit * init;
EAPClientPluginFuncFree * free;
EAPClientPluginFuncProcess * process;
EAPClientPluginFuncFreePacket * free_packet;
EAPClientPluginFuncFailureString * failure_string;
EAPClientPluginFuncSessionKey * session_key;
EAPClientPluginFuncSessionKey * server_key;
EAPClientPluginFuncRequireProperties * require_properties;
EAPClientPluginFuncPublishProperties * publish_properties;
EAPClientPluginFuncPacketDump * packet_dump;
EAPClientPluginFuncUserName * user_name;
EAPClientPluginFuncCopyIdentity * copy_identity;
} EAPClientInfo, *EAPClientInfoRef;
struct EAPClientModule_s {
TAILQ_ENTRY(EAPClientModule_s) link;
char * name;
EAPClientInfoRef info;
};
static TAILQ_HEAD(EAPClientModuleHead, EAPClientModule_s) S_head
= TAILQ_HEAD_INITIALIZER(S_head);
static struct EAPClientModuleHead * S_EAPClientModuleHead_p = &S_head;
EAPClientModuleRef
EAPClientModuleLookup(EAPType type)
{
EAPClientModuleRef scan;
TAILQ_FOREACH(scan, S_EAPClientModuleHead_p, link) {
if (scan->info->eap_type == type)
return (scan);
}
return (NULL);
}
EAPType
EAPClientModulePluginEAPType(EAPClientModuleRef module)
{
return (module->info->eap_type);
}
const char *
EAPClientModulePluginEAPName(EAPClientModuleRef module)
{
return (module->info->eap_name);
}
EAPType
EAPClientModuleDefaultType(void)
{
return (TAILQ_FIRST(S_EAPClientModuleHead_p)->info->eap_type);
}
static EAPClientModuleStatus
EAPClientModuleValidatePlugin(const EAPClientInfoRef info)
{
if (info->init == NULL
|| info->version == NULL
|| info->free == NULL
|| info->process == NULL
|| info->free_packet == NULL) {
return (kEAPClientModuleStatusPluginIncomplete);
}
if ((*info->version)() != kEAPClientPluginVersion) {
return (kEAPClientModuleStatusPluginInvalidVersion);
}
return (kEAPClientModuleStatusOK);
}
static EAPClientModuleStatus
EAPClientModuleAdd(const EAPClientInfoRef info)
{
EAPClientModuleRef module;
module = malloc(sizeof(*module));
if (module == NULL) {
return (kEAPClientModuleStatusAllocationFailed);
}
bzero(module, sizeof(*module));
module->info = info;
TAILQ_INSERT_TAIL(S_EAPClientModuleHead_p, module, link);
return (kEAPClientModuleStatusOK);
}
static void
EAPClientModuleInit(void)
{
static int first;
if (first == TRUE) {
return;
}
first = TRUE;
return;
}
EAPClientModuleStatus
EAPClientModuleAddBuiltinModule(EAPClientPluginFuncIntrospect * func)
{
EAPType eap_type;
const char * eap_name;
EAPClientInfoRef info = NULL;
EAPClientPluginFuncEAPName *name_func;
EAPClientModuleStatus status = kEAPClientModuleStatusOK;
EAPClientPluginFuncEAPType *type_func;
EAPClientModuleInit();
type_func = (EAPClientPluginFuncEAPType *)
(*func)(kEAPClientPluginFuncNameEAPType);
if (type_func == NULL) {
status = kEAPClientModuleStatusPluginIncomplete;
goto failed;
}
name_func = (EAPClientPluginFuncEAPName *)
(*func)(kEAPClientPluginFuncNameEAPName);
if (name_func == NULL) {
status = kEAPClientModuleStatusPluginIncomplete;
goto failed;
}
eap_type = (*type_func)();
if (eap_type <= 0 || eap_type > 255) {
status = kEAPClientModuleStatusInvalidType;
goto failed;
}
eap_name = (*name_func)();
if (eap_name == NULL) {
status = kEAPClientModuleStatusPluginIncomplete;
goto failed;
}
if (EAPClientModuleLookup(eap_type)) {
status = kEAPClientModuleStatusTypeAlreadyLoaded;
goto failed;
}
info = malloc(sizeof(*info));
if (info == NULL) {
status = kEAPClientModuleStatusAllocationFailed;
goto failed;
}
bzero(info, sizeof(*info));
info->eap_type = eap_type;
info->eap_name = eap_name;
info->introspect = (EAPClientPluginFuncIntrospect *)
(*func)(kEAPClientPluginFuncNameIntrospect);
info->init = (EAPClientPluginFuncInit *)
(*func)(kEAPClientPluginFuncNameInit);
info->version = (EAPClientPluginFuncVersion *)
(*func)(kEAPClientPluginFuncNameVersion);
info->free = (EAPClientPluginFuncFree *)
(*func)(kEAPClientPluginFuncNameFree);
info->process = (EAPClientPluginFuncProcess *)
(*func)(kEAPClientPluginFuncNameProcess);
info->free_packet = (EAPClientPluginFuncFreePacket *)
(*func)(kEAPClientPluginFuncNameFreePacket);
info->failure_string = (EAPClientPluginFuncFailureString *)
(*func)(kEAPClientPluginFuncNameFailureString);
info->session_key = (EAPClientPluginFuncSessionKey *)
(*func)(kEAPClientPluginFuncNameSessionKey);
info->server_key = (EAPClientPluginFuncServerKey *)
(*func)(kEAPClientPluginFuncNameServerKey);
info->require_properties = (EAPClientPluginFuncRequireProperties *)
(*func)(kEAPClientPluginFuncNameRequireProperties);
info->publish_properties = (EAPClientPluginFuncPublishProperties *)
(*func)(kEAPClientPluginFuncNamePublishProperties);
info->packet_dump = (EAPClientPluginFuncPacketDump *)
(*func)(kEAPClientPluginFuncNamePacketDump);
info->user_name = (EAPClientPluginFuncUserName *)
(*func)(kEAPClientPluginFuncNameUserName);
info->copy_identity = (EAPClientPluginFuncCopyIdentity *)
(*func)(kEAPClientPluginFuncNameCopyIdentity);
status = EAPClientModuleValidatePlugin(info);
if (status != kEAPClientModuleStatusOK) {
goto failed;
}
status = EAPClientModuleAdd(info);
if (status != kEAPClientModuleStatusOK) {
goto failed;
}
return (status);
failed:
if (info != NULL) {
free (info);
}
return (status);
}
EAPClientPluginFuncRef
EAPClientModulePluginIntrospect(EAPClientModuleRef module,
EAPClientPluginFuncName name)
{
const EAPClientInfoRef info = module->info;
if (info->introspect == NULL) {
return (NULL);
}
return ((*info->introspect)(name));
}
EAPClientStatus
EAPClientModulePluginInit(EAPClientModuleRef module,
EAPClientPluginDataRef plugin,
CFArrayRef * require_props, int * error)
{
EAPClientPluginFuncInit * init = module->info->init;
if (init == NULL) {
return (kEAPClientStatusFailed);
}
return (*init)(plugin, require_props, error);
}
void
EAPClientModulePluginFree(EAPClientModuleRef module,
EAPClientPluginDataRef plugin)
{
EAPClientPluginFuncFree * free = module->info->free;
if (free == NULL) {
return;
}
return (*free)(plugin);
}
void
EAPClientModulePluginFreePacket(EAPClientModuleRef module,
EAPClientPluginDataRef plugin,
EAPPacketRef pkt_p)
{
EAPClientPluginFuncFreePacket * free_packet = module->info->free_packet;
if (free_packet == NULL) {
return;
}
return (*free_packet)(plugin, pkt_p);
}
EAPClientState
EAPClientModulePluginProcess(EAPClientModuleRef module,
EAPClientPluginDataRef plugin,
const EAPPacketRef in_pkt,
EAPPacketRef * out_pkt_p,
EAPClientStatus * status,
EAPClientDomainSpecificError * error)
{
EAPClientPluginFuncProcess * process = module->info->process;
if (process == NULL) {
return (kEAPClientStateFailure);
}
return (*process)(plugin, in_pkt, out_pkt_p, status, error);
}
const char *
EAPClientModulePluginFailureString(EAPClientModuleRef module,
EAPClientPluginDataRef plugin)
{
EAPClientPluginFuncFailureString * failure_string;
failure_string = module->info->failure_string;
if (failure_string == NULL) {
return (NULL);
}
return (*failure_string)(plugin);
}
void *
EAPClientModulePluginSessionKey(EAPClientModuleRef module,
EAPClientPluginDataRef plugin, int * key_length)
{
EAPClientPluginFuncSessionKey * session_key;
session_key = module->info->session_key;
if (session_key == NULL) {
return (NULL);
}
return (*session_key)(plugin, key_length);
}
void *
EAPClientModulePluginServerKey(EAPClientModuleRef module,
EAPClientPluginDataRef plugin, int * key_length)
{
EAPClientPluginFuncServerKey * server_key;
server_key = module->info->server_key;
if (server_key == NULL) {
return (NULL);
}
return (*server_key)(plugin, key_length);
}
CFArrayRef
EAPClientModulePluginRequireProperties(EAPClientModuleRef module,
EAPClientPluginDataRef plugin)
{
EAPClientPluginFuncRequireProperties * require_properties;
require_properties = module->info->require_properties;
if (require_properties == NULL) {
return (NULL);
}
return (*require_properties)(plugin);
}
CFDictionaryRef
EAPClientModulePluginPublishProperties(EAPClientModuleRef module,
EAPClientPluginDataRef plugin)
{
EAPClientPluginFuncPublishProperties * publish_properties;
publish_properties = module->info->publish_properties;
if (publish_properties == NULL) {
return (NULL);
}
return (*publish_properties)(plugin);
}
bool
EAPClientModulePluginPacketDump(EAPClientModuleRef module,
FILE * out_f, const EAPPacketRef packet)
{
EAPClientPluginFuncPacketDump * packet_dump;
packet_dump = module->info->packet_dump;
if (packet_dump == NULL) {
return (FALSE);
}
if (out_f == NULL || packet == NULL) {
return (TRUE);
}
return (*packet_dump)(out_f, packet);
}
CFStringRef
EAPClientModulePluginUserName(EAPClientModuleRef module,
CFDictionaryRef properties)
{
EAPClientPluginFuncUserName * user_name;
user_name = module->info->user_name;
if (user_name == NULL) {
return (NULL);
}
return (*user_name)(properties);
}
CFStringRef
EAPClientModulePluginCopyIdentity(EAPClientModuleRef module,
EAPClientPluginDataRef plugin)
{
EAPClientPluginFuncCopyIdentity * identity;
identity = module->info->copy_identity;
if (identity == NULL) {
return (NULL);
}
return (*identity)(plugin);
}