eap_methods.c 8.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375
  1. /*
  2. * EAP peer: Method registration
  3. * Copyright (c) 2004-2007, Jouni Malinen <j@w1.fi>
  4. *
  5. * This program is free software; you can redistribute it and/or modify
  6. * it under the terms of the GNU General Public License version 2 as
  7. * published by the Free Software Foundation.
  8. *
  9. * Alternatively, this software may be distributed under the terms of BSD
  10. * license.
  11. *
  12. * See README and COPYING for more details.
  13. */
  14. #include "includes.h"
  15. #ifdef CONFIG_DYNAMIC_EAP_METHODS
  16. #include <dlfcn.h>
  17. #endif /* CONFIG_DYNAMIC_EAP_METHODS */
  18. #include "common.h"
  19. #include "eap_i.h"
  20. #include "eap_methods.h"
  21. static struct eap_method *eap_methods = NULL;
  22. /**
  23. * eap_peer_get_eap_method - Get EAP method based on type number
  24. * @vendor: EAP Vendor-Id (0 = IETF)
  25. * @method: EAP type number
  26. * Returns: Pointer to EAP method or %NULL if not found
  27. */
  28. const struct eap_method * eap_peer_get_eap_method(int vendor, EapType method)
  29. {
  30. struct eap_method *m;
  31. for (m = eap_methods; m; m = m->next) {
  32. if (m->vendor == vendor && m->method == method)
  33. return m;
  34. }
  35. return NULL;
  36. }
  37. /**
  38. * eap_peer_get_type - Get EAP type for the given EAP method name
  39. * @name: EAP method name, e.g., TLS
  40. * @vendor: Buffer for returning EAP Vendor-Id
  41. * Returns: EAP method type or %EAP_TYPE_NONE if not found
  42. *
  43. * This function maps EAP type names into EAP type numbers based on the list of
  44. * EAP methods included in the build.
  45. */
  46. EapType eap_peer_get_type(const char *name, int *vendor)
  47. {
  48. struct eap_method *m;
  49. for (m = eap_methods; m; m = m->next) {
  50. if (os_strcmp(m->name, name) == 0) {
  51. *vendor = m->vendor;
  52. return m->method;
  53. }
  54. }
  55. *vendor = EAP_VENDOR_IETF;
  56. return EAP_TYPE_NONE;
  57. }
  58. /**
  59. * eap_get_name - Get EAP method name for the given EAP type
  60. * @vendor: EAP Vendor-Id (0 = IETF)
  61. * @type: EAP method type
  62. * Returns: EAP method name, e.g., TLS, or %NULL if not found
  63. *
  64. * This function maps EAP type numbers into EAP type names based on the list of
  65. * EAP methods included in the build.
  66. */
  67. const char * eap_get_name(int vendor, EapType type)
  68. {
  69. struct eap_method *m;
  70. if (vendor == EAP_VENDOR_IETF && type == EAP_TYPE_EXPANDED)
  71. return "expanded";
  72. for (m = eap_methods; m; m = m->next) {
  73. if (m->vendor == vendor && m->method == type)
  74. return m->name;
  75. }
  76. return NULL;
  77. }
  78. /**
  79. * eap_get_names - Get space separated list of names for supported EAP methods
  80. * @buf: Buffer for names
  81. * @buflen: Buffer length
  82. * Returns: Number of characters written into buf (not including nul
  83. * termination)
  84. */
  85. size_t eap_get_names(char *buf, size_t buflen)
  86. {
  87. char *pos, *end;
  88. struct eap_method *m;
  89. int ret;
  90. if (buflen == 0)
  91. return 0;
  92. pos = buf;
  93. end = pos + buflen;
  94. for (m = eap_methods; m; m = m->next) {
  95. ret = os_snprintf(pos, end - pos, "%s%s",
  96. m == eap_methods ? "" : " ", m->name);
  97. if (ret < 0 || ret >= end - pos)
  98. break;
  99. pos += ret;
  100. }
  101. buf[buflen - 1] = '\0';
  102. return pos - buf;
  103. }
  104. /**
  105. * eap_get_names_as_string_array - Get supported EAP methods as string array
  106. * @num: Buffer for returning the number of items in array, not including %NULL
  107. * terminator. This parameter can be %NULL if the length is not needed.
  108. * Returns: A %NULL-terminated array of strings, or %NULL on error.
  109. *
  110. * This function returns the list of names for all supported EAP methods as an
  111. * array of strings. The caller must free the returned array items and the
  112. * array.
  113. */
  114. char ** eap_get_names_as_string_array(size_t *num)
  115. {
  116. struct eap_method *m;
  117. size_t array_len = 0;
  118. char **array;
  119. int i = 0, j;
  120. for (m = eap_methods; m; m = m->next)
  121. array_len++;
  122. array = os_zalloc(sizeof(char *) * (array_len + 1));
  123. if (array == NULL)
  124. return NULL;
  125. for (m = eap_methods; m; m = m->next) {
  126. array[i++] = os_strdup(m->name);
  127. if (array[i - 1] == NULL) {
  128. for (j = 0; j < i; j++)
  129. os_free(array[j]);
  130. os_free(array);
  131. return NULL;
  132. }
  133. }
  134. array[i] = NULL;
  135. if (num)
  136. *num = array_len;
  137. return array;
  138. }
  139. /**
  140. * eap_peer_get_methods - Get a list of enabled EAP peer methods
  141. * @count: Set to number of available methods
  142. * Returns: List of enabled EAP peer methods
  143. */
  144. const struct eap_method * eap_peer_get_methods(size_t *count)
  145. {
  146. int c = 0;
  147. struct eap_method *m;
  148. for (m = eap_methods; m; m = m->next)
  149. c++;
  150. *count = c;
  151. return eap_methods;
  152. }
  153. #ifdef CONFIG_DYNAMIC_EAP_METHODS
  154. /**
  155. * eap_peer_method_load - Load a dynamic EAP method library (shared object)
  156. * @so: File path for the shared object file to load
  157. * Returns: 0 on success, -1 on failure
  158. */
  159. int eap_peer_method_load(const char *so)
  160. {
  161. void *handle;
  162. int (*dyn_init)(void);
  163. int ret;
  164. handle = dlopen(so, RTLD_LAZY);
  165. if (handle == NULL) {
  166. wpa_printf(MSG_ERROR, "EAP: Failed to open dynamic EAP method "
  167. "'%s': %s", so, dlerror());
  168. return -1;
  169. }
  170. dyn_init = dlsym(handle, "eap_peer_method_dynamic_init");
  171. if (dyn_init == NULL) {
  172. dlclose(handle);
  173. wpa_printf(MSG_ERROR, "EAP: Invalid EAP method '%s' - no "
  174. "eap_peer_method_dynamic_init()", so);
  175. return -1;
  176. }
  177. ret = dyn_init();
  178. if (ret) {
  179. dlclose(handle);
  180. wpa_printf(MSG_ERROR, "EAP: Failed to add EAP method '%s' - "
  181. "ret %d", so, ret);
  182. return ret;
  183. }
  184. /* Store the handle for this shared object. It will be freed with
  185. * dlclose() when the EAP method is unregistered. */
  186. eap_methods->dl_handle = handle;
  187. wpa_printf(MSG_DEBUG, "EAP: Loaded dynamic EAP method: '%s'", so);
  188. return 0;
  189. }
  190. /**
  191. * eap_peer_method_unload - Unload a dynamic EAP method library (shared object)
  192. * @method: Pointer to the dynamically loaded EAP method
  193. * Returns: 0 on success, -1 on failure
  194. *
  195. * This function can be used to unload EAP methods that have been previously
  196. * loaded with eap_peer_method_load(). Before unloading the method, all
  197. * references to the method must be removed to make sure that no dereferences
  198. * of freed memory will occur after unloading.
  199. */
  200. int eap_peer_method_unload(struct eap_method *method)
  201. {
  202. struct eap_method *m, *prev;
  203. void *handle;
  204. m = eap_methods;
  205. prev = NULL;
  206. while (m) {
  207. if (m == method)
  208. break;
  209. prev = m;
  210. m = m->next;
  211. }
  212. if (m == NULL || m->dl_handle == NULL)
  213. return -1;
  214. if (prev)
  215. prev->next = m->next;
  216. else
  217. eap_methods = m->next;
  218. handle = m->dl_handle;
  219. if (m->free)
  220. m->free(m);
  221. else
  222. eap_peer_method_free(m);
  223. dlclose(handle);
  224. return 0;
  225. }
  226. #endif /* CONFIG_DYNAMIC_EAP_METHODS */
  227. /**
  228. * eap_peer_method_alloc - Allocate EAP peer method structure
  229. * @version: Version of the EAP peer method interface (set to
  230. * EAP_PEER_METHOD_INTERFACE_VERSION)
  231. * @vendor: EAP Vendor-ID (EAP_VENDOR_*) (0 = IETF)
  232. * @method: EAP type number (EAP_TYPE_*)
  233. * @name: Name of the method (e.g., "TLS")
  234. * Returns: Allocated EAP method structure or %NULL on failure
  235. *
  236. * The returned structure should be freed with eap_peer_method_free() when it
  237. * is not needed anymore.
  238. */
  239. struct eap_method * eap_peer_method_alloc(int version, int vendor,
  240. EapType method, const char *name)
  241. {
  242. struct eap_method *eap;
  243. eap = os_zalloc(sizeof(*eap));
  244. if (eap == NULL)
  245. return NULL;
  246. eap->version = version;
  247. eap->vendor = vendor;
  248. eap->method = method;
  249. eap->name = name;
  250. return eap;
  251. }
  252. /**
  253. * eap_peer_method_free - Free EAP peer method structure
  254. * @method: Method structure allocated with eap_peer_method_alloc()
  255. */
  256. void eap_peer_method_free(struct eap_method *method)
  257. {
  258. os_free(method);
  259. }
  260. /**
  261. * eap_peer_method_register - Register an EAP peer method
  262. * @method: EAP method to register
  263. * Returns: 0 on success, -1 on invalid method, or -2 if a matching EAP method
  264. * has already been registered
  265. *
  266. * Each EAP peer method needs to call this function to register itself as a
  267. * supported EAP method.
  268. */
  269. int eap_peer_method_register(struct eap_method *method)
  270. {
  271. struct eap_method *m, *last = NULL;
  272. if (method == NULL || method->name == NULL ||
  273. method->version != EAP_PEER_METHOD_INTERFACE_VERSION)
  274. return -1;
  275. for (m = eap_methods; m; m = m->next) {
  276. if ((m->vendor == method->vendor &&
  277. m->method == method->method) ||
  278. os_strcmp(m->name, method->name) == 0)
  279. return -2;
  280. last = m;
  281. }
  282. if (last)
  283. last->next = method;
  284. else
  285. eap_methods = method;
  286. return 0;
  287. }
  288. /**
  289. * eap_peer_unregister_methods - Unregister EAP peer methods
  290. *
  291. * This function is called at program termination to unregister all EAP peer
  292. * methods.
  293. */
  294. void eap_peer_unregister_methods(void)
  295. {
  296. struct eap_method *m;
  297. #ifdef CONFIG_DYNAMIC_EAP_METHODS
  298. void *handle;
  299. #endif /* CONFIG_DYNAMIC_EAP_METHODS */
  300. while (eap_methods) {
  301. m = eap_methods;
  302. eap_methods = eap_methods->next;
  303. #ifdef CONFIG_DYNAMIC_EAP_METHODS
  304. handle = m->dl_handle;
  305. #endif /* CONFIG_DYNAMIC_EAP_METHODS */
  306. if (m->free)
  307. m->free(m);
  308. else
  309. eap_peer_method_free(m);
  310. #ifdef CONFIG_DYNAMIC_EAP_METHODS
  311. if (handle)
  312. dlclose(handle);
  313. #endif /* CONFIG_DYNAMIC_EAP_METHODS */
  314. }
  315. }