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