18d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt/*
28d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * EAP peer: Method registration
38d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * Copyright (c) 2004-2007, Jouni Malinen <j@w1.fi>
48d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt *
5c5ec7f57ead87efa365800228aa0b09a12d9e6c4Dmitry Shmidt * This software may be distributed under the terms of the BSD license.
6c5ec7f57ead87efa365800228aa0b09a12d9e6c4Dmitry Shmidt * See README for more details.
78d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt */
88d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
98d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#include "includes.h"
108d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#ifdef CONFIG_DYNAMIC_EAP_METHODS
118d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#include <dlfcn.h>
128d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#endif /* CONFIG_DYNAMIC_EAP_METHODS */
138d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
148d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#include "common.h"
158d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#include "eap_i.h"
168d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#include "eap_methods.h"
178d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
188d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
198d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstatic struct eap_method *eap_methods = NULL;
208d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
218d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
228d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt/**
238d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * eap_peer_get_eap_method - Get EAP method based on type number
248d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * @vendor: EAP Vendor-Id (0 = IETF)
258d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * @method: EAP type number
268d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * Returns: Pointer to EAP method or %NULL if not found
278d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt */
288d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtconst struct eap_method * eap_peer_get_eap_method(int vendor, EapType method)
298d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
308d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	struct eap_method *m;
318d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	for (m = eap_methods; m; m = m->next) {
328d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		if (m->vendor == vendor && m->method == method)
338d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			return m;
348d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
358d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	return NULL;
368d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
378d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
388d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
398d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt/**
408d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * eap_peer_get_type - Get EAP type for the given EAP method name
418d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * @name: EAP method name, e.g., TLS
428d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * @vendor: Buffer for returning EAP Vendor-Id
438d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * Returns: EAP method type or %EAP_TYPE_NONE if not found
448d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt *
458d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * This function maps EAP type names into EAP type numbers based on the list of
468d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * EAP methods included in the build.
478d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt */
488d520ff1dc2da35cdca849e982051b86468016d8Dmitry ShmidtEapType eap_peer_get_type(const char *name, int *vendor)
498d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
508d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	struct eap_method *m;
518d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	for (m = eap_methods; m; m = m->next) {
528d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		if (os_strcmp(m->name, name) == 0) {
538d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			*vendor = m->vendor;
548d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			return m->method;
558d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		}
568d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
578d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	*vendor = EAP_VENDOR_IETF;
588d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	return EAP_TYPE_NONE;
598d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
608d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
618d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
628d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt/**
638d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * eap_get_name - Get EAP method name for the given EAP type
648d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * @vendor: EAP Vendor-Id (0 = IETF)
658d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * @type: EAP method type
668d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * Returns: EAP method name, e.g., TLS, or %NULL if not found
678d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt *
688d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * This function maps EAP type numbers into EAP type names based on the list of
698d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * EAP methods included in the build.
708d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt */
718d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtconst char * eap_get_name(int vendor, EapType type)
728d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
738d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	struct eap_method *m;
741f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	if (vendor == EAP_VENDOR_IETF && type == EAP_TYPE_EXPANDED)
751f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt		return "expanded";
768d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	for (m = eap_methods; m; m = m->next) {
778d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		if (m->vendor == vendor && m->method == type)
788d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			return m->name;
798d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
808d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	return NULL;
818d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
828d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
838d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
848d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt/**
858d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * eap_get_names - Get space separated list of names for supported EAP methods
868d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * @buf: Buffer for names
878d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * @buflen: Buffer length
888d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * Returns: Number of characters written into buf (not including nul
898d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * termination)
908d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt */
918d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtsize_t eap_get_names(char *buf, size_t buflen)
928d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
938d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	char *pos, *end;
948d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	struct eap_method *m;
958d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	int ret;
968d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
978d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (buflen == 0)
988d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return 0;
998d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
1008d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	pos = buf;
1018d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	end = pos + buflen;
1028d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
1038d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	for (m = eap_methods; m; m = m->next) {
1048d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		ret = os_snprintf(pos, end - pos, "%s%s",
1058d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt				  m == eap_methods ? "" : " ", m->name);
1068d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		if (ret < 0 || ret >= end - pos)
1078d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			break;
1088d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		pos += ret;
1098d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
1108d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	buf[buflen - 1] = '\0';
1118d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
1128d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	return pos - buf;
1138d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
1148d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
1158d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
1168d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt/**
1178d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * eap_get_names_as_string_array - Get supported EAP methods as string array
1188d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * @num: Buffer for returning the number of items in array, not including %NULL
1198d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * terminator. This parameter can be %NULL if the length is not needed.
1208d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * Returns: A %NULL-terminated array of strings, or %NULL on error.
1218d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt *
1228d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * This function returns the list of names for all supported EAP methods as an
1238d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * array of strings. The caller must free the returned array items and the
1248d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * array.
1258d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt */
1268d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtchar ** eap_get_names_as_string_array(size_t *num)
1278d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
1288d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	struct eap_method *m;
1298d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	size_t array_len = 0;
1308d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	char **array;
1318d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	int i = 0, j;
1328d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
1338d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	for (m = eap_methods; m; m = m->next)
1348d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		array_len++;
1358d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
1368d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	array = os_zalloc(sizeof(char *) * (array_len + 1));
1378d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (array == NULL)
1388d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return NULL;
1398d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
1408d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	for (m = eap_methods; m; m = m->next) {
1418d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		array[i++] = os_strdup(m->name);
1428d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		if (array[i - 1] == NULL) {
1438d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			for (j = 0; j < i; j++)
1448d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt				os_free(array[j]);
1458d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			os_free(array);
1468d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			return NULL;
1478d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		}
1488d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
1498d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	array[i] = NULL;
1508d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
1518d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (num)
1528d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		*num = array_len;
1538d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
1548d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	return array;
1558d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
1568d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
1578d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
1588d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt/**
1598d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * eap_peer_get_methods - Get a list of enabled EAP peer methods
1608d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * @count: Set to number of available methods
1618d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * Returns: List of enabled EAP peer methods
1628d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt */
1638d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtconst struct eap_method * eap_peer_get_methods(size_t *count)
1648d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
1658d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	int c = 0;
1668d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	struct eap_method *m;
1678d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
1688d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	for (m = eap_methods; m; m = m->next)
1698d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		c++;
1708d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
1718d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	*count = c;
1728d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	return eap_methods;
1738d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
1748d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
1758d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
1768d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#ifdef CONFIG_DYNAMIC_EAP_METHODS
1778d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt/**
1788d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * eap_peer_method_load - Load a dynamic EAP method library (shared object)
1798d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * @so: File path for the shared object file to load
1808d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * Returns: 0 on success, -1 on failure
1818d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt */
1828d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtint eap_peer_method_load(const char *so)
1838d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
1848d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	void *handle;
1858d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	int (*dyn_init)(void);
1868d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	int ret;
1878d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
1888d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	handle = dlopen(so, RTLD_LAZY);
1898d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (handle == NULL) {
1908d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		wpa_printf(MSG_ERROR, "EAP: Failed to open dynamic EAP method "
1918d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			   "'%s': %s", so, dlerror());
1928d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return -1;
1938d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
1948d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
1958d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	dyn_init = dlsym(handle, "eap_peer_method_dynamic_init");
1968d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (dyn_init == NULL) {
1978d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		dlclose(handle);
1988d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		wpa_printf(MSG_ERROR, "EAP: Invalid EAP method '%s' - no "
1998d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			   "eap_peer_method_dynamic_init()", so);
2008d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return -1;
2018d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
2028d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
2038d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	ret = dyn_init();
2048d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (ret) {
2058d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		dlclose(handle);
2068d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		wpa_printf(MSG_ERROR, "EAP: Failed to add EAP method '%s' - "
2078d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			   "ret %d", so, ret);
2088d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return ret;
2098d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
2108d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
2118d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	/* Store the handle for this shared object. It will be freed with
2128d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	 * dlclose() when the EAP method is unregistered. */
2138d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	eap_methods->dl_handle = handle;
2148d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
2158d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	wpa_printf(MSG_DEBUG, "EAP: Loaded dynamic EAP method: '%s'", so);
2168d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
2178d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	return 0;
2188d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
2198d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
2208d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
2218d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt/**
2228d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * eap_peer_method_unload - Unload a dynamic EAP method library (shared object)
2238d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * @method: Pointer to the dynamically loaded EAP method
2248d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * Returns: 0 on success, -1 on failure
2258d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt *
2268d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * This function can be used to unload EAP methods that have been previously
2278d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * loaded with eap_peer_method_load(). Before unloading the method, all
2288d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * references to the method must be removed to make sure that no dereferences
2298d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * of freed memory will occur after unloading.
2308d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt */
2318d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtint eap_peer_method_unload(struct eap_method *method)
2328d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
2338d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	struct eap_method *m, *prev;
2348d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	void *handle;
2358d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
2368d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	m = eap_methods;
2378d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	prev = NULL;
2388d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	while (m) {
2398d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		if (m == method)
2408d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			break;
2418d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		prev = m;
2428d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		m = m->next;
2438d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
2448d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
2458d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (m == NULL || m->dl_handle == NULL)
2468d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return -1;
2478d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
2488d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (prev)
2498d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		prev->next = m->next;
2508d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	else
2518d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		eap_methods = m->next;
2528d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
2538d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	handle = m->dl_handle;
2548d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
2558d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (m->free)
2568d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		m->free(m);
2578d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	else
2588d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		eap_peer_method_free(m);
2598d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
2608d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	dlclose(handle);
2618d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
2628d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	return 0;
2638d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
2648d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#endif /* CONFIG_DYNAMIC_EAP_METHODS */
2658d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
2668d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
2678d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt/**
2688d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * eap_peer_method_alloc - Allocate EAP peer method structure
2698d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * @version: Version of the EAP peer method interface (set to
2708d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * EAP_PEER_METHOD_INTERFACE_VERSION)
2718d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * @vendor: EAP Vendor-ID (EAP_VENDOR_*) (0 = IETF)
2728d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * @method: EAP type number (EAP_TYPE_*)
2738d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * @name: Name of the method (e.g., "TLS")
2748d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * Returns: Allocated EAP method structure or %NULL on failure
2758d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt *
2768d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * The returned structure should be freed with eap_peer_method_free() when it
2778d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * is not needed anymore.
2788d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt */
2798d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstruct eap_method * eap_peer_method_alloc(int version, int vendor,
2808d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt					  EapType method, const char *name)
2818d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
2828d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	struct eap_method *eap;
2838d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	eap = os_zalloc(sizeof(*eap));
2848d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (eap == NULL)
2858d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return NULL;
2868d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	eap->version = version;
2878d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	eap->vendor = vendor;
2888d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	eap->method = method;
2898d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	eap->name = name;
2908d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	return eap;
2918d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
2928d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
2938d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
2948d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt/**
2958d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * eap_peer_method_free - Free EAP peer method structure
2968d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * @method: Method structure allocated with eap_peer_method_alloc()
2978d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt */
2988d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtvoid eap_peer_method_free(struct eap_method *method)
2998d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
3008d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	os_free(method);
3018d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
3028d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
3038d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
3048d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt/**
3058d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * eap_peer_method_register - Register an EAP peer method
3068d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * @method: EAP method to register
3078d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * Returns: 0 on success, -1 on invalid method, or -2 if a matching EAP method
3088d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * has already been registered
3098d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt *
3108d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * Each EAP peer method needs to call this function to register itself as a
3118d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * supported EAP method.
3128d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt */
3138d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtint eap_peer_method_register(struct eap_method *method)
3148d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
3158d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	struct eap_method *m, *last = NULL;
3168d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
3178d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (method == NULL || method->name == NULL ||
3188d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	    method->version != EAP_PEER_METHOD_INTERFACE_VERSION)
3198d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return -1;
3208d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
3218d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	for (m = eap_methods; m; m = m->next) {
3228d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		if ((m->vendor == method->vendor &&
3238d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		     m->method == method->method) ||
3248d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		    os_strcmp(m->name, method->name) == 0)
3258d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			return -2;
3268d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		last = m;
3278d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
3288d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
3298d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (last)
3308d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		last->next = method;
3318d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	else
3328d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		eap_methods = method;
3338d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
3348d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	return 0;
3358d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
3368d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
3378d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
3388d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt/**
3398d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * eap_peer_unregister_methods - Unregister EAP peer methods
3408d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt *
3418d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * This function is called at program termination to unregister all EAP peer
3428d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * methods.
3438d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt */
3448d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtvoid eap_peer_unregister_methods(void)
3458d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
3468d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	struct eap_method *m;
3478d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#ifdef CONFIG_DYNAMIC_EAP_METHODS
3488d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	void *handle;
3498d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#endif /* CONFIG_DYNAMIC_EAP_METHODS */
3508d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
3518d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	while (eap_methods) {
3528d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		m = eap_methods;
3538d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		eap_methods = eap_methods->next;
3548d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
3558d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#ifdef CONFIG_DYNAMIC_EAP_METHODS
3568d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		handle = m->dl_handle;
3578d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#endif /* CONFIG_DYNAMIC_EAP_METHODS */
3588d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
3598d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		if (m->free)
3608d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			m->free(m);
3618d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		else
3628d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			eap_peer_method_free(m);
3638d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
3648d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#ifdef CONFIG_DYNAMIC_EAP_METHODS
3658d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		if (handle)
3668d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			dlclose(handle);
3678d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#endif /* CONFIG_DYNAMIC_EAP_METHODS */
3688d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
3698d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
370