Branch data Line data Source code
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 : :
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 : : */
28 : 773 : const struct eap_method * eap_peer_get_eap_method(int vendor, EapType method)
29 : : {
30 : : struct eap_method *m;
31 [ + - ]: 10240 : for (m = eap_methods; m; m = m->next) {
32 [ + + ][ + + ]: 10240 : if (m->vendor == vendor && m->method == method)
33 : 773 : return m;
34 : : }
35 : 773 : 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 : : */
48 : 352 : EapType eap_peer_get_type(const char *name, int *vendor)
49 : : {
50 : : struct eap_method *m;
51 [ + + ]: 4642 : for (m = eap_methods; m; m = m->next) {
52 [ + + ]: 4640 : if (os_strcmp(m->name, name) == 0) {
53 : 350 : *vendor = m->vendor;
54 : 350 : return m->method;
55 : : }
56 : : }
57 : 2 : *vendor = EAP_VENDOR_IETF;
58 : 352 : 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 : : */
71 : 679 : const char * eap_get_name(int vendor, EapType type)
72 : : {
73 : : struct eap_method *m;
74 [ + - ][ - + ]: 679 : if (vendor == EAP_VENDOR_IETF && type == EAP_TYPE_EXPANDED)
75 : 0 : return "expanded";
76 [ + + ]: 3566 : for (m = eap_methods; m; m = m->next) {
77 [ + + ][ + + ]: 3558 : if (m->vendor == vendor && m->method == type)
78 : 671 : return m->name;
79 : : }
80 : 679 : 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 : : */
91 : 0 : size_t eap_get_names(char *buf, size_t buflen)
92 : : {
93 : : char *pos, *end;
94 : : struct eap_method *m;
95 : : int ret;
96 : :
97 [ # # ]: 0 : if (buflen == 0)
98 : 0 : return 0;
99 : :
100 : 0 : pos = buf;
101 : 0 : end = pos + buflen;
102 : :
103 [ # # ]: 0 : for (m = eap_methods; m; m = m->next) {
104 [ # # ]: 0 : ret = os_snprintf(pos, end - pos, "%s%s",
105 : 0 : m == eap_methods ? "" : " ", m->name);
106 [ # # ][ # # ]: 0 : if (ret < 0 || ret >= end - pos)
107 : : break;
108 : 0 : pos += ret;
109 : : }
110 : 0 : buf[buflen - 1] = '\0';
111 : :
112 : 0 : 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 : : */
126 : 0 : char ** eap_get_names_as_string_array(size_t *num)
127 : : {
128 : : struct eap_method *m;
129 : 0 : size_t array_len = 0;
130 : : char **array;
131 : 0 : int i = 0, j;
132 : :
133 [ # # ]: 0 : for (m = eap_methods; m; m = m->next)
134 : 0 : array_len++;
135 : :
136 : 0 : array = os_zalloc(sizeof(char *) * (array_len + 1));
137 [ # # ]: 0 : if (array == NULL)
138 : 0 : return NULL;
139 : :
140 [ # # ]: 0 : for (m = eap_methods; m; m = m->next) {
141 : 0 : array[i++] = os_strdup(m->name);
142 [ # # ]: 0 : if (array[i - 1] == NULL) {
143 [ # # ]: 0 : for (j = 0; j < i; j++)
144 : 0 : os_free(array[j]);
145 : 0 : os_free(array);
146 : 0 : return NULL;
147 : : }
148 : : }
149 : 0 : array[i] = NULL;
150 : :
151 [ # # ]: 0 : if (num)
152 : 0 : *num = array_len;
153 : :
154 : 0 : 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 : : */
163 : 43 : const struct eap_method * eap_peer_get_methods(size_t *count)
164 : : {
165 : 43 : int c = 0;
166 : : struct eap_method *m;
167 : :
168 [ + + ]: 1075 : for (m = eap_methods; m; m = m->next)
169 : 1032 : c++;
170 : :
171 : 43 : *count = c;
172 : 43 : 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 : : */
182 : : int 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 : : */
231 : : int 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 : : */
279 : 96 : struct eap_method * eap_peer_method_alloc(int version, int vendor,
280 : : EapType method, const char *name)
281 : : {
282 : : struct eap_method *eap;
283 : 96 : eap = os_zalloc(sizeof(*eap));
284 [ - + ]: 96 : if (eap == NULL)
285 : 0 : return NULL;
286 : 96 : eap->version = version;
287 : 96 : eap->vendor = vendor;
288 : 96 : eap->method = method;
289 : 96 : eap->name = name;
290 : 96 : 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 : : */
298 : 96 : void eap_peer_method_free(struct eap_method *method)
299 : : {
300 : 96 : os_free(method);
301 : 96 : }
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 : : */
313 : 96 : int eap_peer_method_register(struct eap_method *method)
314 : : {
315 : 96 : struct eap_method *m, *last = NULL;
316 : :
317 [ + - ][ + - ]: 96 : if (method == NULL || method->name == NULL ||
[ - + ]
318 : 96 : method->version != EAP_PEER_METHOD_INTERFACE_VERSION)
319 : 0 : return -1;
320 : :
321 [ + + ]: 1200 : for (m = eap_methods; m; m = m->next) {
322 [ + + ][ + - ]: 1104 : if ((m->vendor == method->vendor &&
323 [ - + ]: 1104 : m->method == method->method) ||
324 : 1104 : os_strcmp(m->name, method->name) == 0)
325 : 0 : return -2;
326 : 1104 : last = m;
327 : : }
328 : :
329 [ + + ]: 96 : if (last)
330 : 92 : last->next = method;
331 : : else
332 : 4 : eap_methods = method;
333 : :
334 : 96 : 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 : : */
344 : 4 : void 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 [ + + ]: 100 : while (eap_methods) {
352 : 96 : m = eap_methods;
353 : 96 : 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 [ - + ]: 96 : if (m->free)
360 : 0 : m->free(m);
361 : : else
362 : 96 : 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 : 4 : }
|