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