Coverage Report

Created: 2026-07-16 06:04

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/hostap/src/eap_peer/eap_methods.c
Line
Count
Source
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
0
{
33
0
  struct eap_method *m;
34
0
  for (m = eap_methods; m; m = m->next) {
35
0
    if (m->vendor == vendor && m->method == method)
36
0
      return m;
37
0
  }
38
0
  return NULL;
39
0
}
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
0
{
53
0
  struct eap_method *m;
54
0
  for (m = eap_methods; m; m = m->next) {
55
0
    if (os_strcmp(m->name, name) == 0) {
56
0
      *vendor = m->vendor;
57
0
      return m->method;
58
0
    }
59
0
  }
60
0
  *vendor = EAP_VENDOR_IETF;
61
0
  return EAP_TYPE_NONE;
62
0
}
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
0
{
76
0
  struct eap_method *m;
77
0
  if (vendor == EAP_VENDOR_IETF && type == EAP_TYPE_EXPANDED)
78
0
    return "expanded";
79
0
  for (m = eap_methods; m; m = m->next) {
80
0
    if (m->vendor == vendor && m->method == type)
81
0
      return m->name;
82
0
  }
83
0
  return NULL;
84
0
}
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
0
{
96
0
  char *pos, *end;
97
0
  struct eap_method *m;
98
0
  int ret;
99
100
0
  if (buflen == 0)
101
0
    return 0;
102
103
0
  pos = buf;
104
0
  end = pos + buflen;
105
106
0
  for (m = eap_methods; m; m = m->next) {
107
0
    ret = os_snprintf(pos, end - pos, "%s%s",
108
0
          m == eap_methods ? "" : " ", m->name);
109
0
    if (os_snprintf_error(end - pos, ret))
110
0
      break;
111
0
    pos += ret;
112
0
  }
113
0
  buf[buflen - 1] = '\0';
114
115
0
  return pos - buf;
116
0
}
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
0
{
131
0
  struct eap_method *m;
132
0
  size_t array_len = 0;
133
0
  char **array;
134
0
  int i = 0, j;
135
136
0
  for (m = eap_methods; m; m = m->next)
137
0
    array_len++;
138
139
0
  array = os_calloc(array_len + 1, sizeof(char *));
140
0
  if (array == NULL)
141
0
    return NULL;
142
143
0
  for (m = eap_methods; m; m = m->next) {
144
0
    array[i++] = os_strdup(m->name);
145
0
    if (array[i - 1] == NULL) {
146
0
      for (j = 0; j < i; j++)
147
0
        os_free(array[j]);
148
0
      os_free(array);
149
0
      return NULL;
150
0
    }
151
0
  }
152
0
  array[i] = NULL;
153
154
0
  if (num)
155
0
    *num = array_len;
156
157
0
  return array;
158
0
}
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
0
{
168
0
  int c = 0;
169
0
  struct eap_method *m;
170
171
0
  for (m = eap_methods; m; m = m->next)
172
0
    c++;
173
174
0
  *count = c;
175
0
  return eap_methods;
176
0
}
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
0
{
286
0
  struct eap_method *eap;
287
0
  eap = os_zalloc(sizeof(*eap));
288
0
  if (eap == NULL)
289
0
    return NULL;
290
0
  eap->version = version;
291
0
  eap->vendor = vendor;
292
0
  eap->method = method;
293
0
  eap->name = name;
294
0
  return eap;
295
0
}
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
0
{
304
0
  os_free(method);
305
0
}
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
0
{
320
0
  struct eap_method *m, *last = NULL;
321
322
0
  if (method == NULL || method->name == NULL ||
323
0
      method->version != EAP_PEER_METHOD_INTERFACE_VERSION) {
324
0
    eap_peer_method_free(method);
325
0
    return -1;
326
0
  }
327
328
0
  for (m = eap_methods; m; m = m->next) {
329
0
    if ((m->vendor == method->vendor &&
330
0
         m->method == method->method) ||
331
0
        os_strcmp(m->name, method->name) == 0) {
332
0
      eap_peer_method_free(method);
333
0
      return -2;
334
0
    }
335
0
    last = m;
336
0
  }
337
338
0
  if (last)
339
0
    last->next = method;
340
0
  else
341
0
    eap_methods = method;
342
343
0
  return 0;
344
0
}
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
0
{
355
0
  struct eap_method *m;
356
#ifdef CONFIG_DYNAMIC_EAP_METHODS
357
  void *handle;
358
#endif /* CONFIG_DYNAMIC_EAP_METHODS */
359
360
0
  while (eap_methods) {
361
0
    m = eap_methods;
362
0
    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
0
    if (m->free)
369
0
      m->free(m);
370
0
    else
371
0
      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
0
  }
378
0
}