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