16d49e1aeSJan Lentfer /*
26d49e1aeSJan Lentfer * EAP peer: Method registration
36d49e1aeSJan Lentfer * Copyright (c) 2004-2007, Jouni Malinen <j@w1.fi>
46d49e1aeSJan Lentfer *
53ff40c12SJohn Marino * This software may be distributed under the terms of the BSD license.
63ff40c12SJohn Marino * See README for more details.
76d49e1aeSJan Lentfer */
86d49e1aeSJan Lentfer
96d49e1aeSJan Lentfer #include "includes.h"
106d49e1aeSJan Lentfer #ifdef CONFIG_DYNAMIC_EAP_METHODS
116d49e1aeSJan Lentfer #include <dlfcn.h>
126d49e1aeSJan Lentfer #endif /* CONFIG_DYNAMIC_EAP_METHODS */
136d49e1aeSJan Lentfer
146d49e1aeSJan Lentfer #include "common.h"
156d49e1aeSJan Lentfer #include "eap_i.h"
166d49e1aeSJan Lentfer #include "eap_methods.h"
176d49e1aeSJan Lentfer
186d49e1aeSJan Lentfer
196d49e1aeSJan Lentfer static struct eap_method *eap_methods = NULL;
206d49e1aeSJan Lentfer
21*a1157835SDaniel Fojt static void eap_peer_method_free(struct eap_method *method);
22*a1157835SDaniel Fojt
236d49e1aeSJan Lentfer
246d49e1aeSJan Lentfer /**
256d49e1aeSJan Lentfer * eap_peer_get_eap_method - Get EAP method based on type number
266d49e1aeSJan Lentfer * @vendor: EAP Vendor-Id (0 = IETF)
276d49e1aeSJan Lentfer * @method: EAP type number
286d49e1aeSJan Lentfer * Returns: Pointer to EAP method or %NULL if not found
296d49e1aeSJan Lentfer */
eap_peer_get_eap_method(int vendor,EapType method)306d49e1aeSJan Lentfer const struct eap_method * eap_peer_get_eap_method(int vendor, EapType method)
316d49e1aeSJan Lentfer {
326d49e1aeSJan Lentfer struct eap_method *m;
336d49e1aeSJan Lentfer for (m = eap_methods; m; m = m->next) {
346d49e1aeSJan Lentfer if (m->vendor == vendor && m->method == method)
356d49e1aeSJan Lentfer return m;
366d49e1aeSJan Lentfer }
376d49e1aeSJan Lentfer return NULL;
386d49e1aeSJan Lentfer }
396d49e1aeSJan Lentfer
406d49e1aeSJan Lentfer
416d49e1aeSJan Lentfer /**
426d49e1aeSJan Lentfer * eap_peer_get_type - Get EAP type for the given EAP method name
436d49e1aeSJan Lentfer * @name: EAP method name, e.g., TLS
446d49e1aeSJan Lentfer * @vendor: Buffer for returning EAP Vendor-Id
456d49e1aeSJan Lentfer * Returns: EAP method type or %EAP_TYPE_NONE if not found
466d49e1aeSJan Lentfer *
476d49e1aeSJan Lentfer * This function maps EAP type names into EAP type numbers based on the list of
486d49e1aeSJan Lentfer * EAP methods included in the build.
496d49e1aeSJan Lentfer */
eap_peer_get_type(const char * name,int * vendor)506d49e1aeSJan Lentfer EapType eap_peer_get_type(const char *name, int *vendor)
516d49e1aeSJan Lentfer {
526d49e1aeSJan Lentfer struct eap_method *m;
536d49e1aeSJan Lentfer for (m = eap_methods; m; m = m->next) {
546d49e1aeSJan Lentfer if (os_strcmp(m->name, name) == 0) {
556d49e1aeSJan Lentfer *vendor = m->vendor;
566d49e1aeSJan Lentfer return m->method;
576d49e1aeSJan Lentfer }
586d49e1aeSJan Lentfer }
596d49e1aeSJan Lentfer *vendor = EAP_VENDOR_IETF;
606d49e1aeSJan Lentfer return EAP_TYPE_NONE;
616d49e1aeSJan Lentfer }
626d49e1aeSJan Lentfer
636d49e1aeSJan Lentfer
646d49e1aeSJan Lentfer /**
656d49e1aeSJan Lentfer * eap_get_name - Get EAP method name for the given EAP type
666d49e1aeSJan Lentfer * @vendor: EAP Vendor-Id (0 = IETF)
676d49e1aeSJan Lentfer * @type: EAP method type
686d49e1aeSJan Lentfer * Returns: EAP method name, e.g., TLS, or %NULL if not found
696d49e1aeSJan Lentfer *
706d49e1aeSJan Lentfer * This function maps EAP type numbers into EAP type names based on the list of
716d49e1aeSJan Lentfer * EAP methods included in the build.
726d49e1aeSJan Lentfer */
eap_get_name(int vendor,EapType type)736d49e1aeSJan Lentfer const char * eap_get_name(int vendor, EapType type)
746d49e1aeSJan Lentfer {
756d49e1aeSJan Lentfer struct eap_method *m;
763ff40c12SJohn Marino if (vendor == EAP_VENDOR_IETF && type == EAP_TYPE_EXPANDED)
773ff40c12SJohn Marino return "expanded";
786d49e1aeSJan Lentfer for (m = eap_methods; m; m = m->next) {
796d49e1aeSJan Lentfer if (m->vendor == vendor && m->method == type)
806d49e1aeSJan Lentfer return m->name;
816d49e1aeSJan Lentfer }
826d49e1aeSJan Lentfer return NULL;
836d49e1aeSJan Lentfer }
846d49e1aeSJan Lentfer
856d49e1aeSJan Lentfer
866d49e1aeSJan Lentfer /**
876d49e1aeSJan Lentfer * eap_get_names - Get space separated list of names for supported EAP methods
886d49e1aeSJan Lentfer * @buf: Buffer for names
896d49e1aeSJan Lentfer * @buflen: Buffer length
906d49e1aeSJan Lentfer * Returns: Number of characters written into buf (not including nul
916d49e1aeSJan Lentfer * termination)
926d49e1aeSJan Lentfer */
eap_get_names(char * buf,size_t buflen)936d49e1aeSJan Lentfer size_t eap_get_names(char *buf, size_t buflen)
946d49e1aeSJan Lentfer {
956d49e1aeSJan Lentfer char *pos, *end;
966d49e1aeSJan Lentfer struct eap_method *m;
976d49e1aeSJan Lentfer int ret;
986d49e1aeSJan Lentfer
996d49e1aeSJan Lentfer if (buflen == 0)
1006d49e1aeSJan Lentfer return 0;
1016d49e1aeSJan Lentfer
1026d49e1aeSJan Lentfer pos = buf;
1036d49e1aeSJan Lentfer end = pos + buflen;
1046d49e1aeSJan Lentfer
1056d49e1aeSJan Lentfer for (m = eap_methods; m; m = m->next) {
1066d49e1aeSJan Lentfer ret = os_snprintf(pos, end - pos, "%s%s",
1076d49e1aeSJan Lentfer m == eap_methods ? "" : " ", m->name);
108*a1157835SDaniel Fojt if (os_snprintf_error(end - pos, ret))
1096d49e1aeSJan Lentfer break;
1106d49e1aeSJan Lentfer pos += ret;
1116d49e1aeSJan Lentfer }
1126d49e1aeSJan Lentfer buf[buflen - 1] = '\0';
1136d49e1aeSJan Lentfer
1146d49e1aeSJan Lentfer return pos - buf;
1156d49e1aeSJan Lentfer }
1166d49e1aeSJan Lentfer
1176d49e1aeSJan Lentfer
1186d49e1aeSJan Lentfer /**
1196d49e1aeSJan Lentfer * eap_get_names_as_string_array - Get supported EAP methods as string array
1206d49e1aeSJan Lentfer * @num: Buffer for returning the number of items in array, not including %NULL
1216d49e1aeSJan Lentfer * terminator. This parameter can be %NULL if the length is not needed.
1226d49e1aeSJan Lentfer * Returns: A %NULL-terminated array of strings, or %NULL on error.
1236d49e1aeSJan Lentfer *
1246d49e1aeSJan Lentfer * This function returns the list of names for all supported EAP methods as an
1256d49e1aeSJan Lentfer * array of strings. The caller must free the returned array items and the
1266d49e1aeSJan Lentfer * array.
1276d49e1aeSJan Lentfer */
eap_get_names_as_string_array(size_t * num)1286d49e1aeSJan Lentfer char ** eap_get_names_as_string_array(size_t *num)
1296d49e1aeSJan Lentfer {
1306d49e1aeSJan Lentfer struct eap_method *m;
1316d49e1aeSJan Lentfer size_t array_len = 0;
1326d49e1aeSJan Lentfer char **array;
1336d49e1aeSJan Lentfer int i = 0, j;
1346d49e1aeSJan Lentfer
1356d49e1aeSJan Lentfer for (m = eap_methods; m; m = m->next)
1366d49e1aeSJan Lentfer array_len++;
1376d49e1aeSJan Lentfer
138*a1157835SDaniel Fojt array = os_calloc(array_len + 1, sizeof(char *));
1396d49e1aeSJan Lentfer if (array == NULL)
1406d49e1aeSJan Lentfer return NULL;
1416d49e1aeSJan Lentfer
1426d49e1aeSJan Lentfer for (m = eap_methods; m; m = m->next) {
1436d49e1aeSJan Lentfer array[i++] = os_strdup(m->name);
1446d49e1aeSJan Lentfer if (array[i - 1] == NULL) {
1456d49e1aeSJan Lentfer for (j = 0; j < i; j++)
1466d49e1aeSJan Lentfer os_free(array[j]);
1476d49e1aeSJan Lentfer os_free(array);
1486d49e1aeSJan Lentfer return NULL;
1496d49e1aeSJan Lentfer }
1506d49e1aeSJan Lentfer }
1516d49e1aeSJan Lentfer array[i] = NULL;
1526d49e1aeSJan Lentfer
1536d49e1aeSJan Lentfer if (num)
1546d49e1aeSJan Lentfer *num = array_len;
1556d49e1aeSJan Lentfer
1566d49e1aeSJan Lentfer return array;
1576d49e1aeSJan Lentfer }
1586d49e1aeSJan Lentfer
1596d49e1aeSJan Lentfer
1606d49e1aeSJan Lentfer /**
1616d49e1aeSJan Lentfer * eap_peer_get_methods - Get a list of enabled EAP peer methods
1626d49e1aeSJan Lentfer * @count: Set to number of available methods
1636d49e1aeSJan Lentfer * Returns: List of enabled EAP peer methods
1646d49e1aeSJan Lentfer */
eap_peer_get_methods(size_t * count)1656d49e1aeSJan Lentfer const struct eap_method * eap_peer_get_methods(size_t *count)
1666d49e1aeSJan Lentfer {
1676d49e1aeSJan Lentfer int c = 0;
1686d49e1aeSJan Lentfer struct eap_method *m;
1696d49e1aeSJan Lentfer
1706d49e1aeSJan Lentfer for (m = eap_methods; m; m = m->next)
1716d49e1aeSJan Lentfer c++;
1726d49e1aeSJan Lentfer
1736d49e1aeSJan Lentfer *count = c;
1746d49e1aeSJan Lentfer return eap_methods;
1756d49e1aeSJan Lentfer }
1766d49e1aeSJan Lentfer
1776d49e1aeSJan Lentfer
1786d49e1aeSJan Lentfer #ifdef CONFIG_DYNAMIC_EAP_METHODS
1796d49e1aeSJan Lentfer /**
1806d49e1aeSJan Lentfer * eap_peer_method_load - Load a dynamic EAP method library (shared object)
1816d49e1aeSJan Lentfer * @so: File path for the shared object file to load
1826d49e1aeSJan Lentfer * Returns: 0 on success, -1 on failure
1836d49e1aeSJan Lentfer */
eap_peer_method_load(const char * so)1846d49e1aeSJan Lentfer int eap_peer_method_load(const char *so)
1856d49e1aeSJan Lentfer {
1866d49e1aeSJan Lentfer void *handle;
1876d49e1aeSJan Lentfer int (*dyn_init)(void);
1886d49e1aeSJan Lentfer int ret;
1896d49e1aeSJan Lentfer
1906d49e1aeSJan Lentfer handle = dlopen(so, RTLD_LAZY);
1916d49e1aeSJan Lentfer if (handle == NULL) {
1926d49e1aeSJan Lentfer wpa_printf(MSG_ERROR, "EAP: Failed to open dynamic EAP method "
1936d49e1aeSJan Lentfer "'%s': %s", so, dlerror());
1946d49e1aeSJan Lentfer return -1;
1956d49e1aeSJan Lentfer }
1966d49e1aeSJan Lentfer
1976d49e1aeSJan Lentfer dyn_init = dlsym(handle, "eap_peer_method_dynamic_init");
1986d49e1aeSJan Lentfer if (dyn_init == NULL) {
1996d49e1aeSJan Lentfer dlclose(handle);
2006d49e1aeSJan Lentfer wpa_printf(MSG_ERROR, "EAP: Invalid EAP method '%s' - no "
2016d49e1aeSJan Lentfer "eap_peer_method_dynamic_init()", so);
2026d49e1aeSJan Lentfer return -1;
2036d49e1aeSJan Lentfer }
2046d49e1aeSJan Lentfer
2056d49e1aeSJan Lentfer ret = dyn_init();
2066d49e1aeSJan Lentfer if (ret) {
2076d49e1aeSJan Lentfer dlclose(handle);
2086d49e1aeSJan Lentfer wpa_printf(MSG_ERROR, "EAP: Failed to add EAP method '%s' - "
2096d49e1aeSJan Lentfer "ret %d", so, ret);
2106d49e1aeSJan Lentfer return ret;
2116d49e1aeSJan Lentfer }
2126d49e1aeSJan Lentfer
2136d49e1aeSJan Lentfer /* Store the handle for this shared object. It will be freed with
2146d49e1aeSJan Lentfer * dlclose() when the EAP method is unregistered. */
2156d49e1aeSJan Lentfer eap_methods->dl_handle = handle;
2166d49e1aeSJan Lentfer
2176d49e1aeSJan Lentfer wpa_printf(MSG_DEBUG, "EAP: Loaded dynamic EAP method: '%s'", so);
2186d49e1aeSJan Lentfer
2196d49e1aeSJan Lentfer return 0;
2206d49e1aeSJan Lentfer }
2216d49e1aeSJan Lentfer
2226d49e1aeSJan Lentfer
2236d49e1aeSJan Lentfer /**
2246d49e1aeSJan Lentfer * eap_peer_method_unload - Unload a dynamic EAP method library (shared object)
2256d49e1aeSJan Lentfer * @method: Pointer to the dynamically loaded EAP method
2266d49e1aeSJan Lentfer * Returns: 0 on success, -1 on failure
2276d49e1aeSJan Lentfer *
2286d49e1aeSJan Lentfer * This function can be used to unload EAP methods that have been previously
2296d49e1aeSJan Lentfer * loaded with eap_peer_method_load(). Before unloading the method, all
2306d49e1aeSJan Lentfer * references to the method must be removed to make sure that no dereferences
2316d49e1aeSJan Lentfer * of freed memory will occur after unloading.
2326d49e1aeSJan Lentfer */
eap_peer_method_unload(struct eap_method * method)2336d49e1aeSJan Lentfer int eap_peer_method_unload(struct eap_method *method)
2346d49e1aeSJan Lentfer {
2356d49e1aeSJan Lentfer struct eap_method *m, *prev;
2366d49e1aeSJan Lentfer void *handle;
2376d49e1aeSJan Lentfer
2386d49e1aeSJan Lentfer m = eap_methods;
2396d49e1aeSJan Lentfer prev = NULL;
2406d49e1aeSJan Lentfer while (m) {
2416d49e1aeSJan Lentfer if (m == method)
2426d49e1aeSJan Lentfer break;
2436d49e1aeSJan Lentfer prev = m;
2446d49e1aeSJan Lentfer m = m->next;
2456d49e1aeSJan Lentfer }
2466d49e1aeSJan Lentfer
2476d49e1aeSJan Lentfer if (m == NULL || m->dl_handle == NULL)
2486d49e1aeSJan Lentfer return -1;
2496d49e1aeSJan Lentfer
2506d49e1aeSJan Lentfer if (prev)
2516d49e1aeSJan Lentfer prev->next = m->next;
2526d49e1aeSJan Lentfer else
2536d49e1aeSJan Lentfer eap_methods = m->next;
2546d49e1aeSJan Lentfer
2556d49e1aeSJan Lentfer handle = m->dl_handle;
2566d49e1aeSJan Lentfer
2576d49e1aeSJan Lentfer if (m->free)
2586d49e1aeSJan Lentfer m->free(m);
2596d49e1aeSJan Lentfer else
2606d49e1aeSJan Lentfer eap_peer_method_free(m);
2616d49e1aeSJan Lentfer
2626d49e1aeSJan Lentfer dlclose(handle);
2636d49e1aeSJan Lentfer
2646d49e1aeSJan Lentfer return 0;
2656d49e1aeSJan Lentfer }
2666d49e1aeSJan Lentfer #endif /* CONFIG_DYNAMIC_EAP_METHODS */
2676d49e1aeSJan Lentfer
2686d49e1aeSJan Lentfer
2696d49e1aeSJan Lentfer /**
2706d49e1aeSJan Lentfer * eap_peer_method_alloc - Allocate EAP peer method structure
2716d49e1aeSJan Lentfer * @version: Version of the EAP peer method interface (set to
2726d49e1aeSJan Lentfer * EAP_PEER_METHOD_INTERFACE_VERSION)
2736d49e1aeSJan Lentfer * @vendor: EAP Vendor-ID (EAP_VENDOR_*) (0 = IETF)
2746d49e1aeSJan Lentfer * @method: EAP type number (EAP_TYPE_*)
2756d49e1aeSJan Lentfer * @name: Name of the method (e.g., "TLS")
2766d49e1aeSJan Lentfer * Returns: Allocated EAP method structure or %NULL on failure
2776d49e1aeSJan Lentfer *
2786d49e1aeSJan Lentfer * The returned structure should be freed with eap_peer_method_free() when it
2796d49e1aeSJan Lentfer * is not needed anymore.
2806d49e1aeSJan Lentfer */
eap_peer_method_alloc(int version,int vendor,EapType method,const char * name)2816d49e1aeSJan Lentfer struct eap_method * eap_peer_method_alloc(int version, int vendor,
2826d49e1aeSJan Lentfer EapType method, const char *name)
2836d49e1aeSJan Lentfer {
2846d49e1aeSJan Lentfer struct eap_method *eap;
2856d49e1aeSJan Lentfer eap = os_zalloc(sizeof(*eap));
2866d49e1aeSJan Lentfer if (eap == NULL)
2876d49e1aeSJan Lentfer return NULL;
2886d49e1aeSJan Lentfer eap->version = version;
2896d49e1aeSJan Lentfer eap->vendor = vendor;
2906d49e1aeSJan Lentfer eap->method = method;
2916d49e1aeSJan Lentfer eap->name = name;
2926d49e1aeSJan Lentfer return eap;
2936d49e1aeSJan Lentfer }
2946d49e1aeSJan Lentfer
2956d49e1aeSJan Lentfer
2966d49e1aeSJan Lentfer /**
2976d49e1aeSJan Lentfer * eap_peer_method_free - Free EAP peer method structure
2986d49e1aeSJan Lentfer * @method: Method structure allocated with eap_peer_method_alloc()
2996d49e1aeSJan Lentfer */
eap_peer_method_free(struct eap_method * method)300*a1157835SDaniel Fojt static void eap_peer_method_free(struct eap_method *method)
3016d49e1aeSJan Lentfer {
3026d49e1aeSJan Lentfer os_free(method);
3036d49e1aeSJan Lentfer }
3046d49e1aeSJan Lentfer
3056d49e1aeSJan Lentfer
3066d49e1aeSJan Lentfer /**
3076d49e1aeSJan Lentfer * eap_peer_method_register - Register an EAP peer method
308*a1157835SDaniel Fojt * @method: EAP method to register from eap_peer_method_alloc()
3096d49e1aeSJan Lentfer * Returns: 0 on success, -1 on invalid method, or -2 if a matching EAP method
3106d49e1aeSJan Lentfer * has already been registered
3116d49e1aeSJan Lentfer *
3126d49e1aeSJan Lentfer * Each EAP peer method needs to call this function to register itself as a
313*a1157835SDaniel Fojt * supported EAP method. The caller must not free the allocated method data
314*a1157835SDaniel Fojt * regardless of the return value.
3156d49e1aeSJan Lentfer */
eap_peer_method_register(struct eap_method * method)3166d49e1aeSJan Lentfer int eap_peer_method_register(struct eap_method *method)
3176d49e1aeSJan Lentfer {
3186d49e1aeSJan Lentfer struct eap_method *m, *last = NULL;
3196d49e1aeSJan Lentfer
3206d49e1aeSJan Lentfer if (method == NULL || method->name == NULL ||
321*a1157835SDaniel Fojt method->version != EAP_PEER_METHOD_INTERFACE_VERSION) {
322*a1157835SDaniel Fojt eap_peer_method_free(method);
3236d49e1aeSJan Lentfer return -1;
324*a1157835SDaniel Fojt }
3256d49e1aeSJan Lentfer
3266d49e1aeSJan Lentfer for (m = eap_methods; m; m = m->next) {
3276d49e1aeSJan Lentfer if ((m->vendor == method->vendor &&
3286d49e1aeSJan Lentfer m->method == method->method) ||
329*a1157835SDaniel Fojt os_strcmp(m->name, method->name) == 0) {
330*a1157835SDaniel Fojt eap_peer_method_free(method);
3316d49e1aeSJan Lentfer return -2;
332*a1157835SDaniel Fojt }
3336d49e1aeSJan Lentfer last = m;
3346d49e1aeSJan Lentfer }
3356d49e1aeSJan Lentfer
3366d49e1aeSJan Lentfer if (last)
3376d49e1aeSJan Lentfer last->next = method;
3386d49e1aeSJan Lentfer else
3396d49e1aeSJan Lentfer eap_methods = method;
3406d49e1aeSJan Lentfer
3416d49e1aeSJan Lentfer return 0;
3426d49e1aeSJan Lentfer }
3436d49e1aeSJan Lentfer
3446d49e1aeSJan Lentfer
3456d49e1aeSJan Lentfer /**
3466d49e1aeSJan Lentfer * eap_peer_unregister_methods - Unregister EAP peer methods
3476d49e1aeSJan Lentfer *
3486d49e1aeSJan Lentfer * This function is called at program termination to unregister all EAP peer
3496d49e1aeSJan Lentfer * methods.
3506d49e1aeSJan Lentfer */
eap_peer_unregister_methods(void)3516d49e1aeSJan Lentfer void eap_peer_unregister_methods(void)
3526d49e1aeSJan Lentfer {
3536d49e1aeSJan Lentfer struct eap_method *m;
3546d49e1aeSJan Lentfer #ifdef CONFIG_DYNAMIC_EAP_METHODS
3556d49e1aeSJan Lentfer void *handle;
3566d49e1aeSJan Lentfer #endif /* CONFIG_DYNAMIC_EAP_METHODS */
3576d49e1aeSJan Lentfer
3586d49e1aeSJan Lentfer while (eap_methods) {
3596d49e1aeSJan Lentfer m = eap_methods;
3606d49e1aeSJan Lentfer eap_methods = eap_methods->next;
3616d49e1aeSJan Lentfer
3626d49e1aeSJan Lentfer #ifdef CONFIG_DYNAMIC_EAP_METHODS
3636d49e1aeSJan Lentfer handle = m->dl_handle;
3646d49e1aeSJan Lentfer #endif /* CONFIG_DYNAMIC_EAP_METHODS */
3656d49e1aeSJan Lentfer
3666d49e1aeSJan Lentfer if (m->free)
3676d49e1aeSJan Lentfer m->free(m);
3686d49e1aeSJan Lentfer else
3696d49e1aeSJan Lentfer eap_peer_method_free(m);
3706d49e1aeSJan Lentfer
3716d49e1aeSJan Lentfer #ifdef CONFIG_DYNAMIC_EAP_METHODS
3726d49e1aeSJan Lentfer if (handle)
3736d49e1aeSJan Lentfer dlclose(handle);
3746d49e1aeSJan Lentfer #endif /* CONFIG_DYNAMIC_EAP_METHODS */
3756d49e1aeSJan Lentfer }
3766d49e1aeSJan Lentfer }
377