/** * @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 . * * 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 #include #include #include #include #include "eap_method.h" #include #include #include #include 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_NEXT(eap_type_names, EAP_EXPANDED, EAP_EXPERIMENTAL, EAP_AKA, "EAP_EXPANDED", "EAP_EXPERIMENTAL"); ENUM_END(eap_type_names, EAP_EXPERIMENTAL); 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; u_int32_t vendor; 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 EAP module %d-%d", entry->type, entry->vendor); 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("john@doe.xyz"); 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, &module.vendor); method->destroy(method); if (module.vendor) { DBG1(DBG_CFG, " loaded EAP method %d, vendor %d successfully from %s", module.type, module.vendor, entry->d_name); } else { 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, u_int32_t vendor, 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 && entry->vendor == vendor) { method = entry->constructor(role, server, peer); if (method) { break; } } } iterator->destroy(iterator); if (method == NULL) { if (vendor) { DBG1(DBG_CFG, "no vendor %d specific EAP module found for method " "%d %N", vendor, type, eap_role_names, role); } else { DBG1(DBG_CFG, "no EAP module found for %N %N", eap_type_names, type, eap_role_names, role); } } return method; }