The FreeRADIUS server  $Id: 15bac2a4c627c01d1aa2047687b3418955ac7f00 $
rlm_eap.c
Go to the documentation of this file.
1 /*
2  * This program is is free software; you can redistribute it and/or modify
3  * it under the terms of the GNU General Public License as published by
4  * the Free Software Foundation; either version 2 of the License, or (at
5  * your option) any later version.
6  *
7  * This program is distributed in the hope that it will be useful,
8  * but WITHOUT ANY WARRANTY; without even the implied warranty of
9  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
10  * GNU General Public License for more details.
11  *
12  * You should have received a copy of the GNU General Public License
13  * along with this program; if not, write to the Free Software
14  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
15  */
16 
17 /**
18  * $Id: eadf9012b1d4a386c120c470b501369c4724832a $
19  * @file rlm_eap.c
20  * @brief Implements the EAP framework.
21  *
22  * @copyright 2000-2003,2006 The FreeRADIUS server project
23  * @copyright 2001 hereUare Communications, Inc. (raghud@hereuare.com)
24  * @copyright 2003 Alan DeKok (aland@freeradius.org)
25  */
26 RCSID("$Id: eadf9012b1d4a386c120c470b501369c4724832a $")
27 
28 #define LOG_PREFIX mctx->inst->name
29 
30 #include <freeradius-devel/server/base.h>
31 #include <freeradius-devel/server/module_rlm.h>
32 #include <freeradius-devel/server/dl_module.h>
33 #include <freeradius-devel/server/dl_module.h>
34 #include <freeradius-devel/protocol/freeradius/freeradius.internal.h>
35 #include <freeradius-devel/unlang/interpret.h>
36 #include <freeradius-devel/unlang/module.h>
37 #include "rlm_eap.h"
38 
39 extern module_rlm_t rlm_eap;
40 
41 /** Resume context for calling a submodule
42  *
43  */
44 typedef struct {
45  char const *caller; //!< Original caller.
46  rlm_eap_t *inst; //!< Instance of the rlm_eap module.
47  eap_session_t *eap_session; //!< The eap_session we're continuing.
48  rlm_rcode_t rcode; //!< The result of the submodule.
50 
51 static int submodule_parse(TALLOC_CTX *ctx, void *out, UNUSED void *parent,
52  CONF_ITEM *ci, UNUSED conf_parser_t const *rule);
53 static int eap_type_parse(UNUSED TALLOC_CTX *ctx, void *out, UNUSED void *parent,
54  CONF_ITEM *ci, UNUSED conf_parser_t const *rule);
55 
57  { L("nai"), REQUIRE_REALM_NAI },
58  { L("no"), REQUIRE_REALM_NO },
59  { L("yes"), REQUIRE_REALM_YES }
60 };
62 
63 static const conf_parser_t module_config[] = {
64  { FR_CONF_OFFSET("require_identity_realm", rlm_eap_t, require_realm),
65  .func = cf_table_parse_int,
67  .dflt = "nai" },
68 
69  { FR_CONF_OFFSET_IS_SET("default_eap_type", FR_TYPE_VOID, 0, rlm_eap_t, default_method), .func = eap_type_parse },
70 
72 
73  { FR_CONF_OFFSET("ignore_unknown_eap_types", rlm_eap_t, ignore_unknown_types), .dflt = "no" },
74 
75  { FR_CONF_DEPRECATED("timer_expire", rlm_eap_t, timer_limit), .dflt = "60" },
76  { FR_CONF_DEPRECATED("cisco_accounting_username_bug", rlm_eap_t,
77  cisco_accounting_username_bug), .dflt = "no" },
78  { FR_CONF_DEPRECATED("max_sessions", rlm_eap_t, max_sessions), .dflt = "2048" },
80 };
81 
82 static fr_dict_t const *dict_freeradius;
83 static fr_dict_t const *dict_radius;
84 
87  { .out = &dict_freeradius, .proto = "freeradius" },
88  { .out = &dict_radius, .proto = "radius" },
89  { NULL }
90 };
91 
96 
99 static fr_dict_attr_t const *attr_state;
101 
102 
105  { .out = &attr_auth_type, .name = "Auth-Type", .type = FR_TYPE_UINT32, .dict = &dict_freeradius },
106  { .out = &attr_eap_type, .name = "EAP-Type", .type = FR_TYPE_UINT32, .dict = &dict_freeradius },
107  { .out = &attr_eap_identity, .name = "EAP-Identity", .type = FR_TYPE_STRING, .dict = &dict_freeradius },
108  { .out = &attr_stripped_user_domain, .name = "Stripped-User-Domain", .type = FR_TYPE_STRING, .dict = &dict_freeradius },
109 
110  { .out = &attr_eap_message, .name = "EAP-Message", .type = FR_TYPE_OCTETS, .dict = &dict_radius },
111  { .out = &attr_message_authenticator, .name = "Message-Authenticator", .type = FR_TYPE_OCTETS, .dict = &dict_radius },
112  { .out = &attr_state, .name = "State", .type = FR_TYPE_OCTETS, .dict = &dict_radius },
113  { .out = &attr_user_name, .name = "User-Name", .type = FR_TYPE_STRING, .dict = &dict_radius },
114 
115  { NULL }
116 };
117 
118 static unlang_action_t mod_authenticate(rlm_rcode_t *p_result, module_ctx_t const *mctx, request_t *request) CC_HINT(nonnull);
119 static unlang_action_t mod_authorize(rlm_rcode_t *p_result, module_ctx_t const *mctx, request_t *request) CC_HINT(nonnull);
120 
121 /** Wrapper around dl_instance which loads submodules based on type = foo pairs
122  *
123  * @param[in] ctx to allocate data in (instance of rlm_eap_t).
124  * @param[out] out Where to write child conf section to.
125  * @param[in] parent Base structure address.
126  * @param[in] ci #CONF_PAIR specifying the name of the type module.
127  * @param[in] rule unused.
128  * @return
129  * - 0 on success.
130  * - -1 on failure.
131  */
132 static int submodule_parse(TALLOC_CTX *ctx, void *out, void *parent,
133  CONF_ITEM *ci, conf_parser_t const *rule)
134 { char const *name = cf_pair_value(cf_item_to_pair(ci));
135  char *our_name = NULL;
136  char *p;
137  eap_type_t method;
138 
139  /*
140  * Search with underscores smashed to hyphens
141  * as that's what's used in the dictionary.
142  */
143  p = our_name = talloc_strdup(NULL, name);
144  while (*p) {
145  if (*p == '_') *p = '-';
146  p++;
147  }
148 
149  method = eap_name2type(our_name);
150  talloc_free(our_name);
151 
152  if (method == FR_EAP_METHOD_INVALID) {
153  talloc_free(our_name);
154  cf_log_err(ci, "Unknown EAP type %s", name);
155  return -1;
156  }
157 
158 #if !defined(HAVE_OPENSSL_SSL_H) || !defined(HAVE_LIBSSL)
159  /*
160  * This allows the default configuration to be
161  * shipped with EAP-TLS, etc. enabled. If the
162  * system doesn't have OpenSSL, they will be
163  * ignored.
164  *
165  * If the system does have OpenSSL, then this
166  * code will not be used. The administrator will
167  * then have to delete the tls,
168  * etc. configurations from eap.conf in order to
169  * have EAP without the TLS types.
170  */
171  switch (method) {
172  case FR_EAP_METHOD_TLS:
173  case FR_EAP_METHOD_TTLS:
174  case FR_EAP_METHOD_PEAP:
175  case FR_EAP_METHOD_PWD:
177  case FR_EAP_METHOD_AKA:
178  case FR_EAP_METHOD_SIM:
179  {
181 
184  dl_module_inst_t, "rlm_eap"))));
185  WARN("Ignoring EAP method %s because we don't have OpenSSL support", name);
186  }
187  return 0;
188 
189  default:
190  break;
191  }
192 #endif
193  return module_rlm_submodule_parse(ctx, out, parent, ci, rule);
194 }
195 
196 /** Convert EAP type strings to eap_type_t values
197  *
198  * @param[in] ctx unused.
199  * @param[out] out Where to write the #eap_type_t value we found.
200  * @param[in] parent Base structure address.
201  * @param[in] ci #CONF_PAIR specifying the name of the EAP method.
202  * @param[in] rule unused.
203  * @return
204  * - 0 on success.
205  * - -1 on failure.
206  */
207 static int eap_type_parse(UNUSED TALLOC_CTX *ctx, void *out, UNUSED void *parent,
208  CONF_ITEM *ci, UNUSED conf_parser_t const *rule)
209 {
210  char const *default_method_name = cf_pair_value(cf_item_to_pair(ci));
211  eap_type_t method;
212 
213  /*
214  * Ensure that the default EAP type is loaded.
215  */
216  method = eap_name2type(default_method_name);
217  if (method == FR_EAP_METHOD_INVALID) {
218  cf_log_err(ci, "Unknown EAP type %s", default_method_name);
219  return -1;
220  }
221 
222  *(eap_type_t *)out = method;
223 
224  return 0;
225 }
226 
227 /** Process NAK data from EAP peer
228  *
229  */
230 static eap_type_t eap_process_nak(module_ctx_t const *mctx, request_t *request,
231  eap_type_t last_type,
232  eap_type_data_t *nak)
233 {
235  unsigned int i, s_i = 0;
236  fr_pair_t *vp = NULL;
238  eap_type_t sanitised[nak->length];
239 
240  /*
241  * The NAK data is the preferred EAP type(s) of
242  * the client.
243  *
244  * RFC 3748 says to list one or more proposed
245  * alternative types, one per octet, or to use
246  * 0 for no alternative.
247  */
248  if (!nak->data) {
249  REDEBUG("Peer sent empty (invalid) NAK. Can't select method to continue with");
250 
251  return FR_EAP_METHOD_INVALID;
252  }
253 
254  /*
255  * Do a loop over the contents of the NAK, only moving entries
256  * which are valid to the sanitised array.
257  */
258  for (i = 0; i < nak->length; i++) {
259  /*
260  * Type 0 is valid, and means there are no
261  * common choices.
262  */
263  if (nak->data[i] == 0) {
264  REDEBUG("Peer NAK'd indicating it is not willing to continue");
265 
266  return FR_EAP_METHOD_INVALID;
267  }
268 
269  /*
270  * It is invalid to request identity,
271  * notification & nak in nak.
272  */
273  if (nak->data[i] < FR_EAP_METHOD_MD5) {
274  REDEBUG("Peer NAK'd asking for bad type %s (%d)", eap_type2name(nak->data[i]), nak->data[i]);
275 
276  return FR_EAP_METHOD_INVALID;
277  }
278 
279  if ((nak->data[i] >= FR_EAP_METHOD_MAX) ||
280  !inst->methods[nak->data[i]].submodule) {
281  RDEBUG2("Peer NAK'd asking for unsupported EAP type %s (%d), skipping...",
282  eap_type2name(nak->data[i]),
283  nak->data[i]);
284 
285  continue;
286  }
287 
288  /*
289  * Prevent a firestorm if the client is confused.
290  *
291  * FIXME: Really we should keep a list of
292  * methods we've already sent back.
293  */
294  if (last_type == nak->data[i]) {
295  char const *type_str = eap_type2name(nak->data[i]);
296 
297  RDEBUG2("Peer NAK'd our request for %s (%d) with a request for %s (%d), skipping...",
298  type_str, nak->data[i], type_str, nak->data[i]);
299 
300  RWARN("!!! We requested to use EAP type %s (%i)", type_str, nak->data[i]);
301  RWARN("!!! The supplicant rejected that, and requested to use the same EAP type.");
302  RWARN("!!! i.e. the supplicant said 'I don't like %s, please use %s instead.",
303  type_str, type_str);
304  RWARN("!!! The supplicant software is broken and does not work properly.");
305  RWARN("!!! Please upgrade it to software that works.");
306 
307  continue;
308  }
309 
310  sanitised[s_i++] = nak->data[i];
311  }
312 
313  if (s_i == 0) {
314  REDEBUG("Peer presented no valid EAP types in its NAK response");
315  return FR_EAP_METHOD_INVALID;
316  }
317 
318  vp = fr_pair_find_by_da(&request->control_pairs, NULL, attr_eap_type);
319  if (vp) {
320  /*
321  * Loop over allowed methods and the contents
322  * of the NAK, attempting to find something
323  * we can continue with.
324  */
325  do {
326  /*
327  * Provide a way of the admin potentially
328  * disabling EAP negotiation.
329  */
330  if (vp->vp_uint32 == FR_EAP_METHOD_INVALID) continue;
331 
332  for (i = 0; i < s_i; i++) {
333  /*
334  * Enforce per-user configuration of EAP
335  * types.
336  */
337  if (vp->vp_uint32 != sanitised[i]) continue;
338  RDEBUG2("Found mutually acceptable type %s (%d)", eap_type2name(sanitised[i]), sanitised[i]);
339  method = sanitised[i];
340  break;
341  }
342 
343  if (method != FR_EAP_METHOD_INVALID) break; /* Found one1 */
344  } while ((vp = fr_pair_find_by_da(&request->control_pairs, vp, attr_eap_type)));
345  /*
346  * If there's no control pairs, respond with
347  * the first valid method in the NAK.
348  */
349  } else {
350  method = sanitised[0];
351  }
352 
353  /*
354  * Couldn't find something to continue with,
355  * emit a very verbose message.
356  */
357  if (method == FR_EAP_METHOD_INVALID) {
358  fr_sbuff_t *proposed = NULL, *allowed = NULL;
359 
360  FR_SBUFF_TALLOC_THREAD_LOCAL(&proposed, 256, 1024);
361  FR_SBUFF_TALLOC_THREAD_LOCAL(&allowed, 256, 1024);
362 
363  for (i = 0; i < s_i; i++) {
364  (void) fr_sbuff_in_sprintf(proposed, "%s (%d), ", eap_type2name(sanitised[i]), sanitised[i]);
365  }
366  fr_sbuff_advance(proposed, -2);
367  fr_sbuff_terminate(proposed);
368 
369  vp = NULL;
370  while ((vp = fr_pair_find_by_da(&request->control_pairs, vp, attr_eap_type))) {
371  (void) fr_sbuff_in_sprintf(allowed, "%s (%d), ", eap_type2name(vp->vp_uint32), vp->vp_uint32);
372  }
373  fr_sbuff_advance(allowed, -2); /* Negative advance past start should be disallowed */
374  fr_sbuff_terminate(allowed);
375 
376  REDEBUG("No mutually acceptable EAP types found. Supplicant proposed: %s. We allow: %s",
377  fr_sbuff_start(proposed), fr_sbuff_start(allowed));
378  }
379 
380  return method;
381 }
382 
383 /** Cancel a call to a submodule
384  *
385  * @param[in] mctx module calling ctx.
386  * @param[in] request The current request.
387  * @param[in] action to perform.
388  */
389 static void mod_authenticate_cancel(module_ctx_t const *mctx, request_t *request, UNUSED fr_signal_t action)
390 {
391  eap_session_t *eap_session;
392 
393  RDEBUG2("Request cancelled - Destroying EAP-Session");
394 
395  eap_session = talloc_get_type_abort(mctx->rctx, eap_session_t);
396 
397  TALLOC_FREE(eap_session->subrequest);
398 
399  /*
400  * This is the only safe thing to do.
401  * We have no idea what state the submodule
402  * left its opaque data in.
403  */
404  eap_session_destroy(&eap_session);
405 }
406 
407 /** Process the result of calling a submodule
408  *
409  * @param[out] p_result Result of calling the module, one of:
410  * - RLM_MODULE_INVALID if the request or EAP session state is invalid.
411  * - RLM_MODULE_OK if this round succeeded.
412  * - RLM_MODULE_HANDLED if we're done with this round.
413  * - RLM_MODULE_REJECT if the user should be rejected.
414  * @param[in] request The current request.
415  * @param[in] mctx module calling ctx.
416  * @param[in] eap_session the EAP session
417  * @param[in] result the input result from the submodule
418  */
420  request_t *request, eap_session_t *eap_session, rlm_rcode_t result)
421 {
422  rlm_rcode_t rcode;
423 
424  /*
425  * Cleanup the subrequest
426  */
427  TALLOC_FREE(eap_session->subrequest);
428 
429  /*
430  * The submodule failed. Die.
431  */
432  switch (result) {
433  case RLM_MODULE_FAIL:
434  case RLM_MODULE_INVALID:
435  eap_fail(eap_session);
436  eap_session_destroy(&eap_session);
437 
438  rcode = RLM_MODULE_INVALID;
439  goto finish;
440 
441  /*
442  * Inconsistent result from submodule...
443  */
444  case RLM_MODULE_REJECT:
445  case RLM_MODULE_DISALLOW:
446  eap_session->this_round->request->code = FR_EAP_CODE_FAILURE;
447  break;
448 
449  default:
450  break;
451  }
452 
453  /*
454  * We are done, wrap the EAP-request in RADIUS to send
455  * with all other required radius attributes
456  */
457  rcode = eap_compose(eap_session);
458 
459  /*
460  * Add to the list only if it is EAP-Request, OR if
461  * it's LEAP, and a response.
462  */
463  if (((eap_session->this_round->request->code == FR_EAP_CODE_REQUEST) &&
464  (eap_session->this_round->request->type.num >= FR_EAP_METHOD_MD5)) ||
465 
466  /*
467  * LEAP is a little different. At Stage 4,
468  * it sends an EAP-Success message, but we still
469  * need to keep the State attribute & session
470  * data structure around for the AP Challenge.
471  *
472  * At stage 6, LEAP sends an EAP-Response, which
473  * isn't put into the list.
474  */
475  ((eap_session->this_round->response->code == FR_EAP_CODE_RESPONSE) &&
476  (eap_session->this_round->response->type.num == FR_EAP_METHOD_LEAP) &&
477  (eap_session->this_round->request->code == FR_EAP_CODE_SUCCESS) &&
478  (eap_session->this_round->request->type.num == 0))) {
479  talloc_free(eap_session->prev_round);
480  eap_session->prev_round = eap_session->this_round;
481  eap_session->this_round = NULL;
482  } else {
483  RDEBUG2("Cleaning up EAP session");
484  eap_session_destroy(&eap_session);
485  }
486 
487  /*
488  * Freeze the eap_session so we can continue
489  * the authentication session later.
490  */
491  eap_session_freeze(&eap_session);
492 
493 finish:
494  RETURN_MODULE_RCODE(rcode);
495 }
496 
497 /** Call mod_authenticate_result asynchronously from the unlang interpreter
498  *
499  * @param[out] p_result The result of the operation.
500  * @param[in] mctx module calling ctx.
501  * @param[in] request the current request.
502  * @return The result of this round of authentication.
503  */
505  request_t *request)
506 {
507  eap_session_t *eap_session = talloc_get_type_abort(mctx->rctx, eap_session_t);
508 
509  return mod_authenticate_result(p_result, mctx, request, eap_session, eap_session->submodule_rcode);
510 }
511 
512 /** Basic tests to determine if an identity is a valid NAI
513  *
514  * In this version we mostly just care about realm.
515  *
516  * @param[in] identity to check.
517  * @return
518  * - The length of the string on success.
519  * - <= 0 a negative offset specifying where the format error occurred.
520  */
521 static ssize_t eap_identity_is_nai_with_realm(char const *identity)
522 {
523  char const *p = identity;
524  char const *end = identity + (talloc_array_length(identity) - 1);
525  char const *realm;
526 
527  /*
528  * Get the last '@'
529  */
530  p = realm = memrchr(identity, '@', end - p);
531  if (!p) {
532  fr_strerror_printf("Identity is not valid. Missing realm separator '@'");
533  return identity - end;
534  }
535 
536  p = memchr(p, '.', end - p);
537  if (!p) {
538  fr_strerror_printf("Identity is not valid. Realm is missing label separator '.'");
539  return identity - end;
540  }
541 
542  if ((realm - 1) == p) {
543  fr_strerror_printf("Identity is not valid. "
544  "Realm is missing label between realm separator '@' and label separator '.'");
545  return identity - realm;
546  }
547  if ((p + 1) == end) {
548  fr_strerror_printf("Identity is not valid. "
549  "Realm is missing label between label separator '.' and the end of the "
550  "identity string");
551  return identity - end;
552  }
553 
554  return end - identity;
555 }
556 
557 /** Select the correct callback based on a response
558  *
559  * Based on the EAP response from the supplicant, and setup a call on the
560  * unlang stack to the appropriate submodule.
561  *
562  * Default to the configured EAP-Type for all Unsupported EAP-Types.
563  *
564  * @param[out] p_result the result of the operation.
565  * @param[in] mctx module calling ctx.
566  * @param[in] eap_session State data that persists over multiple rounds of EAP.
567  * @return
568  * - UNLANG_ACTION_CALCULATE_RESULT + *p_result = RLM_MODULE_INVALID.
569  * Invalid request.
570  * - UNLANG_ACTION_PUSHED_CHILD Yield control back to the interpreter so it can
571  * call the submodule.
572  */
573 static unlang_action_t eap_method_select(rlm_rcode_t *p_result, module_ctx_t const *mctx, eap_session_t *eap_session)
574 {
576  eap_type_data_t *type = &eap_session->this_round->response->type;
577  request_t *request = eap_session->request;
578 
579  rlm_eap_method_t const *method;
580 
581  eap_type_t next = inst->default_method;
582  fr_pair_t *vp;
583 
584  /*
585  * Session must have been thawed...
586  */
587  fr_assert(eap_session->request);
588 
589  /*
590  * Don't trust anyone.
591  */
592  if ((type->num == 0) || (type->num >= FR_EAP_METHOD_MAX)) {
593  REDEBUG("Peer sent EAP type number %d, which is outside known range", type->num);
594 
595  is_invalid:
597  }
598 
599  /*
600  * Multiple levels of TLS nesting are invalid. But if
601  * the parent has a home_server defined, then this
602  * request is being processed through a virtual
603  * server... so that's OK.
604  *
605  * i.e. we're inside an EAP tunnel, which means we have a
606  * parent. If the outer session exists, and doesn't have
607  * a home server, then it's multiple layers of tunneling.
608  */
609  if (eap_session->request->parent &&
610  eap_session->request->parent->parent) {
611  RERROR("Multiple levels of TLS nesting are invalid");
612  goto is_invalid;
613  }
614 
615  RDEBUG2("Peer sent packet with EAP method %s (%d)", eap_type2name(type->num), type->num);
616 
617  /*
618  * Figure out what to do.
619  */
620  switch (type->num) {
622  {
623  ssize_t slen;
624 
625  /*
626  * Check if we allow this identity format
627  */
628  switch (inst->require_realm) {
629  case REQUIRE_REALM_NAI:
630  slen = eap_identity_is_nai_with_realm(eap_session->identity);
631  if (slen <= 0) {
632  char *tmp_id;
633  bad_id:
634  /*
635  * Produce an escaped version and run that
636  * through the format check function to get
637  * the correct offset *sigh*...
638  */
639  MEM(tmp_id = fr_asprint(NULL,
640  eap_session->identity,
641  talloc_array_length(eap_session->identity) - 1,
642  '"'));
643  slen = eap_identity_is_nai_with_realm(tmp_id);
644 
645  REMARKER(tmp_id, slen, "%s", fr_strerror());
646 
647  talloc_free(tmp_id);
648  goto is_invalid;
649  }
650  break;
651 
652  case REQUIRE_REALM_YES:
653  slen = eap_identity_is_nai_with_realm(eap_session->identity);
654  if (slen <= 0) {
655  fr_pair_t *stripped_user_domain;
656 
657  /*
658  * If it's not an NAI with a realm, check
659  * to see if the user has set Stripped-User-domain.
660  */
661  stripped_user_domain = fr_pair_find_by_da_idx(&eap_session->request->request_pairs,
663  if (!stripped_user_domain) goto bad_id;
664  }
665  break;
666 
667  case REQUIRE_REALM_NO:
668  break;
669  }
670  }
671  /*
672  * Allow per-user configuration of EAP types.
673  */
674  vp = fr_pair_find_by_da(&eap_session->request->control_pairs, NULL, attr_eap_type);
675  if (vp) {
676  RDEBUG2("Using method from &control.EAP-Type");
677  next = vp->vp_uint32;
678  /*
679  * We have an array of the submodules which
680  * have a type_identity callback. Call
681  * each of these in turn to see if any of
682  * them recognise the identity.
683  */
684  } else if (inst->type_identity_submodule) {
685  size_t i;
686 
687  for (i = 0; i < inst->type_identity_submodule_len; i++) {
688  rlm_eap_submodule_t const *submodule =
689  (rlm_eap_submodule_t const *)inst->type_identity_submodule[i]->module;
690  eap_type_t ret;
691 
692  ret = submodule->type_identity(inst->type_identity_submodule[i]->dl_inst->data,
693  eap_session->identity,
694  talloc_array_length(eap_session->identity) - 1);
695  if (ret != FR_EAP_METHOD_INVALID) {
696  next = ret;
697  break;
698  }
699  }
700  }
701  do_init:
702  /*
703  * Ensure it's valid.
704  */
705  if ((next < FR_EAP_METHOD_MD5) || (next >= FR_EAP_METHOD_MAX) || (!inst->methods[next].submodule)) {
706  REDEBUG2("Peer tried to start unsupported EAP type %s (%d)",
707  eap_type2name(next), next);
708  goto is_invalid;
709  }
710 
711  eap_session->process = inst->methods[next].submodule->session_init;
712  eap_session->type = next;
713  break;
714 
715  case FR_EAP_METHOD_NAK:
716  /*
717  * Delete old data, if necessary. If we called a method
718  * before, and it initialized itself, we need to free
719  * the memory it alloced.
720  */
721  TALLOC_FREE(eap_session->opaque);
722  fr_state_discard_child(eap_session->request, eap_session, 0);
723  next = eap_process_nak(mctx, eap_session->request, eap_session->type, type);
724  if (!next) RETURN_MODULE_REJECT;
725 
726  /*
727  * Initialise the state machine for the next submodule
728  */
729  goto do_init;
730 
731  /*
732  * Only allow modules that are enabled to be called,
733  * treating any other requests as invalid.
734  *
735  * This may seem a bit harsh, but remember the server
736  * dictates which type of EAP method should be started,
737  * so this is the supplicant ignoring the normal EAP method
738  * negotiation mechanism, by not NAKing and just trying
739  * to start a new EAP method.
740  */
741  default:
742  if (!inst->methods[type->num].submodule) {
743  REDEBUG2("Peer asked for unsupported EAP type %s (%d)", eap_type2name(type->num), type->num);
744  goto is_invalid;
745  }
746  /*
747  * Perr started the EAP method without
748  * sending an Identity-Response.
749  *
750  * There's nothing that says it *HAS* to send an
751  * identity response before starting a method,
752  * so just jump to the initialisation function
753  * of the method and continue.
754  */
755  if (eap_session->rounds == 0) {
756  RDEBUG2("Peer started EAP type %s (%d) without sending an Identity", eap_type2name(type->num), type->num);
757  vp = fr_pair_find_by_da(&eap_session->request->control_pairs, NULL, attr_eap_type);
758  if (vp) {
759  RDEBUG2("Using method from &control.EAP-Type");
760  next = vp->vp_uint32;
761  }
762  goto do_init;
763  }
764 
765  /*
766  * FIXME - We should only update the type
767  * on completion of the final round.
768  */
769  eap_session->type = type->num;
770  break;
771  }
772 
773  method = &inst->methods[eap_session->type];
774 
775  RDEBUG2("Calling submodule %s", method->submodule->common.name);
776 
777  /*
778  * Allocate a new subrequest
779  */
780  MEM(eap_session->subrequest = unlang_subrequest_alloc(request,
781  method->submodule->namespace ?
782  *(method->submodule->namespace) :
783  request->dict));
784 
785  if (method->submodule->clone_parent_lists) {
786  if (fr_pair_list_copy(eap_session->subrequest->control_ctx,
787  &eap_session->subrequest->control_pairs, &request->control_pairs) < 0) {
788  list_copy_fail:
789  RERROR("Failed copying parent's attribute list");
790  fail:
791  TALLOC_FREE(eap_session->subrequest);
793  }
794 
795  if (fr_pair_list_copy(eap_session->subrequest->request_ctx,
796  &eap_session->subrequest->request_pairs,
797  &request->request_pairs) < 0) goto list_copy_fail;
798  }
799 
800  /*
801  * Push a resumption frame for the parent
802  * This will get executed when the child is
803  * done (after the subrequest frame in the
804  * parent gets popped).
805  */
806  (void)unlang_module_yield(request, mod_authenticate_result_async, mod_authenticate_cancel, ~FR_SIGNAL_CANCEL, eap_session);
807 
808  /*
809  * This sets up a subrequest frame in the parent
810  * and a resumption frame in the child.
811  *
812  * This must be done before pushing frames onto
813  * the child's stack.
814  */
815  if (unlang_subrequest_child_push(&eap_session->submodule_rcode, eap_session->subrequest,
816  &(unlang_subrequest_session_t){ .enable = true, .unique_ptr = eap_session },
817  false, UNLANG_SUB_FRAME) < 0) {
818  child_fail:
819  unlang_interpet_frame_discard(request); /* Ensure the yield frame doesn't stick around */
820  goto fail;
821  }
822 
823  /*
824  * Push the EAP submodule into the child's stack
825  */
826  if (unlang_module_push(NULL, /* rcode should bubble up and be set in eap_session->submodule_rcode */
827  eap_session->subrequest, method->submodule_inst, eap_session->process,
828  UNLANG_SUB_FRAME) < 0) {
829  goto child_fail;
830  }
831 
832  if (eap_session->identity) {
833  fr_pair_t *identity;
834 
835  request = eap_session->subrequest; /* Set request for pair_append_request macro */
836 
837  MEM(pair_append_request(&identity, attr_eap_identity) >= 0);
838  fr_pair_value_bstrdup_buffer(identity, eap_session->identity, true);
839  }
840 
841  /*
842  * Add the EAP-Type we're running to the subrequest
843  * This is useful for when policies are shared between
844  * virtual server sections for multiple EAP types.
845  */
846  {
847  fr_pair_t *type_vp;
848 
849  MEM(pair_append_request(&type_vp, attr_eap_type) >= 0);
850  type_vp->vp_uint32 = eap_session->type;
851  }
852 
854 }
855 
856 static unlang_action_t mod_authenticate(rlm_rcode_t *p_result, module_ctx_t const *mctx, request_t *request)
857 {
859  eap_session_t *eap_session;
860  eap_packet_raw_t *eap_packet;
861  unlang_action_t ua;
862 
863  if (!fr_pair_find_by_da(&request->request_pairs, NULL, attr_eap_message)) {
864  REDEBUG("You set 'Auth-Type = EAP' for a request that does not contain an EAP-Message attribute!");
866  }
867 
868  /*
869  * Reconstruct the EAP packet from the EAP-Message
870  * attribute. The relevant decoder should have already
871  * concatenated the fragments into a single buffer.
872  */
873  eap_packet = eap_packet_from_vp(request, &request->request_pairs);
874  if (!eap_packet) {
875  RPERROR("Malformed EAP Message");
877  }
878 
879  /*
880  * Allocate a new eap_session, or if this request
881  * is part of an ongoing authentication session,
882  * retrieve the existing eap_session from the request
883  * data.
884  */
885  eap_session = eap_session_continue(inst, &eap_packet, request);
886  if (!eap_session) RETURN_MODULE_INVALID; /* Don't emit error here, it will mask the real issue */
887 
888  /*
889  * Call an EAP submodule to process the request,
890  * or with simple types like Identity and NAK,
891  * process it ourselves.
892  */
893  if ((ua = eap_method_select(p_result, mctx, eap_session)) != UNLANG_ACTION_CALCULATE_RESULT) return ua;
894  switch (*p_result) {
895  case RLM_MODULE_OK:
896  case RLM_MODULE_UPDATED:
897  eap_session_freeze(&eap_session);
898  break;
899 
900  /*
901  * RFC 3748 Section 2
902  * The conversation continues until the authenticator cannot
903  * authenticate the peer (unacceptable Responses to one or more
904  * Requests), in which case the authenticator implementation MUST
905  * transmit an EAP Failure (Code 4).
906  */
907  default:
908  eap_fail(eap_session);
909  eap_session_destroy(&eap_session);
910  break;
911  }
912 
913  return ua;
914 }
915 
916 /*
917  * EAP authorization DEPENDS on other rlm authorizations,
918  * to check for user existence & get their configured values.
919  * It Handles EAP-START Messages, User-Name initialization.
920  */
921 static unlang_action_t mod_authorize(rlm_rcode_t *p_result, module_ctx_t const *mctx, request_t *request)
922 {
924  int status;
925 
926 #ifdef WITH_PROXY
927  /*
928  * We don't do authorization again, once we've seen the
929  * proxy reply (or the proxied packet)
930  */
931  if (request->proxy != NULL)
933 #endif
934 
935  if (!inst->auth_type) {
936  WARN("No 'authenticate %s {...}' section or 'Auth-Type = %s' set. Cannot setup EAP authentication",
937  mctx->inst->name, mctx->inst->name);
939  }
940 
941  /*
942  * For EAP_START, send Access-Challenge with EAP Identity
943  * request. even when we have to proxy this request
944  *
945  * RFC 2869, Section 2.3.1 notes that the "domain" of the
946  * user, (i.e. where to proxy it) comes from the EAP-Identity,
947  * so we CANNOT proxy the user, until we know its identity.
948  *
949  * We therefore send an EAP Identity request.
950  */
951  status = eap_start(request, inst->methods, inst->ignore_unknown_types);
952  switch (status) {
953  case RLM_MODULE_NOOP:
954  case RLM_MODULE_FAIL:
955  case RLM_MODULE_HANDLED:
956  return status;
957 
958  default:
959  break;
960  }
961 
963 
964  if (status == RLM_MODULE_OK) RETURN_MODULE_OK;
965 
967 }
968 
969 static unlang_action_t mod_post_auth(rlm_rcode_t *p_result, module_ctx_t const *mctx, request_t *request)
970 {
971  fr_pair_t *vp;
972  eap_session_t *eap_session;
974 
975  /*
976  * If it's an Access-Accept, RFC 2869, Section 2.3.1
977  * says that we MUST include a User-Name attribute in the
978  * Access-Accept.
979  */
980  username = fr_pair_find_by_da(&request->request_pairs, NULL, attr_user_name);
981  if ((request->reply->code == FR_RADIUS_CODE_ACCESS_ACCEPT) && username) {
982  /*
983  * Doesn't exist, add it in.
984  */
985  vp = fr_pair_find_by_da(&request->reply_pairs, NULL, attr_user_name);
986  if (!vp) {
987  vp = fr_pair_copy(request->reply_ctx, username);
988  fr_pair_append(&request->reply_pairs, vp);
989  }
990  }
991 
992  /*
993  * Only synthesize a failure message if something
994  * previously rejected the request.
995  */
996  if (request->reply->code != FR_RADIUS_CODE_ACCESS_REJECT) RETURN_MODULE_NOOP;
997 
998  if (!fr_pair_find_by_da(&request->request_pairs, NULL, attr_eap_message)) {
999  RDEBUG3("Request didn't contain an EAP-Message, not inserting EAP-Failure");
1001  }
1002 
1003  if (fr_pair_find_by_da(&request->reply_pairs, NULL, attr_eap_message)) {
1004  RDEBUG3("Reply already contained an EAP-Message, not inserting EAP-Failure");
1006  }
1007 
1008  /*
1009  * Retrieve pre-existing eap_session from request
1010  * data. This will have been added to the request
1011  * data by the state API.
1012  */
1013  eap_session = eap_session_thaw(request);
1014  if (!eap_session) {
1015  RDEBUG3("Failed to get eap_session, probably already removed, not inserting EAP-Failure");
1017  }
1018 
1019  /*
1020  * This should never happen, but we may be here
1021  * because there was an unexpected error in the
1022  * EAP module.
1023  */
1024  if (!fr_cond_assert(eap_session->this_round) || !fr_cond_assert(eap_session->this_round->request)) {
1025  eap_session_destroy(&eap_session); /* Free the EAP session, and dissociate it from the request */
1027  }
1028 
1029  /*
1030  * Already set to failure, assume something else
1031  * added EAP-Message with a failure code, do nothing.
1032  */
1034 
1035  /*
1036  * Was *NOT* an EAP-Failure, so we now need to turn it into one.
1037  */
1038  REDEBUG("Request rejected after last call to module \"%s\", transforming response into EAP-Failure",
1039  mctx->inst->name);
1040  eap_fail(eap_session); /* Compose an EAP failure */
1041  eap_session_destroy(&eap_session); /* Free the EAP session, and dissociate it from the request */
1042 
1043  /*
1044  * Make sure there's a message authenticator attribute in the response
1045  * RADIUS protocol code will calculate the correct value later...
1046  */
1049 
1051 }
1052 
1053 static int mod_instantiate(module_inst_ctx_t const *mctx)
1054 {
1055  rlm_eap_t *inst = talloc_get_type_abort(mctx->inst->data, rlm_eap_t);
1056  size_t i;
1057 
1058  inst->auth_type = fr_dict_enum_by_name(attr_auth_type, mctx->inst->name, -1);
1059  if (!inst->auth_type) {
1060  WARN("Failed to find 'authenticate %s {...}' section. EAP authentication will likely not work",
1061  mctx->inst->name);
1062  }
1063 
1064  /*
1065  * Create our own random pool.
1066  */
1067  for (i = 0; i < 256; i++) inst->rand_pool.randrsl[i] = fr_rand();
1068  fr_isaac_init(&inst->rand_pool, 1);
1069  inst->rand_pool.randcnt = 0;
1070 
1071  return 0;
1072 }
1073 
1074 static int mod_bootstrap(module_inst_ctx_t const *mctx)
1075 {
1076  rlm_eap_t *inst = talloc_get_type_abort(mctx->inst->data, rlm_eap_t);
1077  size_t i, j, loaded, count = 0;
1078 
1079  /*
1080  * Load and bootstrap the submodules now
1081  * We have to do that here instead of in a parse function
1082  * Because the submodule might want to look at its parent
1083  * and we haven't completed our own bootstrap phase yet.
1084  */
1085  loaded = talloc_array_length(inst->type_submodules);
1086 
1087  /*
1088  * Pre-allocate the method identity to be the number
1089  * of modules we're going to load.
1090  *
1091  * We'll shrink it later.
1092  */
1093  if (!inst->default_method_is_set) {
1094  MEM(inst->type_identity_submodule = talloc_array(inst, module_instance_t const *, loaded));
1095  }
1096 
1097  for (i = 0; i < loaded; i++) {
1098  module_instance_t *submodule_inst = inst->type_submodules[i];
1099  rlm_eap_submodule_t const *submodule;
1100 
1101  if (!submodule_inst) continue; /* Skipped as we don't have SSL support */
1102 
1103  submodule = (rlm_eap_submodule_t const *)submodule_inst->dl_inst->module->common;
1104 
1105  /*
1106  * Add the methods the submodule provides
1107  */
1108  for (j = 0; j < MAX_PROVIDED_METHODS; j++) {
1109  eap_type_t method;
1110 
1111  if (!submodule->provides[j]) break;
1112 
1113  method = submodule->provides[j];
1114 
1115  /*
1116  * If the user didn't specify a default method
1117  * take the first method provided by the first
1118  * submodule as the default.
1119  */
1120  if (!inst->default_method_is_set && (i == 0)) inst->default_method = method;
1121 
1122  /*
1123  * Check for duplicates
1124  */
1125  if (inst->methods[method].submodule) {
1126  CONF_SECTION *conf = inst->methods[method].submodule_inst->dl_inst->conf;
1127 
1128  cf_log_err(submodule_inst->dl_inst->conf,
1129  "Duplicate EAP-Type %s. Conflicting entry %s[%u]",
1130  eap_type2name(method),
1132 
1133  return -1;
1134  }
1135 
1136  inst->methods[method].submodule_inst = submodule_inst;
1137  inst->methods[method].submodule = submodule;
1138  }
1139 
1140  /*
1141  * This module provides a method identity
1142  * callback. We need to call each of these
1143  * in turn if default_eap_type isn't set,
1144  * to figure out the default eap type.
1145  */
1146  if (!inst->default_method_is_set && submodule->type_identity) {
1147  inst->type_identity_submodule[inst->type_identity_submodule_len++] = submodule_inst;
1148  }
1149  count++;
1150  }
1151 
1152  /*
1153  * Check if the default method specified is actually
1154  * allowed by the config.
1155  */
1156  if (inst->default_method_is_set && !inst->methods[inst->default_method].submodule) {
1157  cf_log_err_by_child(mctx->inst->conf, "default_eap_type", "EAP-Type \"%s\" is not enabled",
1158  eap_type2name(inst->default_method));
1159  return -1;
1160  }
1161 
1162  if (count == 0) {
1163  cf_log_err(mctx->inst->conf, "No EAP method(s) configured, module cannot do anything");
1164  return -1;
1165  }
1166 
1167  /*
1168  * Shrink the method identity array so it's the
1169  * correct length.
1170  */
1171  if (!inst->default_method_is_set) {
1172  if (inst->type_identity_submodule_len > 0) {
1173  MEM(inst->type_identity_submodule = talloc_realloc(inst, inst->type_identity_submodule,
1174  module_instance_t const *,
1175  inst->type_identity_submodule_len));
1176  } else {
1177  TALLOC_FREE(inst->type_identity_submodule);
1178  }
1179  }
1180 
1181  return 0;
1182 }
1183 
1184 static int mod_load(void)
1185 {
1186  if (eap_base_init() < 0) {
1187  fr_perror("Failed initialising EAP base library");
1188  return -1;
1189  }
1190  return 0;
1191 }
1192 
1193 static void mod_unload(void)
1194 {
1195  eap_base_free();
1196 }
1197 
1198 /*
1199  * The module name should be the only globally exported symbol.
1200  * That is, everything else should be 'static'.
1201  */
1203  .common = {
1204  .magic = MODULE_MAGIC_INIT,
1205  .name = "eap",
1206  .inst_size = sizeof(rlm_eap_t),
1207  .config = module_config,
1208  .onload = mod_load,
1209  .unload = mod_unload,
1210  .bootstrap = mod_bootstrap,
1212  },
1213  .method_names = (module_method_name_t[]){
1214  { .name1 = "recv", .name2 = "access-request", .method = mod_authorize },
1215  { .name1 = "authenticate", .name2 = CF_IDENT_ANY, .method = mod_authenticate },
1216  { .name1 = "send", .name2 = CF_IDENT_ANY, .method = mod_post_auth },
1218  }
1219 };
unlang_action_t
Returned by unlang_op_t calls, determine the next action of the interpreter.
Definition: action.h:35
@ UNLANG_ACTION_PUSHED_CHILD
unlang_t pushed a new child onto the stack, execute it instead of continuing.
Definition: action.h:39
@ UNLANG_ACTION_CALCULATE_RESULT
Calculate a new section rlm_rcode_t value.
Definition: action.h:37
#define RCSID(id)
Definition: build.h:444
#define L(_str)
Helper for initialising arrays of string literals.
Definition: build.h:207
#define UNUSED
Definition: build.h:313
#define NUM_ELEMENTS(_t)
Definition: build.h:335
int cf_table_parse_int(UNUSED TALLOC_CTX *ctx, void *out, UNUSED void *parent, CONF_ITEM *ci, conf_parser_t const *rule)
Generic function for parsing conf pair values as int.
Definition: cf_parse.c:1474
#define CONF_PARSER_TERMINATOR
Definition: cf_parse.h:626
#define FR_CONF_DEPRECATED(_name, _struct, _field)
conf_parser_t entry which raises an error if a matching CONF_PAIR is found
Definition: cf_parse.h:385
#define FR_CONF_OFFSET(_name, _struct, _field)
conf_parser_t which parses a single CONF_PAIR, writing the result to a field in a struct
Definition: cf_parse.h:268
#define FR_CONF_OFFSET_IS_SET(_name, _type, _flags, _struct, _field)
conf_parser_t which parses a single CONF_PAIR, writing the result to a field in a struct,...
Definition: cf_parse.h:282
@ CONF_FLAG_MULTI
CONF_PAIR can have multiple copies.
Definition: cf_parse.h:420
@ CONF_FLAG_NOT_EMPTY
CONF_PAIR is required to have a non zero length value.
Definition: cf_parse.h:421
#define FR_CONF_OFFSET_TYPE_FLAGS(_name, _type, _flags, _struct, _field)
conf_parser_t which parses a single CONF_PAIR, writing the result to a field in a struct
Definition: cf_parse.h:241
Defines a CONF_PAIR to C data type mapping.
Definition: cf_parse.h:563
Common header for all CONF_* types.
Definition: cf_priv.h:49
A section grouping multiple CONF_PAIR.
Definition: cf_priv.h:89
CONF_PAIR * cf_item_to_pair(CONF_ITEM const *ci)
Cast a CONF_ITEM to a CONF_PAIR.
Definition: cf_util.c:629
char const * cf_pair_value(CONF_PAIR const *pair)
Return the value of a CONF_PAIR.
Definition: cf_util.c:1511
void * cf_data_value(CONF_DATA const *cd)
Return the user assigned value of CONF_DATA.
Definition: cf_util.c:1680
CONF_SECTION * cf_item_to_section(CONF_ITEM const *ci)
Cast a CONF_ITEM to a CONF_SECTION.
Definition: cf_util.c:649
#define cf_log_err(_cf, _fmt,...)
Definition: cf_util.h:265
#define cf_lineno(_cf)
Definition: cf_util.h:101
#define cf_log_err_by_child(_parent, _child, _fmt,...)
Log an error message against a specified child.
Definition: cf_util.h:292
#define cf_data_find(_cf, _type, _name)
Definition: cf_util.h:220
#define cf_parent(_cf)
Definition: cf_util.h:98
#define cf_filename(_cf)
Definition: cf_util.h:104
#define CF_IDENT_ANY
Definition: cf_util.h:78
rlm_rcode_t eap_fail(eap_session_t *eap_session)
Definition: compose.c:494
rlm_rcode_t eap_start(request_t *request, rlm_eap_method_t const methods[], bool ignore_unknown_types)
Definition: compose.c:291
rlm_rcode_t eap_compose(eap_session_t *eap_session)
Definition: compose.c:153
eap_type_data_t type
Definition: compose.h:39
eap_packet_t * response
Packet we received from the peer.
Definition: compose.h:49
eap_code_t code
Definition: compose.h:36
eap_packet_t * request
Packet we will send to the peer.
Definition: compose.h:50
#define fr_cond_assert(_x)
Calls panic_action ifndef NDEBUG, else logs error and evaluates to value of _x.
Definition: debug.h:137
@ FR_RADIUS_CODE_ACCESS_ACCEPT
RFC2865 - Access-Accept.
Definition: defs.h:34
@ FR_RADIUS_CODE_ACCESS_REJECT
RFC2865 - Access-Reject.
Definition: defs.h:35
fr_dict_attr_t const ** out
Where to write a pointer to the resolved fr_dict_attr_t.
Definition: dict.h:250
fr_dict_t const ** out
Where to write a pointer to the loaded/resolved fr_dict_t.
Definition: dict.h:263
fr_dict_enum_value_t * fr_dict_enum_by_name(fr_dict_attr_t const *da, char const *name, ssize_t len)
Definition: dict_util.c:2992
Specifies an attribute which must be present for the module to function.
Definition: dict.h:249
Specifies a dictionary which must be loaded/loadable for the module to function.
Definition: dict.h:262
dl_module_t const *_CONST module
Module.
Definition: dl_module.h:164
char const *_CONST name
Instance name.
Definition: dl_module.h:163
void *_CONST data
Module instance's parsed configuration.
Definition: dl_module.h:165
#define MODULE_MAGIC_INIT
Stop people using different module/library/server versions together.
Definition: dl_module.h:65
CONF_SECTION *_CONST conf
Module's instance configuration.
Definition: dl_module.h:166
dl_module_common_t const *_CONST common
Symbol exported by the module, containing its public functions, name and behaviour control flags.
Definition: dl_module.h:149
A module/inst tuple.
Definition: dl_module.h:162
eap_type_t eap_name2type(char const *name)
Return an EAP-Type for a particular name.
Definition: types.c:38
char const * eap_type2name(eap_type_t method)
Return an EAP-name for a particular type.
Definition: types.c:54
@ FR_EAP_CODE_FAILURE
Definition: types.h:40
@ FR_EAP_CODE_RESPONSE
Definition: types.h:38
@ FR_EAP_CODE_REQUEST
Definition: types.h:37
@ FR_EAP_CODE_SUCCESS
Definition: types.h:39
eap_type_t num
Definition: types.h:110
size_t length
Definition: types.h:111
enum eap_type eap_type_t
uint8_t * data
Definition: types.h:112
@ FR_EAP_METHOD_SIM
Definition: types.h:63
@ FR_EAP_METHOD_LEAP
Definition: types.h:62
@ FR_EAP_METHOD_NAK
Definition: types.h:48
@ FR_EAP_METHOD_AKA
Definition: types.h:68
@ FR_EAP_METHOD_PWD
Definition: types.h:98
@ FR_EAP_METHOD_AKA_PRIME
Definition: types.h:96
@ FR_EAP_METHOD_TTLS
Definition: types.h:66
@ FR_EAP_METHOD_MD5
Definition: types.h:49
@ FR_EAP_METHOD_IDENTITY
Definition: types.h:46
@ FR_EAP_METHOD_INVALID
Definition: types.h:45
@ FR_EAP_METHOD_TLS
Definition: types.h:58
@ FR_EAP_METHOD_PEAP
Definition: types.h:70
@ FR_EAP_METHOD_MAX
Definition: types.h:102
Structure to represent packet format of eap on wire
Definition: types.h:121
EAP-Type specific data.
Definition: types.h:109
void unlang_interpet_frame_discard(request_t *request)
Discard the bottom most frame on the request's stack.
Definition: interpret.c:1718
#define UNLANG_SUB_FRAME
Definition: interpret.h:36
void fr_isaac_init(fr_randctx *ctx, int flag)
Definition: isaac.c:85
int eap_base_init(void)
Initialise the lib eap base library.
Definition: base.c:466
void eap_base_free(void)
De-init the lib eap base library.
Definition: base.c:489
eap_packet_raw_t * eap_packet_from_vp(TALLOC_CTX *ctx, fr_pair_list_t *vps)
Definition: base.c:279
eap_session_t * eap_session_continue(void const *instance, eap_packet_raw_t **eap_packet_p, request_t *request)
Ingest an eap_packet into a thawed or newly allocated session.
Definition: session.c:307
void eap_session_freeze(eap_session_t **eap_session)
Freeze an eap_session_t so that it can continue later.
Definition: session.c:173
void eap_session_destroy(eap_session_t **eap_session)
'destroy' an EAP session and disassociate it from the current request
Definition: session.c:148
eap_session_t * eap_session_thaw(request_t *request)
Thaw an eap_session_t so it can be continued.
Definition: session.c:205
char * identity
NAI (User-Name) from EAP-Identity.
Definition: session.h:55
void * opaque
Opaque data used by EAP methods.
Definition: session.h:62
request_t * subrequest
Current subrequest being executed.
Definition: session.h:45
eap_type_t type
EAP method number.
Definition: session.h:49
module_method_t process
Callback that should be used to process the next round.
Definition: session.h:64
request_t * request
Current request.
Definition: session.h:51
rlm_rcode_t submodule_rcode
Result of last submodule call.
Definition: session.h:46
eap_round_t * this_round
The EAP response we're processing, and the EAP request we're building.
Definition: session.h:59
eap_round_t * prev_round
Previous response/request pair.
Definition: session.h:57
int rounds
How many roundtrips have occurred this session.
Definition: session.h:66
Tracks the progress of a single session of any EAP method.
Definition: session.h:40
#define RDEBUG3(fmt,...)
Definition: log.h:343
#define RWARN(fmt,...)
Definition: log.h:297
#define RERROR(fmt,...)
Definition: log.h:298
#define RPERROR(fmt,...)
Definition: log.h:302
#define REMARKER(_str, _marker_idx, _marker,...)
Output string with error marker, showing where format error occurred.
Definition: log.h:498
#define REDEBUG2(fmt,...)
Definition: log.h:372
talloc_free(reap)
@ FR_TYPE_STRING
String of printable characters.
Definition: merged_model.c:83
@ FR_TYPE_UINT32
32 Bit unsigned integer.
Definition: merged_model.c:99
@ FR_TYPE_VOID
User data.
Definition: merged_model.c:127
@ FR_TYPE_OCTETS
Raw octets.
Definition: merged_model.c:84
long int ssize_t
Definition: merged_model.c:24
void * memrchr(void const *s, int c, size_t n)
GNU libc extension on some platforms.
Definition: missing.c:83
#define MODULE_INST_CTX(_dl_inst)
Wrapper to create a module_inst_ctx_t as a compound literal.
Definition: module_ctx.h:153
void * rctx
Resume ctx that a module previously set.
Definition: module_ctx.h:45
dl_module_inst_t const * inst
Dynamic loader API handle for the module.
Definition: module_ctx.h:52
dl_module_inst_t const * inst
Dynamic loader API handle for the module.
Definition: module_ctx.h:42
Temporary structure to hold arguments for module calls.
Definition: module_ctx.h:41
Temporary structure to hold arguments for instantiation calls.
Definition: module_ctx.h:51
Specifies a module method identifier.
Definition: module_method.c:36
int module_rlm_submodule_parse(TALLOC_CTX *ctx, void *out, void *parent, CONF_ITEM *ci, conf_parser_t const *rule)
Generic conf_parser_t func for loading drivers.
Definition: module_rlm.c:913
bool module_rlm_section_type_set(request_t *request, fr_dict_attr_t const *type_da, fr_dict_enum_value_t const *enumv)
Set the next section type if it's not already set.
Definition: module_rlm.c:397
module_t common
Common fields presented by all modules.
Definition: module_rlm.h:37
#define RADIUS_AUTH_VECTOR_LENGTH
Definition: net.h:89
fr_pair_t * fr_pair_find_by_da(fr_pair_list_t const *list, fr_pair_t const *prev, fr_dict_attr_t const *da)
Find the first pair with a matching da.
Definition: pair.c:688
int fr_pair_list_copy(TALLOC_CTX *ctx, fr_pair_list_t *to, fr_pair_list_t const *from)
Duplicate a list of pairs.
Definition: pair.c:2316
int fr_pair_append(fr_pair_list_t *list, fr_pair_t *to_add)
Add a VP to the end of the list.
Definition: pair.c:1340
fr_pair_t * fr_pair_find_by_da_idx(fr_pair_list_t const *list, fr_dict_attr_t const *da, unsigned int idx)
Find a pair with a matching da at a given index.
Definition: pair.c:736
fr_pair_t * fr_pair_copy(TALLOC_CTX *ctx, fr_pair_t const *vp)
Copy a single valuepair.
Definition: pair.c:484
int fr_pair_value_mem_alloc(fr_pair_t *vp, uint8_t **out, size_t size, bool tainted)
Pre-allocate a memory buffer for a "octets" type value pair.
Definition: pair.c:2927
char * fr_asprint(TALLOC_CTX *ctx, char const *in, ssize_t inlen, char quote)
Escape string that may contain binary data, and write it to a new buffer.
Definition: print.c:430
static const conf_parser_t config[]
Definition: base.c:188
#define REDEBUG(fmt,...)
Definition: radclient.h:52
#define RDEBUG2(fmt,...)
Definition: radclient.h:54
#define WARN(fmt,...)
Definition: radclient.h:47
static rs_t * conf
Definition: radsniff.c:53
uint32_t fr_rand(void)
Return a 32-bit random number.
Definition: rand.c:106
#define RETURN_MODULE_REJECT
Definition: rcode.h:55
#define RETURN_MODULE_NOOP
Definition: rcode.h:62
#define RETURN_MODULE_RCODE(_rcode)
Definition: rcode.h:64
#define RETURN_MODULE_INVALID
Definition: rcode.h:59
#define RETURN_MODULE_OK
Definition: rcode.h:57
#define RETURN_MODULE_UPDATED
Definition: rcode.h:63
rlm_rcode_t
Return codes indicating the result of the module call.
Definition: rcode.h:40
@ RLM_MODULE_INVALID
The module considers the request invalid.
Definition: rcode.h:45
@ RLM_MODULE_OK
The module is OK, continue.
Definition: rcode.h:43
@ RLM_MODULE_FAIL
Module failed, don't reply.
Definition: rcode.h:42
@ RLM_MODULE_DISALLOW
Reject the request (user is locked out).
Definition: rcode.h:46
@ RLM_MODULE_REJECT
Immediately reject the request.
Definition: rcode.h:41
@ RLM_MODULE_UPDATED
OK (pairs modified).
Definition: rcode.h:49
@ RLM_MODULE_NOOP
Module succeeded without doing anything.
Definition: rcode.h:48
@ RLM_MODULE_HANDLED
The module handled the request, so stop.
Definition: rcode.h:44
fr_dict_autoload_t rlm_eap_dict[]
Definition: rlm_eap.c:86
static int mod_load(void)
Definition: rlm_eap.c:1184
static unlang_action_t eap_method_select(rlm_rcode_t *p_result, module_ctx_t const *mctx, eap_session_t *eap_session)
Select the correct callback based on a response.
Definition: rlm_eap.c:573
static fr_table_num_sorted_t const require_identity_realm_table[]
Definition: rlm_eap.c:56
static ssize_t eap_identity_is_nai_with_realm(char const *identity)
Basic tests to determine if an identity is a valid NAI.
Definition: rlm_eap.c:521
char const * caller
Original caller.
Definition: rlm_eap.c:45
static fr_dict_attr_t const * attr_state
Definition: rlm_eap.c:99
static fr_dict_attr_t const * attr_eap_identity
Definition: rlm_eap.c:94
fr_dict_attr_autoload_t rlm_eap_dict_attr[]
Definition: rlm_eap.c:104
static int submodule_parse(TALLOC_CTX *ctx, void *out, UNUSED void *parent, CONF_ITEM *ci, UNUSED conf_parser_t const *rule)
static fr_dict_attr_t const * attr_eap_message
Definition: rlm_eap.c:97
static fr_dict_attr_t const * attr_eap_type
Definition: rlm_eap.c:93
static eap_type_t eap_process_nak(module_ctx_t const *mctx, request_t *request, eap_type_t last_type, eap_type_data_t *nak)
Process NAK data from EAP peer.
Definition: rlm_eap.c:230
static void mod_authenticate_cancel(module_ctx_t const *mctx, request_t *request, UNUSED fr_signal_t action)
Cancel a call to a submodule.
Definition: rlm_eap.c:389
static fr_dict_t const * dict_freeradius
Definition: rlm_eap.c:82
eap_session_t * eap_session
The eap_session we're continuing.
Definition: rlm_eap.c:47
rlm_eap_t * inst
Instance of the rlm_eap module.
Definition: rlm_eap.c:46
module_rlm_t rlm_eap
Definition: rlm_eap.c:1202
static int eap_type_parse(UNUSED TALLOC_CTX *ctx, void *out, UNUSED void *parent, CONF_ITEM *ci, UNUSED conf_parser_t const *rule)
Convert EAP type strings to eap_type_t values.
Definition: rlm_eap.c:207
static fr_dict_t const * dict_radius
Definition: rlm_eap.c:83
static unlang_action_t mod_authenticate(rlm_rcode_t *p_result, module_ctx_t const *mctx, request_t *request)
Definition: rlm_eap.c:856
static int mod_bootstrap(module_inst_ctx_t const *mctx)
Definition: rlm_eap.c:1074
static fr_dict_attr_t const * attr_auth_type
Definition: rlm_eap.c:92
rlm_rcode_t rcode
The result of the submodule.
Definition: rlm_eap.c:48
static void mod_unload(void)
Definition: rlm_eap.c:1193
static fr_dict_attr_t const * attr_stripped_user_domain
Definition: rlm_eap.c:95
static unlang_action_t mod_authenticate_result(rlm_rcode_t *p_result, UNUSED module_ctx_t const *mctx, request_t *request, eap_session_t *eap_session, rlm_rcode_t result)
Process the result of calling a submodule.
Definition: rlm_eap.c:419
static unlang_action_t mod_authorize(rlm_rcode_t *p_result, module_ctx_t const *mctx, request_t *request)
Definition: rlm_eap.c:921
static fr_dict_attr_t const * attr_user_name
Definition: rlm_eap.c:100
static size_t require_identity_realm_table_len
Definition: rlm_eap.c:61
static const conf_parser_t module_config[]
Definition: rlm_eap.c:63
static unlang_action_t mod_authenticate_result_async(rlm_rcode_t *p_result, module_ctx_t const *mctx, request_t *request)
Call mod_authenticate_result asynchronously from the unlang interpreter.
Definition: rlm_eap.c:504
static int mod_instantiate(module_inst_ctx_t const *mctx)
Definition: rlm_eap.c:1053
static fr_dict_attr_t const * attr_message_authenticator
Definition: rlm_eap.c:98
static unlang_action_t mod_post_auth(rlm_rcode_t *p_result, module_ctx_t const *mctx, request_t *request)
Definition: rlm_eap.c:969
Resume context for calling a submodule.
Definition: rlm_eap.c:44
Implements the EAP framework.
@ REQUIRE_REALM_NAI
Require the EAP-Identity contains an NAI domain.
Definition: rlm_eap.h:41
@ REQUIRE_REALM_NO
Don't require that the identity is qualified.
Definition: rlm_eap.h:40
@ REQUIRE_REALM_YES
Require the EAP-Identity string contain an NAI realm or that Stripped-User-Domain is present in the r...
Definition: rlm_eap.h:38
Instance data for rlm_eap.
Definition: rlm_eap.h:47
static char const * name
static int instantiate(module_inst_ctx_t const *mctx)
Definition: rlm_rest.c:1312
username
Definition: rlm_securid.c:420
ssize_t fr_sbuff_in_sprintf(fr_sbuff_t *sbuff, char const *fmt,...)
Print using a fmt string to an sbuff.
Definition: sbuff.c:1554
#define fr_sbuff_start(_sbuff_or_marker)
#define fr_sbuff_advance(_sbuff_or_marker, _len)
#define FR_SBUFF_TALLOC_THREAD_LOCAL(_out, _init, _max)
#define MODULE_NAME_TERMINATOR
Definition: module.h:135
dl_module_inst_t * dl_inst
Structure containing the module's instance data, configuration, and dl handle.
Definition: module.h:183
Per instance data.
Definition: module.h:169
#define pair_update_reply(_attr, _da)
Return or allocate a fr_pair_t in the reply list.
Definition: pair.h:129
#define pair_append_request(_attr, _da)
Allocate and append a fr_pair_t to the request list.
Definition: pair.h:37
void fr_state_discard_child(request_t *parent, void const *unique_ptr, int unique_int)
Remove state from a child.
Definition: state.c:908
fr_signal_t
Definition: signal.h:48
return count
Definition: module.c:175
unlang_action_t unlang_module_yield(request_t *request, module_method_t resume, unlang_module_signal_t signal, fr_signal_t sigmask, void *rctx)
Yield a request back to the interpreter from within a module.
Definition: module.c:575
int unlang_module_push(rlm_rcode_t *p_result, request_t *request, module_instance_t *module_instance, module_method_t method, bool top_frame)
Push a module or submodule onto the stack for evaluation.
Definition: module.c:325
RETURN_MODULE_FAIL
if(!subtype_vp) goto fail
fr_assert(0)
MEM(pair_append_request(&vp, attr_eap_aka_sim_identity) >=0)
eap_aka_sim_process_conf_t * inst
fr_pair_value_bstrdup_buffer(vp, eap_session->identity, true)
fr_aka_sim_id_type_t type
fr_pair_t * vp
Stores an attribute, a value and various bits of other data.
Definition: pair.h:68
module_t common
Common fields provided by all modules.
Definition: submodule.h:50
module_instance_t * submodule_inst
Submodule's instance data.
Definition: submodule.h:68
#define MAX_PROVIDED_METHODS
Definition: submodule.h:28
rlm_eap_submodule_t const * submodule
Submodule's exported interface.
Definition: submodule.h:69
bool clone_parent_lists
< Namespace children should be allocated in.
Definition: submodule.h:59
eap_type_t provides[MAX_PROVIDED_METHODS]
Allow the module to register itself for more than one EAP-Method.
Definition: submodule.h:52
eap_type_identity_t type_identity
Do we recognise this identity?
Definition: submodule.h:55
Private structure to hold handles and interfaces for an EAP method.
Definition: submodule.h:67
Interface exported by EAP submodules.
Definition: submodule.h:49
request_t * unlang_subrequest_alloc(request_t *parent, fr_dict_t const *namespace)
Allocate a subrequest to run through a virtual server at some point in the future.
Definition: subrequest.c:266
int unlang_subrequest_child_push(rlm_rcode_t *out, request_t *child, unlang_subrequest_session_t const *session, bool free_child, bool top_frame)
Push a pre-existing child back onto the stack as a subrequest.
An element in a lexicographically sorted array of name to num mappings.
Definition: table.h:45
#define talloc_get_type_abort_const
Definition: talloc.h:270
static fr_slen_t parent
Definition: pair.h:844
void fr_perror(char const *fmt,...)
Print the current error to stderr with a prefix.
Definition: strerror.c:733
char const * fr_strerror(void)
Get the last library error.
Definition: strerror.c:554
#define fr_strerror_printf(_fmt,...)
Log to thread local error buffer.
Definition: strerror.h:64
int nonnull(2, 5))
static size_t char ** out
Definition: value.h:984