All Data Structures Files Functions Variables Typedefs Enumerations Enumerator Macros Groups Pages
eap.c
Go to the documentation of this file.
1 /*
2  * eap.c rfc2284 & rfc2869 implementation
3  *
4  * Version: $Id: db4cb2a34c41fcc59db448cc231727bfcdebdd08 $
5  *
6  * This program is free software; you can redistribute it and/or modify
7  * it under the terms of the GNU General Public License as published by
8  * the Free Software Foundation; either version 2 of the License, or
9  * (at your option) any later version.
10  *
11  * This program is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14  * GNU General Public License for more details.
15  *
16  * You should have received a copy of the GNU General Public License
17  * along with this program; if not, write to the Free Software
18  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
19  *
20  * Copyright 2000-2003,2006 The FreeRADIUS server project
21  * Copyright 2001 hereUare Communications, Inc. <raghud@hereuare.com>
22  * Copyright 2003 Alan DeKok <aland@freeradius.org>
23  */
24 /*
25  * EAP PACKET FORMAT
26  * --- ------ ------
27  * 0 1 2 3
28  * 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
29  * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
30  * | Code | Identifier | Length |
31  * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
32  * | Data ...
33  * +-+-+-+-+
34  *
35  *
36  * EAP Request and Response Packet Format
37  * --- ------- --- -------- ------ ------
38  * 0 1 2 3
39  * 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
40  * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
41  * | Code | Identifier | Length |
42  * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
43  * | Type | Type-Data ...
44  * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-
45  *
46  *
47  * EAP Success and Failure Packet Format
48  * --- ------- --- ------- ------ ------
49  * 0 1 2 3
50  * 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
51  * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
52  * | Code | Identifier | Length |
53  * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
54  *
55  */
56 
57 #include <freeradius-devel/modpriv.h>
58 
59 RCSID("$Id: db4cb2a34c41fcc59db448cc231727bfcdebdd08 $")
60 
61 #include "rlm_eap.h"
62 #include <ctype.h>
63 
64 static char const *eap_codes[] = {
65  "", /* 0 is invalid */
66  "Request",
67  "Response",
68  "Success",
69  "Failure"
70 };
71 
73 {
74  /*
75  * We have to check inst->type as it's only allocated
76  * if we loaded the eap method.
77  */
78  if (inst->type && inst->type->detach) (inst->type->detach)(inst->instance);
79 
80 #ifndef NDEBUG
81  /*
82  * Don't dlclose() modules if we're doing memory
83  * debugging. This removes the symbols needed by
84  * valgrind.
85  */
87 #endif
88  if (inst->handle) dlclose(inst->handle);
89 
90  return 0;
91 }
92 
93 /** Load required EAP sub-modules (methods)
94  *
95  */
97 {
98  eap_module_t *method;
99  char *mod_name, *p;
100 
101  /* Make room for the EAP-Type */
102  *m_inst = method = talloc_zero(cs, eap_module_t);
103  if (!inst) return -1;
104 
105  talloc_set_destructor(method, _eap_module_free);
106 
107  /* fill in the structure */
108  method->cs = cs;
109  method->name = eap_type2name(num);
110 
111  /*
112  * The name of the module were trying to load
113  */
114  mod_name = talloc_typed_asprintf(method, "rlm_eap_%s", method->name);
115 
116  /*
117  * dlopen is case sensitive
118  */
119  p = mod_name;
120  while (*p) {
121  *p = tolower(*p);
122  p++;
123  }
124 
125 #if defined(HAVE_DLFCN_H) && defined(RTLD_SELF)
126  method->type = dlsym(RTLD_SELF, mod_name);
127  if (method->type) goto open_self;
128 #endif
129 
130  /*
131  * Link the loaded EAP-Type
132  */
133  method->handle = lt_dlopenext(mod_name);
134  if (!method->handle) {
135  ERROR("rlm_eap (%s): Failed to link %s: %s", inst->xlat_name, mod_name, fr_strerror());
136 
137  return -1;
138  }
139 
140  method->type = dlsym(method->handle, mod_name);
141  if (!method->type) {
142  ERROR("rlm_eap (%s): Failed linking to structure in %s: %s", inst->xlat_name,
143  method->name, dlerror());
144 
145  return -1;
146  }
147 
148 #if !defined(WITH_LIBLTDL) && defined(HAVE_DLFCN_H) && defined(RTLD_SELF)
149 open_self:
150 #endif
151  cf_log_module(cs, "Linked to sub-module %s", mod_name);
152 
153  /*
154  * Call the attach num in the EAP num module
155  */
156  if ((method->type->instantiate) && ((method->type->instantiate)(method->cs, &(method->instance)) < 0)) {
157  ERROR("rlm_eap (%s): Failed to initialise %s", inst->xlat_name, mod_name);
158 
159  if (method->instance) {
160  (void) talloc_steal(method, method->instance);
161  }
162 
163  return -1;
164  }
165 
166  if (method->instance) {
167  (void) talloc_steal(method, method->instance);
168  }
169 
170  return 0;
171 }
172 
173 /*
174  * Call the appropriate handle with the right eap_method.
175  */
176 static int eap_module_call(eap_module_t *module, eap_session_t *eap_session)
177 {
178  int rcode = 1;
179  REQUEST *request = eap_session->request;
180 
181  char const *caller = request->module;
182 
183  rad_assert(module != NULL);
184 
185  RDEBUG2("Calling submodule %s to process data", module->type->name);
186 
187  request->module = module->type->name;
188 
189  rcode = eap_session->process(module->instance, eap_session);
190 
191  request->module = caller;
192  return rcode;
193 }
194 
195 /** Process NAK data from EAP peer
196  *
197  */
199  eap_type_t type,
200  eap_type_data_t *nak)
201 {
202  unsigned int i;
203  VALUE_PAIR *vp;
204  eap_type_t method = PW_EAP_INVALID;
205 
206  /*
207  * The NAK data is the preferred EAP type(s) of
208  * the client.
209  *
210  * RFC 3748 says to list one or more proposed
211  * alternative types, one per octet, or to use
212  * 0 for no alternative.
213  */
214  if (!nak->data) {
215  REDEBUG("Peer sent empty (invalid) NAK. "
216  "Can't select method to continue with");
217 
218  return PW_EAP_INVALID;
219  }
220 
221  /*
222  * Pick one type out of the one they asked for,
223  * as they may have asked for many.
224  */
225  vp = fr_pair_find_by_num(request->config, 0, PW_EAP_TYPE, TAG_ANY);
226  for (i = 0; i < nak->length; i++) {
227  /*
228  * Type 0 is valid, and means there are no
229  * common choices.
230  */
231  if (nak->data[i] == 0) {
232  RDEBUG("Peer NAK'd indicating it is not willing to "
233  "continue ");
234 
235  return PW_EAP_INVALID;
236  }
237 
238  /*
239  * It is invalid to request identity,
240  * notification & nak in nak.
241  */
242  if (nak->data[i] < PW_EAP_MD5) {
243  REDEBUG("Peer NAK'd asking for bad "
244  "type %s (%d)",
245  eap_type2name(nak->data[i]),
246  nak->data[i]);
247 
248  return PW_EAP_INVALID;
249  }
250 
251  if ((nak->data[i] >= PW_EAP_MAX_TYPES) ||
252  !inst->methods[nak->data[i]]) {
253  RDEBUG2("Peer NAK'd asking for "
254  "unsupported type %s (%d), skipping...",
255  eap_type2name(nak->data[i]),
256  nak->data[i]);
257 
258  continue;
259  }
260 
261  /*
262  * Prevent a firestorm if the client is confused.
263  */
264  if (type == nak->data[i]) {
265  RDEBUG2("Peer NAK'd our request for "
266  "%s (%d) with a request for "
267  "%s (%d), skipping...",
268  eap_type2name(nak->data[i]),
269  nak->data[i],
270  eap_type2name(nak->data[i]),
271  nak->data[i]);
272 
273  continue;
274  }
275 
276  /*
277  * Enforce per-user configuration of EAP
278  * types.
279  */
280  if (vp && (vp->vp_integer != nak->data[i])) {
281  RDEBUG2("Peer wants %s (%d), while we "
282  "require %s (%d), skipping",
283  eap_type2name(nak->data[i]),
284  nak->data[i],
285  eap_type2name(vp->vp_integer),
286  vp->vp_integer);
287 
288  continue;
289  }
290 
291  RDEBUG("Found mutually acceptable type %s (%d)",
292  eap_type2name(nak->data[i]), nak->data[i]);
293 
294  method = nak->data[i];
295 
296  break;
297  }
298 
299  if (method == PW_EAP_INVALID) {
300  REDEBUG("No mutually acceptable types found");
301  }
302 
303  return method;
304 }
305 
306 /** Select the correct callback based on a response
307  *
308  * Based on the EAP response from the supplicant, call the appropriate
309  * method callback.
310  *
311  * Default to the configured EAP-Type for all Unsupported EAP-Types.
312  *
313  * @param inst Configuration data for this instance of rlm_eap.
314  * @param eap_session State data that persists over multiple rounds of EAP.
315  * @return a status code.
316  */
318 {
319  eap_type_data_t *type = &eap_session->this_round->response->type;
320  REQUEST *request = eap_session->request;
321 
322  eap_type_t next = inst->default_method;
323  VALUE_PAIR *vp;
324 
325  /*
326  * Don't trust anyone.
327  */
328  if ((type->num == 0) || (type->num >= PW_EAP_MAX_TYPES)) {
329  REDEBUG("Peer sent EAP method number %d, which is outside known range", type->num);
330 
331  return EAP_INVALID;
332  }
333 
334  /*
335  * Multiple levels of TLS nesting are invalid. But if
336  * the parent has a home_server defined, then this
337  * request is being processed through a virtual
338  * server... so that's OK.
339  *
340  * i.e. we're inside an EAP tunnel, which means we have a
341  * parent. If the outer session exists, and doesn't have
342  * a home server, then it's multiple layers of tunneling.
343  */
344  if (eap_session->request->parent &&
345  eap_session->request->parent->parent &&
346  !eap_session->request->parent->parent->home_server) {
347  RERROR("Multiple levels of TLS nesting are invalid");
348 
349  return EAP_INVALID;
350  }
351 
352  RDEBUG2("Peer sent packet with method EAP %s (%d)", eap_type2name(type->num), type->num);
353 
354  /*
355  * Figure out what to do.
356  */
357  switch (type->num) {
358  case PW_EAP_IDENTITY:
359  /*
360  * Allow per-user configuration of EAP types.
361  */
362  vp = fr_pair_find_by_num(eap_session->request->config, 0, PW_EAP_TYPE, TAG_ANY);
363  if (vp) next = vp->vp_integer;
364 
365  /*
366  * Ensure it's valid.
367  */
368  if ((next < PW_EAP_MD5) || (next >= PW_EAP_MAX_TYPES) || (!inst->methods[next])) {
369  REDEBUG2("Tried to start unsupported method (%d)", next);
370 
371  return EAP_INVALID;
372  }
373 
374  do_initiate:
375  /*
376  * If any of these fail, we messed badly somewhere
377  */
378  rad_assert(next >= PW_EAP_MD5);
380  rad_assert(inst->methods[next]);
381 
382  eap_session->process = inst->methods[next]->type->session_init;
383  eap_session->type = next;
384 
385  if (eap_module_call(inst->methods[next], eap_session) == 0) {
386  REDEBUG2("Failed starting EAP %s (%d) session. EAP sub-module failed",
387  eap_type2name(next), next);
388 
389  return EAP_INVALID;
390  }
391  break;
392 
393  case PW_EAP_NAK:
394  /*
395  * Delete old data, if necessary. If we called a method
396  * before, and it initialized itself, we need to free
397  * the memory it alloced.
398  */
399  TALLOC_FREE(eap_session->opaque);
400  next = eap_process_nak(inst, eap_session->request, eap_session->type, type);
401 
402  /*
403  * We probably want to return 'fail' here...
404  */
405  if (!next) return EAP_INVALID;
406 
407  goto do_initiate;
408 
409  /*
410  * Key off of the configured sub-modules.
411  */
412  default:
413  /*
414  * We haven't configured it, it doesn't exit.
415  */
416  if (!inst->methods[type->num]) {
417  REDEBUG2("Client asked for unsupported method %s (%d)",
418  eap_type2name(type->num),
419  type->num);
420 
421  return EAP_INVALID;
422  }
423 
424  eap_session->type = type->num;
425  if (eap_module_call(inst->methods[type->num], eap_session) == 0) {
426  REDEBUG2("Failed continuing EAP %s (%d) session. EAP sub-module failed",
427  eap_type2name(type->num),
428  type->num);
429 
430  return EAP_INVALID;
431  }
432  break;
433  }
434 
435  return EAP_OK;
436 }
437 
438 
439 /*
440  * compose EAP reply packet in EAP-Message attr of RADIUS.
441  *
442  * Set the RADIUS reply codes based on EAP request codes. Append
443  * any additonal VPs to RADIUS reply
444  */
446 {
447  VALUE_PAIR *vp;
449  REQUEST *request;
451  eap_packet_t *reply;
452  int rcode;
453 
454 #ifndef NDEBUG
455  eap_session = talloc_get_type_abort(eap_session, eap_session_t);
456  request = talloc_get_type_abort(eap_session->request, REQUEST);
457  eap_round = talloc_get_type_abort(eap_session->this_round, eap_round_t);
458  reply = talloc_get_type_abort(eap_round->request, eap_packet_t);
459 #else
460  request = eap_session->request;
461  eap_round = eap_session->this_round;
462  reply = eap_round->request;
463 #endif
464 
465  /*
466  * The Id for the EAP packet to the NAS wasn't set.
467  * Do so now.
468  *
469  * LEAP requires the Id to be incremented on EAP-Success
470  * in Stage 4, so that we can carry on the conversation
471  * where the client asks us to authenticate ourselves
472  * in stage 5.
473  */
474  if (!eap_round->set_request_id) {
475  /*
476  * Id serves to suppport request/response
477  * retransmission in the EAP layer and as such
478  * must be different for 'adjacent' packets
479  * except in case of success/failure-replies.
480  *
481  * RFC2716 (EAP-TLS) requires this to be
482  * incremented, RFC2284 only makes the above-
483  * mentioned restriction.
484  */
485  reply->id = eap_session->this_round->response->id;
486 
487  switch (reply->code) {
488  /*
489  * The Id is a simple "ack" for success
490  * and failure.
491  *
492  * RFC 3748 section 4.2 says
493  *
494  * ... The Identifier field MUST match
495  * the Identifier field of the Response
496  * packet that it is sent in response
497  * to.
498  */
499  case PW_EAP_SUCCESS:
500  case PW_EAP_FAILURE:
501  break;
502 
503  /*
504  * We've sent a response to their
505  * request, the Id is incremented.
506  */
507  default:
508  ++reply->id;
509  }
510  }
511 
512  /*
513  * For Request & Response packets, set the EAP sub-type,
514  * if the EAP sub-module didn't already set it.
515  *
516  * This allows the TLS module to be "morphic", and means
517  * that the TTLS and PEAP modules can call it to do most
518  * of their dirty work.
519  */
520  if (((eap_round->request->code == PW_EAP_REQUEST) ||
521  (eap_round->request->code == PW_EAP_RESPONSE)) &&
522  (eap_round->request->type.num == 0)) {
523  rad_assert(eap_session->type >= PW_EAP_MD5);
524  rad_assert(eap_session->type < PW_EAP_MAX_TYPES);
525 
526  eap_round->request->type.num = eap_session->type;
527  }
528 
529  if (eap_wireformat(reply) == EAP_INVALID) {
530  return RLM_MODULE_INVALID;
531  }
532  eap_packet = (eap_packet_raw_t *)reply->packet;
533 
534  vp = radius_pair_create(request->reply, &request->reply->vps, PW_EAP_MESSAGE, 0);
535  if (!vp) return RLM_MODULE_INVALID;
536 
537  vp->vp_length = eap_packet->length[0] * 256 + eap_packet->length[1];
538  vp->vp_octets = talloc_steal(vp, reply->packet);
539  reply->packet = NULL;
540 
541  /*
542  * EAP-Message is always associated with
543  * Message-Authenticator but not vice-versa.
544  *
545  * Don't add a Message-Authenticator if it's already
546  * there.
547  */
548  vp = fr_pair_find_by_num(request->reply->vps, 0, PW_MESSAGE_AUTHENTICATOR, TAG_ANY);
549  if (!vp) {
550  vp = fr_pair_afrom_num(request->reply, 0, PW_MESSAGE_AUTHENTICATOR);
551  vp->vp_length = AUTH_VECTOR_LEN;
552  vp->vp_octets = talloc_zero_array(vp, uint8_t, vp->vp_length);
553  fr_pair_add(&(request->reply->vps), vp);
554  }
555 
556  /* Set request reply code, but only if it's not already set. */
557  rcode = RLM_MODULE_OK;
558  if (!request->reply->code) switch (reply->code) {
559  case PW_EAP_RESPONSE:
560  request->reply->code = PW_CODE_ACCESS_ACCEPT;
561  rcode = RLM_MODULE_HANDLED; /* leap weirdness */
562  break;
563 
564  case PW_EAP_SUCCESS:
565  request->reply->code = PW_CODE_ACCESS_ACCEPT;
566  rcode = RLM_MODULE_OK;
567  break;
568 
569  case PW_EAP_FAILURE:
570  request->reply->code = PW_CODE_ACCESS_REJECT;
571  rcode = RLM_MODULE_REJECT;
572  break;
573 
574  case PW_EAP_REQUEST:
575  request->reply->code = PW_CODE_ACCESS_CHALLENGE;
576  rcode = RLM_MODULE_HANDLED;
577  break;
578 
579  default:
580  /*
581  * When we're pulling MS-CHAPv2 out of EAP-MS-CHAPv2,
582  * we do so WITHOUT setting a reply code, as the
583  * request is being proxied.
584  */
585  if (request->options & RAD_REQUEST_OPTION_PROXY_EAP) {
586  return RLM_MODULE_HANDLED;
587  }
588 
589  /* Should never enter here */
590  REDEBUG("Reply code %d is unknown, rejecting the request", reply->code);
591  request->reply->code = PW_CODE_ACCESS_REJECT;
592  reply->code = PW_EAP_FAILURE;
593  rcode = RLM_MODULE_REJECT;
594  break;
595  }
596 
597  RDEBUG2("Sending EAP %s (code %i) ID %d length %i",
598  eap_codes[eap_packet->code], eap_packet->code, reply->id,
599  eap_packet->length[0] * 256 + eap_packet->length[1]);
600 
601  return rcode;
602 }
603 
604 /*
605  * Radius criteria, EAP-Message is invalid without Message-Authenticator
606  * For EAP_START, send Access-Challenge with EAP Identity request.
607  */
609 {
610  VALUE_PAIR *vp, *proxy;
611  VALUE_PAIR *eap_msg;
612 
613  eap_msg = fr_pair_find_by_num(request->packet->vps, 0, PW_EAP_MESSAGE, TAG_ANY);
614  if (!eap_msg) {
615  RDEBUG2("No EAP-Message, not doing EAP");
616  return EAP_NOOP;
617  }
618 
619  /*
620  * Look for EAP-Type = None (FreeRADIUS specific attribute)
621  * this allows you to NOT do EAP for some users.
622  */
623  vp = fr_pair_find_by_num(request->packet->vps, 0, PW_EAP_TYPE, TAG_ANY);
624  if (vp && vp->vp_integer == 0) {
625  RDEBUG2("Found EAP-Message, but EAP-Type = None, so we're not doing EAP");
626  return EAP_NOOP;
627  }
628 
629  /*
630  * http://www.freeradius.org/rfc/rfc2869.html#EAP-Message
631  *
632  * Checks for Message-Authenticator are handled by fr_radius_recv().
633  */
634 
635  /*
636  * Check for a Proxy-To-Realm. Don't get excited over LOCAL
637  * realms (sigh).
638  */
639  proxy = fr_pair_find_by_num(request->config, 0, PW_PROXY_TO_REALM, TAG_ANY);
640  if (proxy) {
641  REALM *realm;
642 
643  /*
644  * If it's a LOCAL realm, then we're not proxying
645  * to it.
646  */
647  realm = realm_find(proxy->vp_strvalue);
648  if (!realm || (realm && (!realm->auth_pool))) {
649  proxy = NULL;
650  }
651  }
652 
653  /*
654  * Check the length before de-referencing the contents.
655  *
656  * Lengths of zero are required by the RFC for EAP-Start,
657  * but we've never seen them in practice.
658  *
659  * Lengths of two are what we see in practice as
660  * EAP-Starts.
661  */
662  if ((eap_msg->vp_length == 0) || (eap_msg->vp_length == 2)) {
663  uint8_t *p;
664 
665  /*
666  * It's a valid EAP-Start, but the request
667  * was marked as being proxied. So we don't
668  * do EAP, as the home server will do it.
669  */
670  if (proxy) {
671  do_proxy:
672  RDEBUG2("Request is supposed to be proxied to "
673  "Realm %s. Not doing EAP.", proxy->vp_strvalue);
674  return EAP_NOOP;
675  }
676 
677  RDEBUG2("Got EAP_START message");
678  vp = fr_pair_afrom_num(request->reply, 0, PW_EAP_MESSAGE);
679  if (!vp) return EAP_FAIL;
680  fr_pair_add(&request->reply->vps, vp);
681 
682  /*
683  * Manually create an EAP Identity request
684  */
685  p = talloc_array(vp, uint8_t, 5);
686  p[0] = PW_EAP_REQUEST;
687  p[1] = 0; /* ID */
688  p[2] = 0;
689  p[3] = 5; /* length */
690  p[4] = PW_EAP_IDENTITY;
691  fr_pair_value_memsteal(vp, p);
692 
693  return EAP_FOUND;
694  } /* end of handling EAP-Start */
695 
696  /*
697  * Supplicants don't usually send EAP-Failures to the
698  * server, but they're not forbidden from doing so.
699  * This behaviour was observed with a Spirent Avalanche test server.
700  */
701  if ((eap_msg->vp_length == EAP_HEADER_LEN) && (eap_msg->vp_octets[0] == PW_EAP_FAILURE)) {
702  REDEBUG("Peer sent EAP %s (code %i) ID %d length %zu",
703  eap_codes[eap_msg->vp_octets[0]],
704  eap_msg->vp_octets[0],
705  eap_msg->vp_octets[1],
706  eap_msg->vp_length);
707  return EAP_FAIL;
708  /*
709  * The EAP packet header is 4 bytes, plus one byte of
710  * EAP sub-type. Short packets are discarded, unless
711  * we're proxying.
712  */
713  } else if (eap_msg->vp_length < (EAP_HEADER_LEN + 1)) {
714  if (proxy) goto do_proxy;
715 
716  RDEBUG2("Ignoring EAP-Message which is too short to be meaningful");
717  return EAP_FAIL;
718  }
719 
720  /*
721  * Create an EAP-Type containing the EAP-type
722  * from the packet.
723  */
724  vp = fr_pair_afrom_num(request->packet, 0, PW_EAP_TYPE);
725  if (vp) {
726  vp->vp_integer = eap_msg->vp_octets[4];
727  fr_pair_add(&(request->packet->vps), vp);
728  }
729 
730  /*
731  * If the request was marked to be proxied, do it now.
732  * This is done after checking for a valid length
733  * (which may not be good), and after adding the EAP-Type
734  * attribute. This lets other modules selectively cancel
735  * proxying based on EAP-Type.
736  */
737  if (proxy) goto do_proxy;
738 
739  /*
740  * From now on, we're supposed to be handling the
741  * EAP packet. We better understand it...
742  */
743 
744  /*
745  * We're allowed only a few codes. Request, Response,
746  * Success, or Failure.
747  */
748  if ((eap_msg->vp_octets[0] == 0) ||
749  (eap_msg->vp_octets[0] >= PW_EAP_MAX_CODES)) {
750  RDEBUG2("Peer sent EAP packet with unknown code %i", eap_msg->vp_octets[0]);
751  } else {
752  RDEBUG2("Peer sent EAP %s (code %i) ID %d length %zu",
753  eap_codes[eap_msg->vp_octets[0]],
754  eap_msg->vp_octets[0],
755  eap_msg->vp_octets[1],
756  eap_msg->vp_length);
757  }
758 
759  /*
760  * We handle request and responses. The only other defined
761  * codes are success and fail. The client SHOULD NOT be
762  * sending success/fail packets to us, as it doesn't make
763  * sense.
764  */
765  if ((eap_msg->vp_octets[0] != PW_EAP_REQUEST) &&
766  (eap_msg->vp_octets[0] != PW_EAP_RESPONSE)) {
767  RDEBUG2("Ignoring EAP packet which we don't know how to handle");
768  return EAP_FAIL;
769  }
770 
771  /*
772  * We've been told to ignore unknown EAP types, AND it's
773  * an unknown type. Return "NOOP", which will cause the
774  * mod_authorize() to return NOOP.
775  *
776  * EAP-Identity, Notification, and NAK are all handled
777  * internally, so they never have eap_sessions.
778  */
779  if ((eap_msg->vp_octets[4] >= PW_EAP_MD5) &&
780  inst->ignore_unknown_types &&
781  ((eap_msg->vp_octets[4] == 0) ||
782  (eap_msg->vp_octets[4] >= PW_EAP_MAX_TYPES) ||
783  (!inst->methods[eap_msg->vp_octets[4]]))) {
784  RDEBUG2("Ignoring Unknown EAP type");
785  return EAP_NOOP;
786  }
787 
788  /*
789  * They're NAKing the EAP type we wanted to use, and
790  * asking for one which we don't support.
791  *
792  * NAK is code + id + length1 + length + NAK
793  * + requested EAP type(s).
794  *
795  * We know at this point that we can't handle the
796  * request. We could either return an EAP-Fail here, but
797  * it's not too critical.
798  *
799  * By returning "noop", we can ensure that authorize()
800  * returns NOOP, and another module may choose to proxy
801  * the request.
802  */
803  if ((eap_msg->vp_octets[4] == PW_EAP_NAK) &&
804  (eap_msg->vp_length >= (EAP_HEADER_LEN + 2)) &&
805  inst->ignore_unknown_types &&
806  ((eap_msg->vp_octets[5] == 0) ||
807  (eap_msg->vp_octets[5] >= PW_EAP_MAX_TYPES) ||
808  (!inst->methods[eap_msg->vp_octets[5]]))) {
809  RDEBUG2("Ignoring NAK with request for unknown EAP type");
810  return EAP_NOOP;
811  }
812 
813  if ((eap_msg->vp_octets[4] == PW_EAP_TTLS) ||
814  (eap_msg->vp_octets[4] == PW_EAP_PEAP)) {
815  RDEBUG2("Continuing tunnel setup");
816  return EAP_OK;
817  }
818  /*
819  * We return ok in response to EAP identity
820  * This means we can write:
821  *
822  * eap {
823  * ok = return
824  * }
825  * ldap
826  * sql
827  *
828  * ...in the inner-tunnel, to avoid expensive and unnecessary SQL/LDAP lookups
829  */
830  if (eap_msg->vp_octets[4] == PW_EAP_IDENTITY) {
831  RDEBUG2("Peer sent EAP-Identity. Returning 'ok' so we can short-circuit the rest of authorize");
832  return EAP_OK;
833  }
834 
835  /*
836  * Later EAP messages are longer than the 'start'
837  * message, so if everything is OK, this function returns
838  * 'no start found', so that the rest of the EAP code can
839  * use the State attribute to match this EAP-Message to
840  * an ongoing conversation.
841  */
842  RDEBUG2("Continuing on-going EAP conversation");
843 
844  return EAP_NOTFOUND;
845 }
846 
847 /*
848  * compose EAP FAILURE packet in EAP-Message
849  */
850 void eap_fail(eap_session_t *eap_session)
851 {
852  /*
853  * Delete any previous replies.
854  */
855  fr_pair_delete_by_num(&eap_session->request->reply->vps, 0, PW_EAP_MESSAGE, TAG_ANY);
856  fr_pair_delete_by_num(&eap_session->request->reply->vps, 0, PW_STATE, TAG_ANY);
857 
858  talloc_free(eap_session->this_round->request);
859  eap_session->this_round->request = talloc_zero(eap_session->this_round, eap_packet_t);
860  eap_session->this_round->request->code = PW_EAP_FAILURE;
861  eap_session->finished = true;
862  eap_compose(eap_session);
863 }
864 
865 /*
866  * compose EAP SUCCESS packet in EAP-Message
867  */
868 void eap_success(eap_session_t *eap_session)
869 {
870  eap_session->this_round->request->code = PW_EAP_SUCCESS;
871  eap_session->finished = true;
872  eap_compose(eap_session);
873 }
874 
875 /*
876  * Basic EAP packet verfications & validations
877  */
878 static int eap_validation(REQUEST *request, eap_packet_raw_t **eap_packet_p)
879 {
880  uint16_t len;
881  eap_packet_raw_t *eap_packet = *eap_packet_p;
882 
883  memcpy(&len, eap_packet->length, sizeof(uint16_t));
884  len = ntohs(len);
885 
886  /*
887  * High level EAP packet checks
888  */
889  if ((len <= EAP_HEADER_LEN) ||
890  ((eap_packet->code != PW_EAP_RESPONSE) &&
891  (eap_packet->code != PW_EAP_REQUEST))) {
892  RAUTH("Badly formatted EAP Message: Ignoring the packet");
893  return EAP_INVALID;
894  }
895 
896  if ((eap_packet->data[0] <= 0) ||
897  (eap_packet->data[0] >= PW_EAP_MAX_TYPES)) {
898  /*
899  * Handle expanded types by smashing them to
900  * normal types.
901  */
902  if (eap_packet->data[0] == PW_EAP_EXPANDED_TYPE) {
903  uint8_t *p, *q;
904 
905  if (len <= (EAP_HEADER_LEN + 1 + 3 + 4)) {
906  RAUTH("Expanded EAP type is too short: ignoring the packet");
907  return EAP_INVALID;
908  }
909 
910  if ((eap_packet->data[1] != 0) ||
911  (eap_packet->data[2] != 0) ||
912  (eap_packet->data[3] != 0)) {
913  RAUTH("Expanded EAP type has unknown Vendor-ID: ignoring the packet");
914  return EAP_INVALID;
915  }
916 
917  if ((eap_packet->data[4] != 0) ||
918  (eap_packet->data[5] != 0) ||
919  (eap_packet->data[6] != 0)) {
920  RAUTH("Expanded EAP type has unknown Vendor-Type: ignoring the packet");
921  return EAP_INVALID;
922  }
923 
924  if ((eap_packet->data[7] == 0) ||
925  (eap_packet->data[7] >= PW_EAP_MAX_TYPES)) {
926  RAUTH("Unsupported Expanded EAP type %u: ignoring the packet", eap_packet->data[7]);
927  return EAP_INVALID;
928  }
929 
930  if (eap_packet->data[7] == PW_EAP_NAK) {
931  RAUTH("Unsupported Expanded EAP-NAK: ignoring the packet");
932  return EAP_INVALID;
933  }
934 
935  /*
936  * Re-write the EAP packet to NOT have the expanded type.
937  */
938  q = (uint8_t *) eap_packet;
939  memmove(q + EAP_HEADER_LEN, q + EAP_HEADER_LEN + 7, len - 7 - EAP_HEADER_LEN);
940 
941  p = talloc_realloc(talloc_parent(eap_packet), eap_packet, uint8_t, len - 7);
942  if (!p) {
943  RAUTH("Unsupported EAP type %u: ignoring the packet", eap_packet->data[0]);
944  return EAP_INVALID;
945  }
946 
947  len -= 7;
948  p[2] = (len >> 8) & 0xff;
949  p[3] = len & 0xff;
950 
951  *eap_packet_p = (eap_packet_raw_t *) p;
952  RWARN("Converting Expanded EAP to normal EAP.");
953  RWARN("Unnecessary use of Expanded EAP types is not recommened.");
954 
955  return EAP_VALID;
956  }
957 
958  RAUTH("Unsupported EAP type %u: ignoring the packet", eap_packet->data[0]);
959  return EAP_INVALID;
960  }
961 
962  /* we don't expect notification, but we send it */
963  if (eap_packet->data[0] == PW_EAP_NOTIFICATION) {
964  RAUTH("Got NOTIFICATION, "
965  "Ignoring the packet");
966  return EAP_INVALID;
967  }
968 
969  return EAP_VALID;
970 }
971 
972 
973 /*
974  * Get the user Identity only from EAP-Identity packets
975  */
976 static char *eap_identity(REQUEST *request, eap_session_t *eap_session, eap_packet_raw_t *eap_packet)
977 {
978  int size;
979  uint16_t len;
980  char *identity;
981 
982  if ((!eap_packet) ||
983  (eap_packet->code != PW_EAP_RESPONSE) ||
984  (eap_packet->data[0] != PW_EAP_IDENTITY)) {
985  return NULL;
986  }
987 
988  memcpy(&len, eap_packet->length, sizeof(uint16_t));
989  len = ntohs(len);
990 
991  if ((len <= 5) || (eap_packet->data[1] == 0x00)) {
992  RDEBUG("EAP-Identity Unknown");
993  return NULL;
994  }
995 
996  if (len > 1024) {
997  RDEBUG("EAP-Identity too long");
998  return NULL;
999  }
1000 
1001  size = len - 5;
1002  identity = talloc_array(eap_session, char, size + 1);
1003  memcpy(identity, &eap_packet->data[1], size);
1004  identity[size] = '\0';
1005 
1006  return identity;
1007 }
1008 
1009 
1010 /*
1011  * Create our Request-Response data structure with the eap packet
1012  */
1013 static eap_round_t *eap_buildds(eap_session_t *eap_session, eap_packet_raw_t **eap_packet_p)
1014 {
1015  eap_round_t *eap_round = NULL;
1016  eap_packet_raw_t *eap_packet = *eap_packet_p;
1017  int typelen;
1018  uint16_t len;
1019 
1020  eap_round = eap_round_alloc(eap_session);
1021  if (eap_round == NULL) return NULL;
1022 
1023  eap_round->response->packet = (uint8_t *)eap_packet;
1024  (void) talloc_steal(eap_round, eap_packet);
1025  eap_round->response->code = eap_packet->code;
1026  eap_round->response->id = eap_packet->id;
1027  eap_round->response->type.num = eap_packet->data[0];
1028 
1029  memcpy(&len, eap_packet->length, sizeof(uint16_t));
1030  len = ntohs(len);
1031  eap_round->response->length = len;
1032 
1033  /*
1034  * We've eaten the eap packet into the eap_round.
1035  */
1036  *eap_packet_p = NULL;
1037 
1038  /*
1039  * First 5 bytes in eap, are code + id + length(2) + type.
1040  *
1041  * The rest is type-specific data. We skip type while
1042  * getting typedata from data.
1043  */
1044  typelen = len - 5/*code + id + length + type */;
1045  if (typelen > 0) {
1046  /*
1047  * Since the packet contains the complete
1048  * eap_packet, typedata will be a ptr in packet
1049  * to its typedata
1050  */
1051  eap_round->response->type.data = eap_round->response->packet + 5/*code+id+length+type*/;
1052  eap_round->response->type.length = typelen;
1053  } else {
1054  eap_round->response->type.length = 0;
1055  eap_round->response->type.data = NULL;
1056  }
1057 
1058  return eap_round;
1059 }
1060 
1061 /*
1062  * If identity response then create a fresh eap_session & fill the identity
1063  * else eap_session MUST be in our list, get that.
1064  * This eap_session creation cannot fail
1065  *
1066  * username contains REQUEST->username which might have been stripped.
1067  * identity contains the one sent in EAP-Identity response
1068  */
1070 {
1071  eap_session_t *eap_session = NULL;
1073  VALUE_PAIR *vp;
1074 
1075  /*
1076  * Ensure it's a valid EAP-Request, or EAP-Response.
1077  */
1078  if (eap_validation(request, eap_packet_p) == EAP_INVALID) {
1079  error:
1080  talloc_free(*eap_packet_p);
1081  *eap_packet_p = NULL;
1082  return NULL;
1083  }
1084 
1085  eap_packet = *eap_packet_p;
1086 
1087  /*
1088  * eap_session_t MUST be found in the list if it is not
1089  * EAP-Identity response
1090  */
1091  if (eap_packet->data[0] != PW_EAP_IDENTITY) {
1092  eap_session = request_data_reference(request, NULL, REQUEST_DATA_EAP_SESSION);
1093  if (!eap_session) {
1094  /* Either send EAP_Identity or EAP-Fail */
1095  REDEBUG("No EAP session matching state");
1096  goto error;
1097  }
1098  /*
1099  * This *MUST* be kept up to date, so that
1100  * request data is removed correctly when
1101  * the eap_session_t is freed.
1102  */
1103  eap_session->request = request;
1104  eap_session->updated = request->timestamp.tv_sec;
1105 
1106  RDEBUG4("Got eap_session_t %p from request data", eap_session);
1107 #ifdef WITH_VERIFY_PTR
1108  eap_session = talloc_get_type_abort(eap_session, eap_session_t);
1109 #endif
1110  eap_session->rounds++;
1111  if (eap_session->rounds >= 50) {
1112  RERROR("Failing EAP session due to too many round trips");
1113  talloc_free(eap_session);
1114  goto error;
1115  }
1116 
1117  /*
1118  * Even more paranoia. Without this, some weird
1119  * clients could do crazy things.
1120  *
1121  * It's ok to send EAP sub-type NAK in response
1122  * to a request for a particular type, but it's NOT
1123  * OK to blindly return data for another type.
1124  */
1125  if ((eap_packet->data[0] != PW_EAP_NAK) &&
1126  (eap_packet->data[0] != eap_session->type)) {
1127  RERROR("Response appears to match a previous request, but the EAP type is wrong");
1128  RERROR("We expected EAP type %s, but received type %s",
1129  eap_type2name(eap_session->type),
1130  eap_type2name(eap_packet->data[0]));
1131  RERROR("Your Supplicant or NAS is probably broken");
1132  goto error;
1133  }
1134 
1135  vp = fr_pair_find_by_num(request->packet->vps, 0, PW_USER_NAME, TAG_ANY);
1136  if (!vp) {
1137  /*
1138  * NAS did not set the User-Name
1139  * attribute, so we set it here and
1140  * prepend it to the beginning of the
1141  * request vps so that autz's work
1142  * correctly
1143  */
1144  RDEBUG2("Broken NAS did not set User-Name, setting from EAP Identity");
1145  vp = fr_pair_make(request->packet, &request->packet->vps, "User-Name", eap_session->identity, T_OP_EQ);
1146  if (!vp) {
1147  goto error;
1148  }
1149  } else {
1150  /*
1151  * A little more paranoia. If the NAS
1152  * *did* set the User-Name, and it doesn't
1153  * match the identity, (i.e. If they
1154  * change their User-Name part way through
1155  * the EAP transaction), then reject the
1156  * request as the NAS is doing something
1157  * funny.
1158  */
1159  if (strncmp(eap_session->identity, vp->vp_strvalue, MAX_STRING_LEN) != 0) {
1160  RDEBUG("Identity does not match User-Name. Authentication failed");
1161  goto error;
1162  }
1163  }
1164 
1165  /*
1166  * Packet was EAP identity
1167  */
1168  } else {
1169  eap_session = eap_session_alloc(inst, request);
1170  if (!eap_session) goto error;
1171 
1172  RDEBUG4("New eap_session_t %p", eap_session);
1173 
1174  /*
1175  * All fields in the eap_session are set to zero.
1176  */
1177  eap_session->identity = eap_identity(request, eap_session, eap_packet);
1178  if (!eap_session->identity) {
1179  RDEBUG("Identity Unknown, authentication failed");
1180  error2:
1181  talloc_free(eap_session);
1182  goto error;
1183  }
1184 
1185  vp = fr_pair_find_by_num(request->packet->vps, 0, PW_USER_NAME, TAG_ANY);
1186  if (!vp) {
1187  /*
1188  * NAS did not set the User-Name
1189  * attribute, so we set it here and
1190  * prepend it to the beginning of the
1191  * request vps so that autz's work
1192  * correctly
1193  */
1194  RWDEBUG2("NAS did not set User-Name. Setting it locally from EAP Identity");
1195  vp = fr_pair_make(request->packet, &request->packet->vps,
1196  "User-Name", eap_session->identity, T_OP_EQ);
1197  if (!vp) goto error2;
1198  } else {
1199  /*
1200  * Paranoia. If the NAS *did* set the
1201  * User-Name, and it doesn't match the
1202  * identity, the NAS is doing something
1203  * funny, so reject the request.
1204  */
1205  if (strncmp(eap_session->identity, vp->vp_strvalue, MAX_STRING_LEN) != 0) {
1206  RDEBUG("Identity does not match User-Name, setting from EAP Identity");
1207  goto error2;
1208  }
1209  }
1210  }
1211 
1212  eap_session->this_round = eap_buildds(eap_session, eap_packet_p);
1213  if (!eap_session->this_round) {
1214  REDEBUG("Failed allocating memory for round");
1215  goto error2;
1216  }
1217 
1218  return eap_session;
1219 }
uint8_t id
Definition: eap_types.h:145
uint8_t * packet
Definition: eap_types.h:138
size_t length
Definition: eap_types.h:135
VALUE_PAIR * config
VALUE_PAIR (s) used to set per request parameters for modules and the server core at runtime...
Definition: radiusd.h:227
Ok, continue.
Definition: eap_types.h:109
#define RERROR(fmt,...)
Definition: log.h:207
eap_process_t session_init
Callback for creating a new eap_session_t.
Definition: eap.h:99
void eap_success(eap_session_t *eap_session)
Definition: eap.c:868
RFC2865 - Access-Challenge.
Definition: radius.h:102
Main server configuration.
Definition: radiusd.h:108
Invalid, don't reply.
Definition: eap_types.h:112
The module is OK, continue.
Definition: radiusd.h:91
VALUE_PAIR * fr_pair_afrom_num(TALLOC_CTX *ctx, unsigned int vendor, unsigned int attr)
Create a new valuepair.
Definition: pair.c:106
#define RAD_REQUEST_OPTION_PROXY_EAP
Definition: eap.h:111
lt_dlhandle lt_dlopenext(char const *name)
Definition: modules.c:151
#define RWARN(fmt,...)
Definition: log.h:206
int rounds
How many roundtrips have occurred this session.
Definition: eap.h:84
VALUE_PAIR * radius_pair_create(TALLOC_CTX *ctx, VALUE_PAIR **vps, unsigned int attribute, unsigned int vendor)
Create a VALUE_PAIR and add it to a list of VALUE_PAIR s.
Definition: pair.c:704
eap_process_t process
Callback that should be used to process the next round.
Definition: eap.h:82
#define REDEBUG2(fmt,...)
Definition: log.h:255
VALUE_PAIR * vps
Result of decoding the packet into VALUE_PAIRs.
Definition: libradius.h:162
void * request_data_reference(REQUEST *request, void *unique_ptr, int unique_int)
Get opaque data from a request without removing it.
Definition: request.c:484
uint8_t code
Definition: eap_types.h:144
#define EAP_HEADER_LEN
Definition: eap_types.h:35
rlm_rcode_t eap_compose(eap_session_t *eap_session)
Definition: eap.c:445
bool finished
Whether we consider this session complete.
Definition: eap.h:89
home_pool_t * auth_pool
Definition: realms.h:183
Definition: realms.h:178
eap_packet_t * request
Packet we will send to the peer.
Definition: eap.h:45
#define inst
void * opaque
Opaque data used by EAP methods.
Definition: eap.h:80
Definition: token.h:46
The module considers the request invalid.
Definition: radiusd.h:93
void eap_fail(eap_session_t *eap_session)
Definition: eap.c:850
eap_type_data_t type
Definition: eap_types.h:136
REQUEST * request
Request that contains the response we're processing.
Definition: eap.h:71
EAP-Type specific data.
Definition: eap_types.h:121
RFC2865 - Access-Reject.
Definition: radius.h:94
enum eap_method eap_type_t
#define rad_assert(expr)
Definition: rad_assert.h:38
eap_type_t num
Definition: eap_types.h:122
enum eap_rcode eap_rcode_t
eap_type_t type
EAP method number.
Definition: eap.h:69
rlm_eap_module_t * type
Definition: rlm_eap.h:39
#define AUTH_VECTOR_LEN
Definition: libradius.h:118
bool debug_memory
Cleanup the server properly on exit, freeing up any memory we allocated.
Definition: radiusd.h:156
uint8_t id
Definition: eap_types.h:134
static eap_round_t * eap_buildds(eap_session_t *eap_session, eap_packet_raw_t **eap_packet_p)
Definition: eap.c:1013
Structure to represent packet format of eap on wire
Definition: eap_types.h:143
char const * name
Definition: rlm_eap.h:38
static int do_proxy(REQUEST *request)
Definition: listen.c:2010
void fr_pair_add(VALUE_PAIR **head, VALUE_PAIR *vp)
Add a VP to the end of the list.
Definition: pair.c:659
Tracks the progress of a single session of any EAP method.
Definition: eap.h:60
int(* detach)(void *instance)
Destroy an EAP submodule instance.
Definition: eap.h:103
Immediately reject the request.
Definition: radiusd.h:89
unsigned int code
Packet code (type).
Definition: libradius.h:155
eap_round_t * this_round
The EAP response we're processing, and the EAP request we're building.
Definition: eap.h:77
eap_rcode_t eap_method_select(rlm_eap_t *inst, eap_session_t *eap_session)
Select the correct callback based on a response.
Definition: eap.c:317
void * instance
Definition: rlm_eap.h:42
RFC2865 - Access-Accept.
Definition: radius.h:93
Failed, don't reply.
Definition: eap_types.h:110
REQUEST * parent
Definition: radiusd.h:290
Stores an attribute, a value and various bits of other data.
Definition: pair.h:112
size_t length
Definition: eap_types.h:123
RADIUS_PACKET * reply
Outgoing response.
Definition: radiusd.h:225
char * talloc_typed_asprintf(void const *t, char const *fmt,...)
Call talloc vasprintf, setting the type on the new chunk correctly.
Definition: missing.c:611
uint8_t length[2]
Definition: eap_types.h:146
uint8_t data[1]
Definition: eap_types.h:147
enum rlm_rcodes rlm_rcode_t
Return codes indicating the result of the module call.
Contains a pair of request and response packets.
Definition: eap.h:43
char const * name
The name of the sub-module (without rlm_ prefix).
Definition: eap.h:96
char const * fr_strerror(void)
Get the last library error.
Definition: log.c:212
#define RWDEBUG2(fmt,...)
Definition: log.h:252
Valid, continue.
Definition: eap_types.h:113
void fr_pair_delete_by_num(VALUE_PAIR **head, unsigned int vendor, unsigned int attr, int8_t tag)
Delete matching pairs.
Definition: pair.c:797
char * identity
NAI (User-Name) from EAP-Identity.
Definition: eap.h:73
char identity[]
Definition: eap_pwd.h:630
#define REQUEST_DATA_EAP_SESSION
Definition: eap.h:106
CONF_SECTION * cs
Definition: rlm_eap.h:41
#define RDEBUG2(fmt,...)
Definition: log.h:244
static int eap_validation(REQUEST *request, eap_packet_raw_t **eap_packet_p)
Definition: eap.c:878
EAP eap_session data found, continue.
Definition: eap_types.h:108
static int eap_module_call(eap_module_t *module, eap_session_t *eap_session)
Definition: eap.c:176
eap_session_t * eap_session_get(rlm_eap_t *inst, eap_packet_raw_t **eap_packet_p, REQUEST *request)
Definition: eap.c:1069
REALM * realm_find(char const *name)
Definition: realms.c:2235
bool ignore_unknown_types
Definition: rlm_eap.h:57
char const * eap_type2name(eap_type_t method)
Return an EAP-name for a particular type.
Definition: eapcommon.c:104
void fr_pair_value_memsteal(VALUE_PAIR *vp, uint8_t const *src)
Reparent an allocated octet buffer to a VALUE_PAIR.
Definition: pair.c:1933
#define TAG_ANY
Definition: pair.h:191
struct timeval timestamp
When we started processing the request.
Definition: radiusd.h:214
int eap_module_instantiate(rlm_eap_t *inst, eap_module_t **m_inst, eap_type_t num, CONF_SECTION *cs)
Load required EAP sub-modules (methods)
Definition: eap.c:96
int(* instantiate)(CONF_SECTION *conf, void **instance)
Create a new submodule instance.
Definition: eap.h:98
RADIUS_PACKET * packet
Incoming request.
Definition: radiusd.h:221
#define RAUTH(fmt,...)
Definition: log.h:202
char const * xlat_name
Definition: rlm_eap.h:64
#define REDEBUG(fmt,...)
Definition: log.h:254
static char const * eap_codes[]
Definition: eap.c:64
VALUE_PAIR * fr_pair_find_by_num(VALUE_PAIR *head, unsigned int vendor, unsigned int attr, int8_t tag)
Find the pair with the matching attribute.
Definition: pair.c:639
home_server_t * home_server
Definition: radiusd.h:240
int eap_wireformat(eap_packet_t *reply)
Definition: eapcommon.c:128
EAP eap_session data not found.
Definition: eap_types.h:107
static eap_type_t eap_process_nak(rlm_eap_t *inst, REQUEST *request, eap_type_t type, eap_type_data_t *nak)
Process NAK data from EAP peer.
Definition: eap.c:198
Succeeded without doing anything.
Definition: eap_types.h:111
eap_module_t * methods[PW_EAP_MAX_TYPES]
Definition: rlm_eap.h:52
Structure to hold EAP data.
Definition: eap_types.h:132
int eap_start(rlm_eap_t *inst, REQUEST *request)
Definition: eap.c:608
static char * eap_identity(REQUEST *request, eap_session_t *eap_session, eap_packet_raw_t *eap_packet)
Definition: eap.c:976
static int _eap_module_free(eap_module_t *inst)
Definition: eap.c:72
#define RDEBUG4(fmt,...)
Definition: log.h:246
eap_packet_t * response
Packet we received from the peer.
Definition: eap.h:44
#define MAX_STRING_LEN
Definition: libradius.h:120
eap_round_t * eap_round_alloc(eap_session_t *eap_session)
Definition: mem.c:32
eap_type_t default_method
Definition: rlm_eap.h:55
#define RCSID(id)
Definition: build.h:135
eap_session_t * eap_session_alloc(rlm_eap_t *inst, REQUEST *request)
Allocate a new eap_session_t.
Definition: mem.c:107
bool set_request_id
Definition: eap.h:46
The module handled the request, so stop.
Definition: radiusd.h:92
char const * module
Module the request is currently being processed by.
Definition: radiusd.h:253
void void void void void cf_log_module(CONF_SECTION const *cs, char const *fmt,...) CC_HINT(format(printf
VALUE_PAIR * fr_pair_make(TALLOC_CTX *ctx, VALUE_PAIR **vps, char const *attribute, char const *value, FR_TOKEN op)
Create a VALUE_PAIR from ASCII strings.
Definition: pair.c:338
#define PW_EAP_EXPANDED_TYPE
Definition: eap_types.h:104
#define RDEBUG(fmt,...)
Definition: log.h:243
uint32_t options
mainly for proxying EAP-MSCHAPv2.
Definition: radiusd.h:304
#define ERROR(fmt,...)
Definition: log.h:145
eap_code_t code
Definition: eap_types.h:133
time_t updated
The last time we received a packet for this EAP session.
Definition: eap.h:86
lt_dlhandle handle
Definition: rlm_eap.h:40
uint8_t * data
Definition: eap_types.h:124