1/* 2 * EAP peer: Method registration 3 * Copyright (c) 2004-2006, 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 15#include "includes.h" 16#ifdef CONFIG_DYNAMIC_EAP_METHODS 17#include <dlfcn.h> 18#endif /* CONFIG_DYNAMIC_EAP_METHODS */ 19 20#include "common.h" 21#include "eap_i.h" 22#include "eap_methods.h" 23 24 25static struct eap_method *eap_methods = NULL; 26 27 28/** 29 * eap_sm_get_eap_methods - Get EAP method based on type number 30 * @vendor: EAP Vendor-Id (0 = IETF) 31 * @method: EAP type number 32 * Returns: Pointer to EAP method or %NULL if not found 33 */ 34const struct eap_method * eap_sm_get_eap_methods(int vendor, EapType method) 35{ 36 struct eap_method *m; 37 for (m = eap_methods; m; m = m->next) { 38 if (m->vendor == vendor && m->method == method) 39 return m; 40 } 41 return NULL; 42} 43 44 45/** 46 * eap_get_type - Get EAP type for the given EAP method name 47 * @name: EAP method name, e.g., TLS 48 * @vendor: Buffer for returning EAP Vendor-Id 49 * Returns: EAP method type or %EAP_TYPE_NONE if not found 50 * 51 * This function maps EAP type names into EAP type numbers based on the list of 52 * EAP methods included in the build. 53 */ 54EapType eap_get_type(const char *name, int *vendor) 55{ 56 struct eap_method *m; 57 for (m = eap_methods; m; m = m->next) { 58 if (os_strcmp(m->name, name) == 0) { 59 *vendor = m->vendor; 60 return m->method; 61 } 62 } 63 *vendor = EAP_VENDOR_IETF; 64 return EAP_TYPE_NONE; 65} 66 67 68/** 69 * eap_get_name - Get EAP method name for the given EAP type 70 * @vendor: EAP Vendor-Id (0 = IETF) 71 * @type: EAP method type 72 * Returns: EAP method name, e.g., TLS, or %NULL if not found 73 * 74 * This function maps EAP type numbers into EAP type names based on the list of 75 * EAP methods included in the build. 76 */ 77const char * eap_get_name(int vendor, EapType type) 78{ 79 struct eap_method *m; 80 for (m = eap_methods; m; m = m->next) { 81 if (m->vendor == vendor && m->method == type) 82 return m->name; 83 } 84 return NULL; 85} 86 87 88/** 89 * eap_get_names - Get space separated list of names for supported EAP methods 90 * @buf: Buffer for names 91 * @buflen: Buffer length 92 * Returns: Number of characters written into buf (not including nul 93 * termination) 94 */ 95size_t eap_get_names(char *buf, size_t buflen) 96{ 97 char *pos, *end; 98 struct eap_method *m; 99 int ret; 100 101 if (buflen == 0) 102 return 0; 103 104 pos = buf; 105 end = pos + buflen; 106 107 for (m = eap_methods; m; m = m->next) { 108 ret = os_snprintf(pos, end - pos, "%s%s", 109 m == eap_methods ? "" : " ", m->name); 110 if (ret < 0 || ret >= end - pos) 111 break; 112 pos += ret; 113 } 114 buf[buflen - 1] = '\0'; 115 116 return pos - buf; 117} 118 119 120/** 121 * eap_get_names_as_string_array - Get supported EAP methods as string array 122 * @num: Buffer for returning the number of items in array, not including %NULL 123 * terminator. This parameter can be %NULL if the length is not needed. 124 * Returns: A %NULL-terminated array of strings, or %NULL on error. 125 * 126 * This function returns the list of names for all supported EAP methods as an 127 * array of strings. The caller must free the returned array items and the 128 * array. 129 */ 130char ** eap_get_names_as_string_array(size_t *num) 131{ 132 struct eap_method *m; 133 size_t array_len = 0; 134 char **array; 135 int i = 0, j; 136 137 for (m = eap_methods; m; m = m->next) 138 array_len++; 139 140 array = os_zalloc(sizeof(char *) * (array_len + 1)); 141 if (array == NULL) 142 return NULL; 143 144 for (m = eap_methods; m; m = m->next) { 145 array[i++] = os_strdup(m->name); 146 if (array[i - 1] == NULL) { 147 for (j = 0; j < i; j++) 148 os_free(array[j]); 149 os_free(array); 150 return NULL; 151 } 152 } 153 array[i] = NULL; 154 155 if (num) 156 *num = array_len; 157 158 return array; 159} 160 161 162/** 163 * eap_peer_get_methods - Get a list of enabled EAP peer methods 164 * @count: Set to number of available methods 165 * Returns: List of enabled EAP peer methods 166 */ 167const struct eap_method * eap_peer_get_methods(size_t *count) 168{ 169 int c = 0; 170 struct eap_method *m; 171 172 for (m = eap_methods; m; m = m->next) 173 c++; 174 175 *count = c; 176 return eap_methods; 177} 178 179 180#ifdef CONFIG_DYNAMIC_EAP_METHODS 181/** 182 * eap_peer_method_load - Load a dynamic EAP method library (shared object) 183 * @so: File path for the shared object file to load 184 * Returns: 0 on success, -1 on failure 185 */ 186int eap_peer_method_load(const char *so) 187{ 188 void *handle; 189 int (*dyn_init)(void); 190 int ret; 191 192 handle = dlopen(so, RTLD_LAZY); 193 if (handle == NULL) { 194 wpa_printf(MSG_ERROR, "EAP: Failed to open dynamic EAP method " 195 "'%s': %s", so, dlerror()); 196 return -1; 197 } 198 199 dyn_init = dlsym(handle, "eap_peer_method_dynamic_init"); 200 if (dyn_init == NULL) { 201 dlclose(handle); 202 wpa_printf(MSG_ERROR, "EAP: Invalid EAP method '%s' - no " 203 "eap_peer_method_dynamic_init()", so); 204 return -1; 205 } 206 207 ret = dyn_init(); 208 if (ret) { 209 dlclose(handle); 210 wpa_printf(MSG_ERROR, "EAP: Failed to add EAP method '%s' - " 211 "ret %d", so, ret); 212 return ret; 213 } 214 215 /* Store the handle for this shared object. It will be freed with 216 * dlclose() when the EAP method is unregistered. */ 217 eap_methods->dl_handle = handle; 218 219 wpa_printf(MSG_DEBUG, "EAP: Loaded dynamic EAP method: '%s'", so); 220 221 return 0; 222} 223 224 225/** 226 * eap_peer_method_unload - Unload a dynamic EAP method library (shared object) 227 * @method: Pointer to the dynamically loaded EAP method 228 * Returns: 0 on success, -1 on failure 229 * 230 * This function can be used to unload EAP methods that have been previously 231 * loaded with eap_peer_method_load(). Before unloading the method, all 232 * references to the method must be removed to make sure that no dereferences 233 * of freed memory will occur after unloading. 234 */ 235int eap_peer_method_unload(struct eap_method *method) 236{ 237 struct eap_method *m, *prev; 238 void *handle; 239 240 m = eap_methods; 241 prev = NULL; 242 while (m) { 243 if (m == method) 244 break; 245 prev = m; 246 m = m->next; 247 } 248 249 if (m == NULL || m->dl_handle == NULL) 250 return -1; 251 252 if (prev) 253 prev->next = m->next; 254 else 255 eap_methods = m->next; 256 257 handle = m->dl_handle; 258 259 if (m->free) 260 m->free(m); 261 else 262 eap_peer_method_free(m); 263 264 dlclose(handle); 265 266 return 0; 267} 268#endif /* CONFIG_DYNAMIC_EAP_METHODS */ 269 270 271/** 272 * eap_peer_method_alloc - Allocate EAP peer method structure 273 * @version: Version of the EAP peer method interface (set to 274 * EAP_PEER_METHOD_INTERFACE_VERSION) 275 * @vendor: EAP Vendor-ID (EAP_VENDOR_*) (0 = IETF) 276 * @method: EAP type number (EAP_TYPE_*) 277 * @name: Name of the method (e.g., "TLS") 278 * Returns: Allocated EAP method structure or %NULL on failure 279 * 280 * The returned structure should be freed with eap_peer_method_free() when it 281 * is not needed anymore. 282 */ 283struct eap_method * eap_peer_method_alloc(int version, int vendor, 284 EapType method, const char *name) 285{ 286 struct eap_method *eap; 287 eap = os_zalloc(sizeof(*eap)); 288 if (eap == NULL) 289 return NULL; 290 eap->version = version; 291 eap->vendor = vendor; 292 eap->method = method; 293 eap->name = name; 294 return eap; 295} 296 297 298/** 299 * eap_peer_method_free - Free EAP peer method structure 300 * @method: Method structure allocated with eap_peer_method_alloc() 301 */ 302void eap_peer_method_free(struct eap_method *method) 303{ 304 os_free(method); 305} 306 307 308/** 309 * eap_peer_method_register - Register an EAP peer method 310 * @method: EAP method to register 311 * Returns: 0 on success, -1 on invalid method, or -2 if a matching EAP method 312 * has already been registered 313 * 314 * Each EAP peer method needs to call this function to register itself as a 315 * supported EAP method. 316 */ 317int eap_peer_method_register(struct eap_method *method) 318{ 319 struct eap_method *m, *last = NULL; 320 321 if (method == NULL || method->name == NULL || 322 method->version != EAP_PEER_METHOD_INTERFACE_VERSION) 323 return -1; 324 325 for (m = eap_methods; m; m = m->next) { 326 if ((m->vendor == method->vendor && 327 m->method == method->method) || 328 os_strcmp(m->name, method->name) == 0) 329 return -2; 330 last = m; 331 } 332 333 if (last) 334 last->next = method; 335 else 336 eap_methods = method; 337 338 return 0; 339} 340 341 342/** 343 * eap_peer_register_methods - Register statically linked EAP peer methods 344 * Returns: 0 on success, -1 on failure 345 * 346 * This function is called at program initialization to register all EAP peer 347 * methods that were linked in statically. 348 */ 349int eap_peer_register_methods(void) 350{ 351 int ret = 0; 352 353#ifdef EAP_MD5 354 if (ret == 0) { 355 int eap_peer_md5_register(void); 356 ret = eap_peer_md5_register(); 357 } 358#endif /* EAP_MD5 */ 359 360#ifdef EAP_TLS 361 if (ret == 0) { 362 int eap_peer_tls_register(void); 363 ret = eap_peer_tls_register(); 364 } 365#endif /* EAP_TLS */ 366 367#ifdef EAP_MSCHAPv2 368 if (ret == 0) { 369 int eap_peer_mschapv2_register(void); 370 ret = eap_peer_mschapv2_register(); 371 } 372#endif /* EAP_MSCHAPv2 */ 373 374#ifdef EAP_PEAP 375 if (ret == 0) { 376 int eap_peer_peap_register(void); 377 ret = eap_peer_peap_register(); 378 } 379#endif /* EAP_PEAP */ 380 381#ifdef EAP_TTLS 382 if (ret == 0) { 383 int eap_peer_ttls_register(void); 384 ret = eap_peer_ttls_register(); 385 } 386#endif /* EAP_TTLS */ 387 388#ifdef EAP_GTC 389 if (ret == 0) { 390 int eap_peer_gtc_register(void); 391 ret = eap_peer_gtc_register(); 392 } 393#endif /* EAP_GTC */ 394 395#ifdef EAP_OTP 396 if (ret == 0) { 397 int eap_peer_otp_register(void); 398 ret = eap_peer_otp_register(); 399 } 400#endif /* EAP_OTP */ 401 402#ifdef EAP_SIM 403 if (ret == 0) { 404 int eap_peer_sim_register(void); 405 ret = eap_peer_sim_register(); 406 } 407#endif /* EAP_SIM */ 408 409#ifdef EAP_LEAP 410 if (ret == 0) { 411 int eap_peer_leap_register(void); 412 ret = eap_peer_leap_register(); 413 } 414#endif /* EAP_LEAP */ 415 416#ifdef EAP_PSK 417 if (ret == 0) { 418 int eap_peer_psk_register(void); 419 ret = eap_peer_psk_register(); 420 } 421#endif /* EAP_PSK */ 422 423#ifdef EAP_AKA 424 if (ret == 0) { 425 int eap_peer_aka_register(void); 426 ret = eap_peer_aka_register(); 427 } 428#endif /* EAP_AKA */ 429 430#ifdef EAP_FAST 431 if (ret == 0) { 432 int eap_peer_fast_register(void); 433 ret = eap_peer_fast_register(); 434 } 435#endif /* EAP_FAST */ 436 437#ifdef EAP_PAX 438 if (ret == 0) { 439 int eap_peer_pax_register(void); 440 ret = eap_peer_pax_register(); 441 } 442#endif /* EAP_PAX */ 443 444#ifdef EAP_SAKE 445 if (ret == 0) { 446 int eap_peer_sake_register(void); 447 ret = eap_peer_sake_register(); 448 } 449#endif /* EAP_SAKE */ 450 451#ifdef EAP_GPSK 452 if (ret == 0) { 453 int eap_peer_gpsk_register(void); 454 ret = eap_peer_gpsk_register(); 455 } 456#endif /* EAP_GPSK */ 457 458#ifdef EAP_VENDOR_TEST 459 if (ret == 0) { 460 int eap_peer_vendor_test_register(void); 461 ret = eap_peer_vendor_test_register(); 462 } 463#endif /* EAP_VENDOR_TEST */ 464 465 return ret; 466} 467 468 469/** 470 * eap_peer_unregister_methods - Unregister EAP peer methods 471 * 472 * This function is called at program termination to unregister all EAP peer 473 * methods. 474 */ 475void eap_peer_unregister_methods(void) 476{ 477 struct eap_method *m; 478#ifdef CONFIG_DYNAMIC_EAP_METHODS 479 void *handle; 480#endif /* CONFIG_DYNAMIC_EAP_METHODS */ 481 482 while (eap_methods) { 483 m = eap_methods; 484 eap_methods = eap_methods->next; 485 486#ifdef CONFIG_DYNAMIC_EAP_METHODS 487 handle = m->dl_handle; 488#endif /* CONFIG_DYNAMIC_EAP_METHODS */ 489 490 if (m->free) 491 m->free(m); 492 else 493 eap_peer_method_free(m); 494 495#ifdef CONFIG_DYNAMIC_EAP_METHODS 496 if (handle) 497 dlclose(handle); 498#endif /* CONFIG_DYNAMIC_EAP_METHODS */ 499 } 500} 501