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