213 lines
4.8 KiB
C
213 lines
4.8 KiB
C
/**
|
|
* @file eap_method.c
|
|
*
|
|
* @brief Generic constructor for eap_methods.
|
|
*
|
|
*/
|
|
|
|
/*
|
|
* Copyright (C) 2006 Martin Willi
|
|
* Hochschule fuer Technik Rapperswil
|
|
*
|
|
* This program is free software; you can redistribute it and/or modify it
|
|
* under the terms of the GNU General Public License as published by the
|
|
* Free Software Foundation; either version 2 of the License, or (at your
|
|
* option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
|
|
*
|
|
* This program is distributed in the hope that it will be useful, but
|
|
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
|
|
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
|
* for more details.
|
|
*/
|
|
|
|
#include <string.h>
|
|
#include <sys/stat.h>
|
|
#include <dirent.h>
|
|
#include <error.h>
|
|
#include <dlfcn.h>
|
|
|
|
#include "eap_method.h"
|
|
|
|
#include <daemon.h>
|
|
#include <library.h>
|
|
#include <utils/linked_list.h>
|
|
#include <utils/identification.h>
|
|
|
|
|
|
ENUM_BEGIN(eap_type_names, EAP_IDENTITY, EAP_TOKEN_CARD,
|
|
"EAP_IDENTITY",
|
|
"EAP_NOTIFICATION",
|
|
"EAP_NAK",
|
|
"EAP_MD5",
|
|
"EAP_ONE_TIME_PASSWORD",
|
|
"EAP_TOKEN_CARD");
|
|
ENUM_NEXT(eap_type_names, EAP_SIM, EAP_SIM, EAP_TOKEN_CARD,
|
|
"EAP_SIM");
|
|
ENUM_NEXT(eap_type_names, EAP_AKA, EAP_AKA, EAP_SIM,
|
|
"EAP_AKA");
|
|
ENUM_END(eap_type_names, EAP_AKA);
|
|
|
|
ENUM(eap_code_names, EAP_REQUEST, EAP_FAILURE,
|
|
"EAP_REQUEST",
|
|
"EAP_RESPONSE",
|
|
"EAP_SUCCESS",
|
|
"EAP_FAILURE",
|
|
);
|
|
|
|
ENUM(eap_role_names, EAP_SERVER, EAP_PEER,
|
|
"EAP_SERVER",
|
|
"EAP_PEER",
|
|
);
|
|
|
|
|
|
typedef struct module_entry_t module_entry_t;
|
|
|
|
/**
|
|
* Representation of a loaded module: EAP type, library handle, constructor
|
|
*/
|
|
struct module_entry_t {
|
|
eap_type_t type;
|
|
void *handle;
|
|
eap_constructor_t constructor;
|
|
};
|
|
|
|
/** List of module_entry_t's */
|
|
static linked_list_t *modules = NULL;
|
|
|
|
/**
|
|
* unload modules at daemon shutdown
|
|
*/
|
|
void eap_method_unload()
|
|
{
|
|
if (modules)
|
|
{
|
|
module_entry_t *entry;
|
|
|
|
while (modules->remove_last(modules, (void**)&entry) == SUCCESS)
|
|
{
|
|
DBG2(DBG_CFG, "unloaded module for %s", eap_type_names, entry->type);
|
|
dlclose(entry->handle);
|
|
free(entry);
|
|
}
|
|
modules->destroy(modules);
|
|
modules = NULL;
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Load EAP modules at daemon startup
|
|
*/
|
|
void eap_method_load(char *directory)
|
|
{
|
|
struct dirent* entry;
|
|
DIR* dir;
|
|
|
|
eap_method_unload();
|
|
modules = linked_list_create();
|
|
|
|
dir = opendir(directory);
|
|
if (dir == NULL)
|
|
{
|
|
DBG1(DBG_CFG, "error opening EAP modules directory %s", directory);
|
|
return;
|
|
}
|
|
|
|
DBG1(DBG_CFG, "loading EAP modules from '%s'", directory);
|
|
|
|
while ((entry = readdir(dir)) != NULL)
|
|
{
|
|
char file[256];
|
|
module_entry_t module, *loaded_module;
|
|
eap_method_t *method;
|
|
identification_t *id;
|
|
char *ending;
|
|
|
|
snprintf(file, sizeof(file), "%s/%s", directory, entry->d_name);
|
|
|
|
ending = entry->d_name + strlen(entry->d_name) - 3;
|
|
if (ending <= entry->d_name || !streq(ending, ".so"))
|
|
{
|
|
/* skip anything which does not look like a library */
|
|
DBG2(DBG_CFG, " skipping %s, doesn't look like a library",
|
|
entry->d_name);
|
|
continue;
|
|
}
|
|
|
|
/* try to load the library */
|
|
module.handle = dlopen(file, RTLD_LAZY);
|
|
if (module.handle == NULL)
|
|
{
|
|
DBG1(DBG_CFG, " opening EAP module %s failed: %s", entry->d_name,
|
|
dlerror());
|
|
continue;
|
|
}
|
|
module.constructor = dlsym(module.handle, "eap_create");
|
|
if (module.constructor == NULL)
|
|
{
|
|
DBG1(DBG_CFG, " EAP module %s has no eap_create() function, skipped",
|
|
entry->d_name);
|
|
dlclose(module.handle);
|
|
continue;
|
|
}
|
|
|
|
/* get the type implemented in the method, create an instance for it */
|
|
id = identification_create_from_string("[email protected]");
|
|
method = module.constructor(EAP_SERVER, id, id);
|
|
if (method == NULL)
|
|
{
|
|
method = module.constructor(EAP_PEER, id, id);
|
|
}
|
|
id->destroy(id);
|
|
if (method == NULL)
|
|
{
|
|
DBG1(DBG_CFG, " unable to create instance of EAP method %s, skipped",
|
|
entry->d_name);
|
|
dlclose(module.handle);
|
|
continue;
|
|
}
|
|
module.type = method->get_type(method);
|
|
method->destroy(method);
|
|
|
|
DBG1(DBG_CFG, " loaded EAP method %N successfully from %s",
|
|
eap_type_names, module.type, entry->d_name);
|
|
|
|
loaded_module = malloc_thing(module_entry_t);
|
|
memcpy(loaded_module, &module, sizeof(module));
|
|
modules->insert_last(modules, loaded_module);
|
|
}
|
|
closedir(dir);
|
|
}
|
|
|
|
/*
|
|
* Described in header.
|
|
*/
|
|
eap_method_t *eap_method_create(eap_type_t type, eap_role_t role,
|
|
identification_t *server,
|
|
identification_t *peer)
|
|
{
|
|
eap_method_t *method = NULL;
|
|
iterator_t *iterator;
|
|
module_entry_t *entry;
|
|
|
|
iterator = modules->create_iterator(modules, TRUE);
|
|
while (iterator->iterate(iterator, (void**)&entry))
|
|
{
|
|
if (entry->type == type)
|
|
{
|
|
method = entry->constructor(role, server, peer);
|
|
if (method)
|
|
{
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
iterator->destroy(iterator);
|
|
|
|
if (method == NULL)
|
|
{
|
|
DBG1(DBG_CFG, "no EAP module found for %N %N",
|
|
eap_type_names, type, eap_role_names, role);
|
|
}
|
|
return method;
|
|
}
|