All Data Structures Files Functions Variables Typedefs Enumerations Enumerator Macros Groups Pages
ttls.c
Go to the documentation of this file.
1 /*
2  * rlm_eap_ttls.c contains the interfaces that are called from eap
3  *
4  * Version: $Id: f37ba0e59ee4634d97d2c95375d138cb3cdba6bf $
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 2003 Alan DeKok <aland@freeradius.org>
21  * Copyright 2006 The FreeRADIUS server project
22  */
23 
24 RCSID("$Id: f37ba0e59ee4634d97d2c95375d138cb3cdba6bf $")
25 
26 #include "eap_ttls.h"
27 #include "eap_chbind.h"
28 
29 /*
30  * 0 1 2 3
31  * 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
32  * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
33  * | AVP Code |
34  * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
35  * |V M r r r r r r| AVP Length |
36  * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
37  * | Vendor-ID (opt) |
38  * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
39  * | Data ...
40  * +-+-+-+-+-+-+-+-+
41  */
42 
43 /*
44  * Verify that the diameter packet is valid.
45  */
46 static int diameter_verify(REQUEST *request, uint8_t const *data, unsigned int data_len)
47 {
48  uint32_t attr;
49  uint32_t length;
50  unsigned int hdr_len;
51  unsigned int remaining = data_len;
52 
53  while (remaining > 0) {
54  hdr_len = 12;
55 
56  if (remaining < hdr_len) {
57  RDEBUG2("Diameter attribute is too small (%u) to contain a Diameter header", remaining);
58  return 0;
59  }
60 
61  memcpy(&attr, data, sizeof(attr));
62  attr = ntohl(attr);
63  memcpy(&length, data + 4, sizeof(length));
64  length = ntohl(length);
65 
66  if ((data[4] & 0x80) != 0) {
67  if (remaining < 16) {
68  RDEBUG2("Diameter attribute is too small to contain a Diameter header with Vendor-Id");
69  return 0;
70  }
71 
72  hdr_len = 16;
73  }
74 
75  /*
76  * Get the length. If it's too big, die.
77  */
78  length &= 0x00ffffff;
79 
80  /*
81  * Too short or too long is bad.
82  */
83  if (length <= (hdr_len - 4)) {
84  RDEBUG2("Tunneled attribute %u is too short (%u < %u) to contain anything useful.", attr,
85  length, hdr_len);
86  return 0;
87  }
88 
89  if (length > remaining) {
90  RDEBUG2("Tunneled attribute %u is longer than room remaining in the packet (%u > %u).", attr,
91  length, remaining);
92  return 0;
93  }
94 
95  /*
96  * Check for broken implementations, which don't
97  * pad the AVP to a 4-octet boundary.
98  */
99  if (remaining == length) break;
100 
101  /*
102  * The length does NOT include the padding, so
103  * we've got to account for it here by rounding up
104  * to the nearest 4-byte boundary.
105  */
106  length += 0x03;
107  length &= ~0x03;
108 
109  /*
110  * If the rest of the diameter packet is larger than
111  * this attribute, continue.
112  *
113  * Otherwise, if the attribute over-flows the end
114  * of the packet, die.
115  */
116  if (remaining < length) {
117  REDEBUG2("Diameter attribute overflows packet!");
118  return 0;
119  }
120 
121  /*
122  * remaining > length, continue.
123  */
124  remaining -= length;
125  data += length;
126  }
127 
128  /*
129  * We got this far. It looks OK.
130  */
131  return 1;
132 }
133 
134 
135 /*
136  * Convert diameter attributes to our VALUE_PAIR's
137  */
138 static VALUE_PAIR *diameter2vp(REQUEST *request, REQUEST *fake, SSL *ssl,
139  uint8_t const *data, size_t data_len)
140 {
141  uint32_t attr;
142  uint32_t vendor;
143  uint32_t length;
144  size_t offset;
145  size_t size;
146  size_t data_left = data_len;
147  VALUE_PAIR *first = NULL;
148  VALUE_PAIR *vp = NULL;
149  RADIUS_PACKET *packet = fake->packet; /* FIXME: api issues */
150  vp_cursor_t out;
151 
152  fr_cursor_init(&out, &first);
153 
154  while (data_left > 0) {
155  rad_assert(data_left <= data_len);
156  memcpy(&attr, data, sizeof(attr));
157  data += 4;
158  attr = ntohl(attr);
159  vendor = 0;
160 
161  memcpy(&length, data, sizeof(length));
162  data += 4;
163  length = ntohl(length);
164 
165  /*
166  * A "vendor" flag, with a vendor ID of zero,
167  * is equivalent to no vendor. This is stupid.
168  */
169  offset = 8;
170  if ((length & ((uint32_t)1 << 31)) != 0) {
171  memcpy(&vendor, data, sizeof(vendor));
172  vendor = ntohl(vendor);
173 
174  data += 4; /* skip the vendor field, it's zero */
175  offset += 4; /* offset to value field */
176 
177  if (attr > 65535) goto next_attr;
178  }
179 
180  /*
181  * FIXME: Handle the M bit. For now, we assume that
182  * some other module takes care of any attribute
183  * with the M bit set.
184  */
185 
186  /*
187  * Get the length.
188  */
189  length &= 0x00ffffff;
190 
191  /*
192  * Get the size of the value portion of the
193  * attribute.
194  */
195  size = length - offset;
196 
197  /*
198  * Vendor attributes can be larger than 255.
199  * Normal attributes cannot be.
200  */
201  if ((attr > 255) && (vendor == 0)) {
202  RWDEBUG2("Skipping Diameter attribute %u", attr);
203  goto next_attr;
204  }
205 
206  /*
207  * EAP-Message AVPs can be larger than 253 octets.
208  *
209  * For now, we rely on the main decoder in
210  * src/lib/radius to decode data into VPs. This
211  * means putting the data into a RADIUS attribute
212  * format. It also means that we can't handle
213  * "extended" attributes in the Diameter space. Oh well...
214  */
215  if ((size > 253) && !((vendor == 0) && (attr == PW_EAP_MESSAGE))) {
216  RWDEBUG2("diameter2vp skipping long attribute %u", attr);
217  goto next_attr;
218  }
219 
220  /*
221  * RADIUS VSAs are handled as Diameter attributes
222  * with Vendor-Id == 0, and the VSA data packed
223  * into the "String" field as per normal.
224  *
225  * EXCEPT for the MS-CHAP attributes.
226  */
227  if ((vendor == 0) && (attr == PW_VENDOR_SPECIFIC)) {
228  ssize_t decoded;
229  uint8_t buffer[256];
230  vp_cursor_t cursor;
231 
232  buffer[0] = PW_VENDOR_SPECIFIC;
233  buffer[1] = size + 2;
234  memcpy(buffer + 2, data, size);
235 
236  fr_cursor_init(&cursor, &vp);
237  decoded = fr_radius_decode_pair(packet, &cursor, fr_dict_root(fr_dict_internal),
238  buffer, size + 2, NULL);
239  if (decoded < 0) {
240  REDEBUG2("diameter2vp failed decoding attr: %s",
241  fr_strerror());
242  goto do_octets;
243  }
244 
245  if ((size_t) decoded != size + 2) {
246  REDEBUG2("diameter2vp failed to entirely decode VSA");
247  fr_pair_list_free(&vp);
248  goto do_octets;
249  }
250 
251  fr_cursor_merge(&out, vp);
252 
253  goto next_attr;
254  }
255 
256  /*
257  * Create it. If this fails, it's because we're OOM.
258  */
259  do_octets:
260  vp = fr_pair_afrom_num(packet, vendor, attr);
261  if (!vp) {
262  RDEBUG2("Failure in creating VP");
263  fr_pair_list_free(&first);
264  return NULL;
265  }
266 
267  /*
268  * If it's a type from our dictionary, then
269  * we need to put the data in a relevant place.
270  *
271  * @todo: Export the lib/radius.c decoder, and use it here!
272  */
273  switch (vp->da->type) {
274  case PW_TYPE_INTEGER:
275  case PW_TYPE_DATE:
276  if (size != vp->vp_length) {
277  fr_dict_attr_t const *da;
278 
279  /*
280  * Bad format. Create a "raw"
281  * attribute.
282  */
283  raw:
284  if (vp) fr_pair_list_free(&vp);
285  da = fr_dict_unknown_afrom_fields(packet, fr_dict_root(fr_dict_internal), vendor, attr);
286  if (!da) return NULL;
287  vp = fr_pair_afrom_da(packet, da);
288  if (!vp) return NULL;
289  fr_pair_value_memcpy(vp, data, size);
290  break;
291  }
292  memcpy(&vp->vp_integer, data, vp->vp_length);
293 
294  /*
295  * Stored in host byte order: change it.
296  */
297  vp->vp_integer = ntohl(vp->vp_integer);
298  break;
299 
300  case PW_TYPE_INTEGER64:
301  if (size != vp->vp_length) goto raw;
302  memcpy(&vp->vp_integer64, data, vp->vp_length);
303 
304  /*
305  * Stored in host byte order: change it.
306  */
307  vp->vp_integer64 = ntohll(vp->vp_integer64);
308  break;
309 
310  case PW_TYPE_IPV4_ADDR:
311  if (size != vp->vp_length) {
312  RDEBUG2("Invalid length attribute %d",
313  attr);
314  fr_pair_list_free(&first);
315  fr_pair_list_free(&vp);
316  return NULL;
317  }
318  memcpy(&vp->vp_ipaddr, data, vp->vp_length);
319 
320  /*
321  * Stored in network byte order: don't change it.
322  */
323  break;
324 
325  case PW_TYPE_BYTE:
326  if (size != vp->vp_length) goto raw;
327  vp->vp_byte = data[0];
328  break;
329 
330  case PW_TYPE_SHORT:
331  if (size != vp->vp_length) goto raw;
332  vp->vp_short = (data[0] * 256) + data[1];
333  break;
334 
335  case PW_TYPE_SIGNED:
336  if (size != vp->vp_length) goto raw;
337  memcpy(&vp->vp_signed, data, vp->vp_length);
338  vp->vp_signed = ntohl(vp->vp_signed);
339  break;
340 
341  case PW_TYPE_IPV6_ADDR:
342  if (size != vp->vp_length) goto raw;
343  memcpy(&vp->vp_ipv6addr, data, vp->vp_length);
344  break;
345 
346  case PW_TYPE_IPV6_PREFIX:
347  if (size != vp->vp_length) goto raw;
348  memcpy(vp->vp_ipv6prefix, data, vp->vp_length);
349  break;
350 
351  case PW_TYPE_STRING:
352  fr_pair_value_bstrncpy(vp, data, size);
353  vp->vp_length = strlen(vp->vp_strvalue); /* embedded zeros are NOT allowed */
354  break;
355 
356  /*
357  * Copy it over verbatim.
358  */
359  case PW_TYPE_OCTETS:
360  default:
361  fr_pair_value_memcpy(vp, data, size);
362  break;
363  }
364 
365  /*
366  * Ensure that the client is using the
367  * correct challenge. This weirdness is
368  * to protect against against replay
369  * attacks, where anyone observing the
370  * CHAP exchange could pose as that user,
371  * by simply choosing to use the same
372  * challenge.
373  *
374  * By using a challenge based on
375  * information from the current session,
376  * we can guarantee that the client is
377  * not *choosing* a challenge.
378  *
379  * We're a little forgiving in that we
380  * have loose checks on the length, and
381  * we do NOT check the Id (first octet of
382  * the response to the challenge)
383  *
384  * But if the client gets the challenge correct,
385  * we're not too worried about the Id.
386  */
387  if (((vp->da->vendor == 0) && (vp->da->attr == PW_CHAP_CHALLENGE)) ||
388  ((vp->da->vendor == VENDORPEC_MICROSOFT) && (vp->da->attr == PW_MSCHAP_CHALLENGE))) {
389  uint8_t challenge[16];
390 
391  if ((vp->vp_length < 8) ||
392  (vp->vp_length > 16)) {
393  RDEBUG("Tunneled challenge has invalid length");
394  fr_pair_list_free(&first);
395  fr_pair_list_free(&vp);
396  return NULL;
397  }
398 
399  eap_ttls_gen_challenge(ssl, challenge,
400  sizeof(challenge));
401 
402  if (memcmp(challenge, vp->vp_octets,
403  vp->vp_length) != 0) {
404  RDEBUG("Tunneled challenge is incorrect");
405  fr_pair_list_free(&first);
406  fr_pair_list_free(&vp);
407  return NULL;
408  }
409  }
410 
411  /*
412  * Update the list.
413  */
414  fr_cursor_insert(&out, vp);
415 
416  next_attr:
417  /*
418  * Catch non-aligned attributes.
419  */
420  if (data_left == length) break;
421 
422  /*
423  * The length does NOT include the padding, so
424  * we've got to account for it here by rounding up
425  * to the nearest 4-byte boundary.
426  */
427  length += 0x03;
428  length &= ~0x03;
429 
430  rad_assert(data_left >= length);
431  data_left -= length;
432  data += length - offset; /* already updated */
433  }
434 
435  /*
436  * We got this far. It looks OK.
437  */
438  return first;
439 }
440 
441 /*
442  * Convert VALUE_PAIR's to diameter attributes, and write them
443  * to an SSL session.
444  *
445  * The ONLY VALUE_PAIR's which may be passed to this function
446  * are ones which can go inside of a RADIUS (i.e. diameter)
447  * packet. So no server-configuration attributes, or the like.
448  */
449 static int vp2diameter(REQUEST *request, tls_session_t *tls_session, VALUE_PAIR *first)
450 {
451  /*
452  * RADIUS packets are no more than 4k in size, so if
453  * we've got more than 4k of data to write, it's very
454  * bad.
455  */
456  uint8_t buffer[4096];
457  uint8_t *p;
458  uint32_t attr;
459  uint32_t length;
460  uint32_t vendor;
461  size_t total;
462  uint64_t attr64;
463  VALUE_PAIR *vp;
464  vp_cursor_t cursor;
465 
466  p = buffer;
467  total = 0;
468 
469  for (vp = fr_cursor_init(&cursor, &first); vp; vp = fr_cursor_next(&cursor)) {
470  /*
471  * Too much data: die.
472  */
473  if ((total + vp->vp_length + 12) >= sizeof(buffer)) {
474  RDEBUG2("output buffer is full!");
475  return 0;
476  }
477 
478  /*
479  * Hmm... we don't group multiple EAP-Messages
480  * together. Maybe we should...
481  */
482 
483  length = vp->vp_length;
484  vendor = vp->da->vendor;
485  if (vendor != 0) {
486  attr = vp->da->attr & 0xffff;
487  length |= ((uint32_t)1 << 31);
488  } else {
489  attr = vp->da->attr;
490  }
491 
492  /*
493  * Hmm... set the M bit for all attributes?
494  */
495  length |= (1 << 30);
496 
497  attr = ntohl(attr);
498 
499  memcpy(p, &attr, sizeof(attr));
500  p += 4;
501  total += 4;
502 
503  length += 8; /* includes 8 bytes of attr & length */
504 
505  if (vendor != 0) {
506  length += 4; /* include 4 bytes of vendor */
507 
508  length = ntohl(length);
509  memcpy(p, &length, sizeof(length));
510  p += 4;
511  total += 4;
512 
513  vendor = ntohl(vendor);
514  memcpy(p, &vendor, sizeof(vendor));
515  p += 4;
516  total += 4;
517  } else {
518  length = ntohl(length);
519  memcpy(p, &length, sizeof(length));
520  p += 4;
521  total += 4;
522  }
523 
524  switch (vp->da->type) {
525  case PW_TYPE_INTEGER:
526  case PW_TYPE_DATE:
527  attr = htonl(vp->vp_integer); /* stored in host order */
528  memcpy(p, &attr, sizeof(attr));
529  length = 4;
530  break;
531 
532  case PW_TYPE_INTEGER64:
533  attr64 = htonll(vp->vp_integer64); /* stored in host order */
534  memcpy(p, &attr64, sizeof(attr64));
535  length = 8;
536  break;
537 
538  case PW_TYPE_IPV4_ADDR:
539  memcpy(p, &vp->vp_ipaddr, 4); /* network order */
540  length = 4;
541  break;
542 
543  case PW_TYPE_STRING:
544  case PW_TYPE_OCTETS:
545  default:
546  memcpy(p, vp->vp_strvalue, vp->vp_length);
547  length = vp->vp_length;
548  break;
549  }
550 
551  /*
552  * Skip to the end of the data.
553  */
554  p += length;
555  total += length;
556 
557  /*
558  * Align the data to a multiple of 4 bytes.
559  */
560  if ((total & 0x03) != 0) {
561  size_t i;
562 
563  length = 4 - (total & 0x03);
564  for (i = 0; i < length; i++) {
565  *p = '\0';
566  p++;
567  total++;
568  }
569  }
570  } /* loop over the VP's to write. */
571 
572  /*
573  * Write the data in the buffer to the SSL session.
574  */
575  if (total > 0) {
576 #ifndef NDEBUG
577  size_t i;
578 
579  if ((rad_debug_lvl > 2) && fr_log_fp) {
580  for (i = 0; i < total; i++) {
581  if ((i & 0x0f) == 0) fprintf(fr_log_fp, " TTLS tunnel data out %04x: ", (int) i);
582 
583  fprintf(fr_log_fp, "%02x ", buffer[i]);
584 
585  if ((i & 0x0f) == 0x0f) fprintf(fr_log_fp, "\n");
586  }
587  if ((total & 0x0f) != 0) fprintf(fr_log_fp, "\n");
588  }
589 #endif
590 
591  (tls_session->record_from_buff)(&tls_session->clean_in, buffer, total);
592 
593  /*
594  * FIXME: Check the return code.
595  */
596  tls_handshake_send(request, tls_session);
597  }
598 
599  /*
600  * Everything's OK.
601  */
602  return 1;
603 }
604 
605 /*
606  * Use a reply packet to determine what to do.
607  */
608 static rlm_rcode_t CC_HINT(nonnull) process_reply(eap_session_t *eap_session, tls_session_t *tls_session,
609  REQUEST *request, RADIUS_PACKET *reply)
610 {
612  VALUE_PAIR *vp;
613  ttls_tunnel_t *t = tls_session->opaque;
614 
615  rad_assert(eap_session->request == request);
616 
617  /*
618  * If the response packet was Access-Accept, then
619  * we're OK. If not, die horribly.
620  *
621  * FIXME: Take MS-CHAP2-Success attribute, and
622  * tunnel it back to the client, to authenticate
623  * ourselves to the client.
624  *
625  * FIXME: If we have an Access-Challenge, then
626  * the Reply-Message is tunneled back to the client.
627  *
628  * FIXME: If we have an EAP-Message, then that message
629  * must be tunneled back to the client.
630  *
631  * FIXME: If we have an Access-Challenge with a State
632  * attribute, then do we tunnel that to the client, or
633  * keep track of it ourselves?
634  *
635  * FIXME: EAP-Messages can only start with 'identity',
636  * NOT 'eap start', so we should check for that....
637  */
638  switch (reply->code) {
640  RDEBUG("Got tunneled Access-Accept");
641 
642  rcode = RLM_MODULE_OK;
643 
644  /*
645  * Always delete MPPE keys & encryption policy
646  * from the tunneled reply. These never get sent
647  * back to the user.
648  */
653 
654  /*
655  * MS-CHAP2-Success means that we do NOT return
656  * an Access-Accept, but instead tunnel that
657  * attribute to the client, and keep going with
658  * the TTLS session. Once the client accepts
659  * our identity, it will respond with an empty
660  * packet, and we will send EAP-Success.
661  */
662  vp = NULL;
663  fr_pair_list_mcopy_by_num(tls_session, &vp, &reply->vps, VENDORPEC_MICROSOFT, PW_MSCHAP2_SUCCESS,
664  TAG_ANY);
665  if (vp) {
666  RDEBUG("Got MS-CHAP2-Success, tunneling it to the client in a challenge");
667  rcode = RLM_MODULE_HANDLED;
668  t->authenticated = true;
669 
670  /*
671  * Use the tunneled reply, but not now.
672  */
673  if (t->use_tunneled_reply) {
674  rad_assert(!t->accept_vps);
675  fr_pair_list_mcopy_by_num(t, &t->accept_vps, &reply->vps, 0, 0, TAG_ANY);
676  rad_assert(!reply->vps);
677  }
678 
679  } else { /* no MS-CHAP2-Success */
680  /*
681  * Can only have EAP-Message if there's
682  * no MS-CHAP2-Success.
683  *
684  * We also do NOT tunnel the EAP-Success
685  * attribute back to the client, as the client
686  * can figure it out, from the non-tunneled
687  * EAP-Success packet.
688  */
689  fr_pair_list_mcopy_by_num(tls_session, &vp, &reply->vps, 0, PW_EAP_MESSAGE, TAG_ANY);
690  fr_pair_list_free(&vp);
691  }
692 
693  /* move channel binding responses; we need to send them */
694  fr_pair_list_mcopy_by_num(tls_session, &vp, &reply->vps, VENDORPEC_UKERNA, PW_UKERNA_CHBIND, TAG_ANY);
696  t->authenticated = true;
697  /*
698  * Use the tunneled reply, but not now.
699  */
700  if (t->use_tunneled_reply) {
701  rad_assert(!t->accept_vps);
702  fr_pair_list_mcopy_by_num(t, &t->accept_vps, &reply->vps, 0, 0, TAG_ANY);
703  rad_assert(!reply->vps);
704  }
705  rcode = RLM_MODULE_HANDLED;
706  }
707 
708  /*
709  * Handle the ACK, by tunneling any necessary reply
710  * VP's back to the client.
711  */
712  if (vp) {
713  RDEBUG("Sending tunneled reply attributes");
714  rdebug_pair_list(L_DBG_LVL_1, request, vp, NULL);
715 
716  vp2diameter(request, tls_session, vp);
717  fr_pair_list_free(&vp);
718  }
719 
720  /*
721  * If we've been told to use the attributes from
722  * the reply, then do so.
723  *
724  * WARNING: This may leak information about the
725  * tunneled user!
726  */
727  if (t->use_tunneled_reply) {
728  fr_pair_delete_by_num(&reply->vps, 0, PW_PROXY_STATE, TAG_ANY);
729  fr_pair_list_mcopy_by_num(request->reply, &request->reply->vps, &reply->vps, 0, 0, TAG_ANY);
730  }
731  break;
732 
733 
735  RDEBUG("Got tunneled Access-Reject");
736  rcode = RLM_MODULE_REJECT;
737  break;
738 
739  /*
740  * Handle Access-Challenge, but only if we
741  * send tunneled reply data. This is because
742  * an Access-Challenge means that we MUST tunnel
743  * a Reply-Message to the client.
744  */
746  RDEBUG("Got tunneled Access-Challenge");
747 
748  /*
749  * Keep the State attribute, if necessary.
750  *
751  * Get rid of the old State, too.
752  */
754  fr_pair_list_mcopy_by_num(t, &t->state, &reply->vps, 0, PW_STATE, TAG_ANY);
755 
756  /*
757  * We should really be a bit smarter about this,
758  * and move over only those attributes which
759  * are relevant to the authentication request,
760  * but that's a lot more work, and this "dumb"
761  * method works in 99.9% of the situations.
762  */
763  vp = NULL;
764  fr_pair_list_mcopy_by_num(t, &vp, &reply->vps, 0, PW_EAP_MESSAGE, TAG_ANY);
765 
766  /*
767  * There MUST be a Reply-Message in the challenge,
768  * which we tunnel back to the client.
769  *
770  * If there isn't one in the reply VP's, then
771  * we MUST create one, with an empty string as
772  * it's value.
773  */
774  fr_pair_list_mcopy_by_num(t, &vp, &reply->vps, 0, PW_REPLY_MESSAGE, TAG_ANY);
775 
776  /* also move chbind messages, if any */
778 
779  /*
780  * Handle the ACK, by tunneling any necessary reply
781  * VP's back to the client.
782  */
783  if (vp) {
784  vp2diameter(request, tls_session, vp);
785  fr_pair_list_free(&vp);
786  }
787  rcode = RLM_MODULE_HANDLED;
788  break;
789 
790  default:
791  RDEBUG("Unknown RADIUS packet type %d: rejecting tunneled user", reply->code);
792  rcode = RLM_MODULE_INVALID;
793  break;
794  }
795 
796  return rcode;
797 }
798 
799 
800 #ifdef WITH_PROXY
801 /*
802  * Do post-proxy processing,
803  */
804 static int CC_HINT(nonnull) eap_ttls_postproxy(eap_session_t *eap_session, void *data)
805 {
806  int rcode;
807  tls_session_t *tls_session = (tls_session_t *) data;
808  REQUEST *fake, *request = eap_session->request;
809 
810  RDEBUG("Passing reply from proxy back into the tunnel");
811 
812  /*
813  * If there was a fake request associated with the proxied
814  * request, do more processing of it.
815  */
816  fake = (REQUEST *) request_data_get(eap_session->request,
817  eap_session->request->proxy,
819 
820  /*
821  * Do the callback, if it exists, and if it was a success.
822  */
823  if (fake && (eap_session->request->proxy_reply->code == PW_CODE_ACCESS_ACCEPT)) {
824  /*
825  * Terrible hacks.
826  */
827  rad_assert(!fake->packet);
828  fake->packet = talloc_steal(fake, request->proxy);
829  fake->packet->src_ipaddr = request->packet->src_ipaddr;
830  request->proxy = NULL;
831 
832  rad_assert(!fake->reply);
833  fake->reply = talloc_steal(fake, request->proxy_reply);
834  request->proxy_reply = NULL;
835 
836  if ((rad_debug_lvl > 0) && fr_log_fp) {
837  fprintf(fr_log_fp, "server %s {\n",
838  (!fake->server) ? "" : fake->server);
839  }
840 
841  /*
842  * Perform a post-auth stage for the tunneled
843  * session.
844  */
846  rcode = rad_postauth(fake);
847  RDEBUG2("post-auth returns %d", rcode);
848 
849  if ((rad_debug_lvl > 0) && fr_log_fp) {
850  fprintf(fr_log_fp, "} # server %s\n",
851  (!fake->server) ? "" : fake->server);
852 
853  RDEBUG("Final reply from tunneled session code %d", fake->reply->code);
854  rdebug_pair_list(L_DBG_LVL_1, request, fake->reply->vps, NULL);
855  }
856 
857  /*
858  * Terrible hacks.
859  */
860  request->proxy = talloc_steal(request, fake->packet);
861  fake->packet = NULL;
862  request->proxy_reply = talloc_steal(request, fake->reply);
863  fake->reply = NULL;
864 
865  /*
866  * And we're done with this request.
867  */
868 
869  switch (rcode) {
870  case RLM_MODULE_FAIL:
871  talloc_free(fake);
872  eap_tls_fail(eap_session);
873  return 0;
874 
875  default: /* Don't Do Anything */
876  RDEBUG2("Got reply %d",
877  request->proxy_reply->code);
878  break;
879  }
880  }
881  talloc_free(fake); /* robust if !fake */
882 
883  /*
884  * Process the reply from the home server.
885  */
886  rcode = process_reply(eap_session, tls_session, eap_session->request, eap_session->request->proxy_reply);
887 
888  /*
889  * The proxy code uses the reply from the home server as
890  * the basis for the reply to the NAS. We don't want that,
891  * so we toss it, after we've had our way with it.
892  */
893  fr_pair_list_free(&eap_session->request->proxy_reply->vps);
894 
895  switch (rcode) {
896  case RLM_MODULE_REJECT:
897  RDEBUG("Reply was rejected");
898  break;
899 
900  case RLM_MODULE_HANDLED:
901  RDEBUG("Reply was handled");
902  eap_tls_request(eap_session);
904  return 1;
905 
906  case RLM_MODULE_OK:
907  RDEBUG("Reply was OK");
908 
909  /*
910  * Success: Automatically return MPPE keys.
911  */
912  if (eap_tls_success(eap_session) < 0) return 0;
913  return 1;
914 
915  default:
916  RDEBUG("Reply was unknown");
917  break;
918  }
919 
920  eap_tls_fail(eap_session);
921  return 0;
922 }
923 
924 #endif /* WITH_PROXY */
925 
926 /*
927  * Process the "diameter" contents of the tunneled data.
928  */
929 PW_CODE eap_ttls_process(eap_session_t *eap_session, tls_session_t *tls_session)
930 {
932  rlm_rcode_t rcode;
933  REQUEST *fake;
934  VALUE_PAIR *vp;
935  ttls_tunnel_t *t;
936  uint8_t const *data;
937  size_t data_len;
938  REQUEST *request = eap_session->request;
939  chbind_packet_t *chbind;
940 
941  /*
942  * Just look at the buffer directly, without doing
943  * record_to_buff.
944  */
945  data_len = tls_session->clean_out.used;
946  tls_session->clean_out.used = 0;
947  data = tls_session->clean_out.data;
948 
949  t = (ttls_tunnel_t *) tls_session->opaque;
950 
951  /*
952  * If there's no data, maybe this is an ACK to an
953  * MS-CHAP2-Success.
954  */
955  if (data_len == 0) {
956  if (t->authenticated) {
957  RDEBUG("Got ACK, and the user was already authenticated");
958  return PW_CODE_ACCESS_ACCEPT;
959  } /* else no session, no data, die. */
960 
961  /*
962  * FIXME: Call SSL_get_error() to see what went
963  * wrong.
964  */
965  RDEBUG2("SSL_read Error");
966  return PW_CODE_ACCESS_REJECT;
967  }
968 
969 #ifndef NDEBUG
970  if ((rad_debug_lvl > 2) && fr_log_fp) {
971  size_t i;
972 
973  for (i = 0; i < data_len; i++) {
974  if ((i & 0x0f) == 0) fprintf(fr_log_fp, " TTLS tunnel data in %04x: ", (int) i);
975 
976  fprintf(fr_log_fp, "%02x ", data[i]);
977 
978  if ((i & 0x0f) == 0x0f) fprintf(fr_log_fp, "\n");
979  }
980  if ((data_len & 0x0f) != 0) fprintf(fr_log_fp, "\n");
981  }
982 #endif
983 
984  if (!diameter_verify(request, data, data_len)) {
985  return PW_CODE_ACCESS_REJECT;
986  }
987 
988  /*
989  * Allocate a fake REQUEST structure.
990  */
991  fake = request_alloc_fake(request);
992 
993  rad_assert(!fake->packet->vps);
994 
995  /*
996  * Add the tunneled attributes to the fake request.
997  */
998  fake->packet->vps = diameter2vp(request, fake, tls_session->ssl, data, data_len);
999  if (!fake->packet->vps) {
1000  talloc_free(fake);
1001  return PW_CODE_ACCESS_REJECT;
1002  }
1003 
1004  /*
1005  * Tell the request that it's a fake one.
1006  */
1007  pair_make_request("Freeradius-Proxied-To", "127.0.0.1", T_OP_EQ);
1008 
1009  RDEBUG("Got tunneled request");
1010  rdebug_pair_list(L_DBG_LVL_1, request, fake->packet->vps, NULL);
1011 
1012  /*
1013  * Update other items in the REQUEST data structure.
1014  */
1015  fake->username = fr_pair_find_by_num(fake->packet->vps, 0, PW_USER_NAME, TAG_ANY);
1016  fake->password = fr_pair_find_by_num(fake->packet->vps, 0, PW_USER_PASSWORD, TAG_ANY);
1017 
1018  /*
1019  * No User-Name, try to create one from stored data.
1020  */
1021  if (!fake->username) {
1022  /*
1023  * No User-Name in the stored data, look for
1024  * an EAP-Identity, and pull it out of there.
1025  */
1026  if (!t->username) {
1027  vp = fr_pair_find_by_num(fake->packet->vps, 0, PW_EAP_MESSAGE, TAG_ANY);
1028  if (vp &&
1029  (vp->vp_length >= EAP_HEADER_LEN + 2) &&
1030  (vp->vp_strvalue[0] == PW_EAP_RESPONSE) &&
1031  (vp->vp_strvalue[EAP_HEADER_LEN] == PW_EAP_IDENTITY) &&
1032  (vp->vp_strvalue[EAP_HEADER_LEN + 1] != 0)) {
1033  /*
1034  * Create & remember a User-Name
1035  */
1036  t->username = fr_pair_make(t, NULL, "User-Name", NULL, T_OP_EQ);
1037  rad_assert(t->username != NULL);
1038 
1039  fr_pair_value_bstrncpy(t->username, vp->vp_octets + 5, vp->vp_length - 5);
1040 
1041  RDEBUG("Got tunneled identity of %s",
1042  t->username->vp_strvalue);
1043 
1044  /*
1045  * If there's a default EAP type,
1046  * set it here.
1047  */
1048  if (t->default_method != 0) {
1049  RDEBUG("Setting default EAP type for tunneled EAP session");
1050  vp = fr_pair_afrom_num(fake, 0, PW_EAP_TYPE);
1051  rad_assert(vp != NULL);
1052  vp->vp_integer = t->default_method;
1053  fr_pair_add(&fake->config, vp);
1054  }
1055 
1056  } else {
1057  /*
1058  * Don't reject the request outright,
1059  * as it's permitted to do EAP without
1060  * user-name.
1061  */
1062  RWDEBUG2("No EAP-Identity found to start EAP conversation");
1063  }
1064  } /* else there WAS a t->username */
1065 
1066  if (t->username) {
1067  vp = fr_pair_list_copy(fake->packet, t->username);
1068  fr_pair_add(&fake->packet->vps, vp);
1069  fake->username = fr_pair_find_by_num(fake->packet->vps, 0, PW_USER_NAME, TAG_ANY);
1070  }
1071  } /* else the request ALREADY had a User-Name */
1072 
1073  /*
1074  * Add the State attribute, too, if it exists.
1075  */
1076  if (t->state) {
1077  vp = fr_pair_list_copy(fake->packet, t->state);
1078  if (vp) fr_pair_add(&fake->packet->vps, vp);
1079  }
1080 
1081  /*
1082  * If this is set, we copy SOME of the request attributes
1083  * from outside of the tunnel to inside of the tunnel.
1084  *
1085  * We copy ONLY those attributes which do NOT already
1086  * exist in the tunneled request.
1087  */
1088  if (t->copy_request_to_tunnel) {
1089  VALUE_PAIR *copy;
1090  vp_cursor_t cursor;
1091 
1092  for (vp = fr_cursor_init(&cursor, &request->packet->vps); vp; vp = fr_cursor_next(&cursor)) {
1093  /*
1094  * The attribute is a server-side thingy,
1095  * don't copy it.
1096  */
1097  if ((vp->da->attr > 255) &&
1098  (vp->da->vendor == 0)) {
1099  continue;
1100  }
1101 
1102  /*
1103  * The outside attribute is already in the
1104  * tunnel, don't copy it.
1105  *
1106  * This works for BOTH attributes which
1107  * are originally in the tunneled request,
1108  * AND attributes which are copied there
1109  * from below.
1110  */
1111  if (fr_pair_find_by_da(fake->packet->vps, vp->da, TAG_ANY)) {
1112  continue;
1113  }
1114 
1115  /*
1116  * Some attributes are handled specially.
1117  */
1118  switch (vp->da->attr) {
1119  /*
1120  * NEVER copy Message-Authenticator,
1121  * EAP-Message, or State. They're
1122  * only for outside of the tunnel.
1123  */
1124  case PW_USER_NAME:
1125  case PW_USER_PASSWORD:
1126  case PW_CHAP_PASSWORD:
1127  case PW_CHAP_CHALLENGE:
1128  case PW_PROXY_STATE:
1129  case PW_MESSAGE_AUTHENTICATOR:
1130  case PW_EAP_MESSAGE:
1131  case PW_STATE:
1132  continue;
1133 
1134  /*
1135  * By default, copy it over.
1136  */
1137  default:
1138  break;
1139  }
1140 
1141  /*
1142  * Don't copy from the head, we've already
1143  * checked it.
1144  */
1145  copy = fr_pair_list_copy_by_num(fake->packet, vp, vp->da->vendor, vp->da->attr, TAG_ANY);
1146  fr_pair_add(&fake->packet->vps, copy);
1147  }
1148  }
1149 
1150  /*
1151  * Process channel binding.
1152  */
1153  chbind = eap_chbind_vp2packet(fake, fake->packet->vps);
1154  if (chbind) {
1155  PW_CODE chbind_code;
1156  CHBIND_REQ *req = talloc_zero(fake, CHBIND_REQ);
1157 
1158  RDEBUG("received chbind request");
1159  req->request = chbind;
1160  if (fake->username) {
1161  req->username = fake->username;
1162  } else {
1163  req->username = NULL;
1164  }
1165  chbind_code = chbind_process(request, req);
1166 
1167  /* encapsulate response here */
1168  if (req->response) {
1169  RDEBUG("sending chbind response");
1170  fr_pair_add(&fake->reply->vps,
1171  eap_chbind_packet2vp(fake, req->response));
1172  } else {
1173  RDEBUG("no chbind response");
1174  }
1175 
1176  /* clean up chbind req */
1177  talloc_free(req);
1178 
1179  if (chbind_code != PW_CODE_ACCESS_ACCEPT) {
1180  return chbind_code;
1181  }
1182  }
1183 
1184  /*
1185  * Call authentication recursively, which will
1186  * do PAP, CHAP, MS-CHAP, etc.
1187  */
1188  eap_virtual_server(request, fake, eap_session, t->virtual_server);
1189 
1190  /*
1191  * Decide what to do with the reply.
1192  */
1193  switch (fake->reply->code) {
1194  case 0: /* No reply code, must be proxied... */
1195 #ifdef WITH_PROXY
1196  vp = fr_pair_find_by_num(fake->config, 0, PW_PROXY_TO_REALM, TAG_ANY);
1197  if (vp) {
1198  eap_tunnel_data_t *tunnel;
1199  RDEBUG("Tunneled authentication will be proxied to %s", vp->vp_strvalue);
1200 
1201  /*
1202  * Tell the original request that it's going
1203  * to be proxied.
1204  */
1205  fr_pair_list_mcopy_by_num(request, &request->config, &fake->config, 0, PW_PROXY_TO_REALM,
1206  TAG_ANY);
1207 
1208  /*
1209  * Seed the proxy packet with the
1210  * tunneled request.
1211  */
1212  rad_assert(!request->proxy);
1213  request->proxy = talloc_steal(request, fake->packet);
1214  memset(&request->proxy->src_ipaddr, 0,
1215  sizeof(request->proxy->src_ipaddr));
1216  memset(&request->proxy->src_ipaddr, 0,
1217  sizeof(request->proxy->src_ipaddr));
1218  request->proxy->src_port = 0;
1219  request->proxy->dst_port = 0;
1220  fake->packet = NULL;
1221  fr_radius_free(&fake->reply);
1222  fake->reply = NULL;
1223 
1224  /*
1225  * Set up the callbacks for the tunnel
1226  */
1227  tunnel = talloc_zero(request, eap_tunnel_data_t);
1228  tunnel->tls_session = tls_session;
1229  tunnel->callback = eap_ttls_postproxy;
1230 
1231  /*
1232  * Associate the callback with the request.
1233  */
1234  code = request_data_add(request, request->proxy, REQUEST_DATA_EAP_TUNNEL_CALLBACK,
1235  tunnel, false, false, false);
1236  rad_assert(code == 0);
1237 
1238  /*
1239  * rlm_eap.c has taken care of associating
1240  * the eap_session with the fake request.
1241  *
1242  * So we associate the fake request with
1243  * this request.
1244  */
1246  fake, true, false, false);
1247  rad_assert(code == 0);
1248  fake = NULL;
1249 
1250  /*
1251  * Didn't authenticate the packet, but
1252  * we're proxying it.
1253  */
1254  code = PW_CODE_STATUS_CLIENT;
1255 
1256  } else
1257 #endif /* WITH_PROXY */
1258  {
1259  RDEBUG("No tunneled reply was found for request %d , and the request was not proxied: rejecting the user.",
1260  request->number);
1261  code = PW_CODE_ACCESS_REJECT;
1262  }
1263  break;
1264 
1265  default:
1266  /*
1267  * Returns RLM_MODULE_FOO, and we want to return PW_FOO
1268  */
1269  rcode = process_reply(eap_session, tls_session, request, fake->reply);
1270  switch (rcode) {
1271  case RLM_MODULE_REJECT:
1272  code = PW_CODE_ACCESS_REJECT;
1273  break;
1274 
1275  case RLM_MODULE_HANDLED:
1276  code = PW_CODE_ACCESS_CHALLENGE;
1277  break;
1278 
1279  case RLM_MODULE_OK:
1280  code = PW_CODE_ACCESS_ACCEPT;
1281  break;
1282 
1283  default:
1284  code = PW_CODE_ACCESS_REJECT;
1285  break;
1286  }
1287  break;
1288  }
1289 
1290  talloc_free(fake);
1291 
1292  return code;
1293 }
#define PW_MSCHAP_CHALLENGE
Definition: radius.h:213
bool use_tunneled_reply
Definition: eap_ttls.h:37
bool copy_request_to_tunnel
Definition: eap_ttls.h:36
void fr_pair_list_free(VALUE_PAIR **)
Free memory used by a valuepair list.
Definition: pair.c:544
static rlm_rcode_t CC_HINT(nonnull)
Definition: ttls.c:608
rlm_rcode_t eap_virtual_server(REQUEST *request, REQUEST *fake, eap_session_t *eap_session, char const *virtual_server)
Send a fake request to a virtual server, managing the eap_session_t of the child. ...
Definition: eapcommon.c:418
FILE * fr_log_fp
Definition: radius.c:81
128 Bit IPv6 Address.
Definition: radius.h:40
VALUE_PAIR * config
VALUE_PAIR (s) used to set per request parameters for modules and the server core at runtime...
Definition: radiusd.h:227
VALUE_PAIR * eap_chbind_packet2vp(REQUEST *request, chbind_packet_t *packet)
Definition: eap_chbind.c:291
fr_dict_attr_t * fr_dict_unknown_afrom_fields(TALLOC_CTX *ctx, fr_dict_attr_t const *parent, unsigned int vendor, unsigned int attr) CC_HINT(nonnull)
Allocates an unknown attribute.
Definition: dict.c:2613
RFC2865 - Access-Challenge.
Definition: radius.h:102
RADIUS_PACKET * proxy_reply
Incoming response from proxy server.
Definition: radiusd.h:238
The module is OK, continue.
Definition: radiusd.h:91
Dictionary attribute.
Definition: dict.h:77
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
int rad_postauth(REQUEST *)
Definition: auth.c:287
void fr_pair_list_mcopy_by_num(TALLOC_CTX *ctx, VALUE_PAIR **to, VALUE_PAIR **from, unsigned int vendor, unsigned int attr, int8_t tag)
Copy / delete matching pairs between VALUE_PAIR lists.
Definition: pair.c:1823
#define PW_UKERNA_CHBIND
Definition: radius.h:222
char const * virtual_server
Definition: eap_ttls.h:38
VALUE_PAIR * username
Definition: eap_ttls.h:31
32 Bit signed integer.
Definition: radius.h:45
int default_method
Definition: eap_ttls.h:35
fr_ipaddr_t src_ipaddr
Src IP address of packet.
Definition: libradius.h:149
static int vp2diameter(REQUEST *request, tls_session_t *tls_session, VALUE_PAIR *first)
Definition: ttls.c:449
VALUE_PAIR * username
Cached username VALUE_PAIR from request RADIUS_PACKET.
Definition: radiusd.h:222
#define REQUEST_DATA_EAP_TUNNEL_CALLBACK
Definition: eap.h:109
#define REDEBUG2(fmt,...)
Definition: log.h:255
VALUE_PAIR * vps
Result of decoding the packet into VALUE_PAIRs.
Definition: libradius.h:162
IPv6 Prefix.
Definition: radius.h:41
#define pair_make_request(_a, _b, _c)
Definition: radiusd.h:545
#define EAP_HEADER_LEN
Definition: eap_types.h:35
VALUE_PAIR * fr_cursor_init(vp_cursor_t *cursor, VALUE_PAIR *const *node)
Setup a cursor to iterate over attribute pairs.
Definition: cursor.c:60
uint8_t length
Definition: proto_bfd.c:203
VALUE_PAIR * password
Cached password VALUE_PAIR from request RADIUS_PACKET.
Definition: radiusd.h:223
Definition: token.h:46
The module considers the request invalid.
Definition: radiusd.h:93
unsigned int number
Monotonically increasing request number. Reset on server restart.
Definition: radiusd.h:213
VALUE_PAIR * fr_pair_list_copy_by_num(TALLOC_CTX *ctx, VALUE_PAIR *from, unsigned int vendor, unsigned int attr, int8_t tag)
Copy matching pairs.
Definition: pair.c:1428
uint16_t dst_port
DST Port of packet.
Definition: libradius.h:152
uint16_t src_port
Src port of packet.
Definition: libradius.h:151
REQUEST * request_alloc_fake(REQUEST *oldreq)
Definition: request.c:124
VALUE_PAIR * state
Definition: eap_ttls.h:32
Abstraction to allow iterating over different configurations of VALUE_PAIRs.
Definition: pair.h:144
REQUEST * request
Request that contains the response we're processing.
Definition: eap.h:71
#define VENDORPEC_MICROSOFT
Definition: radius.h:200
RADIUS_PACKET * proxy
Outgoing request to proxy server.
Definition: radiusd.h:237
RFC2865 - Access-Reject.
Definition: radius.h:94
static VALUE_PAIR * diameter2vp(REQUEST *request, REQUEST *fake, SSL *ssl, uint8_t const *data, size_t data_len)
Definition: ttls.c:138
#define rad_assert(expr)
Definition: rad_assert.h:38
PW_CODE eap_ttls_process(eap_session_t *eap_session, tls_session_t *tls_session)
Definition: ttls.c:929
Highest priority debug messages (-x).
Definition: log.h:51
VALUE_PAIR * fr_pair_list_copy(TALLOC_CTX *ctx, VALUE_PAIR *from)
Copy a pairlist.
Definition: pair.c:1394
8 Bit unsigned integer.
Definition: radius.h:42
void fr_cursor_merge(vp_cursor_t *cursor, VALUE_PAIR *vp)
Merges multiple VALUE_PAIR into the cursor.
Definition: cursor.c:394
void fr_cursor_insert(vp_cursor_t *cursor, VALUE_PAIR *vp)
Insert a single VALUE_PAIR at the end of the list.
Definition: cursor.c:321
PW_CODE chbind_process(REQUEST *request, CHBIND_REQ *chbind)
Definition: eap_chbind.c:156
void fr_pair_add(VALUE_PAIR **head, VALUE_PAIR *vp)
Add a VP to the end of the list.
Definition: pair.c:659
int eap_tls_success(eap_session_t *eap_session)
Send an EAP-TLS success.
Definition: eap_tls.c:211
Tracks the progress of a single session of any EAP method.
Definition: eap.h:60
unsigned int attr
Attribute number.
Definition: dict.h:79
Immediately reject the request.
Definition: radiusd.h:89
unsigned int code
Packet code (type).
Definition: libradius.h:155
void * request_data_get(REQUEST *request, void *unique_ptr, int unique_int)
Get opaque data from a request.
Definition: request.c:374
VALUE_PAIR * accept_vps
Definition: eap_ttls.h:33
RFC2865 - Access-Accept.
Definition: radius.h:93
void * tls_session
Definition: eap.h:119
unsigned int vendor
Vendor that defines this attribute.
Definition: dict.h:78
Stores an attribute, a value and various bits of other data.
Definition: pair.h:112
eap_tunnel_callback_t callback
Definition: eap.h:120
RADIUS_PACKET * reply
Outgoing response.
Definition: radiusd.h:225
#define VENDORPEC_UKERNA
Definition: radius.h:203
32 Bit unsigned integer.
Definition: radius.h:34
enum rlm_rcodes rlm_rcode_t
Return codes indicating the result of the module call.
char const * fr_strerror(void)
Get the last library error.
Definition: log.c:212
#define RWDEBUG2(fmt,...)
Definition: log.h:252
chbind_packet_t * request
Definition: eap_chbind.h:47
bool authenticated
Definition: eap_ttls.h:34
void rdebug_pair_list(log_lvl_t level, REQUEST *, VALUE_PAIR *, char const *)
Print a list of VALUE_PAIRs.
Definition: pair.c:757
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
64 Bit unsigned integer.
Definition: radius.h:51
chbind_packet_t * response
Definition: eap_chbind.h:48
VALUE_PAIR * fr_pair_find_by_da(VALUE_PAIR *head, fr_dict_attr_t const *da, int8_t tag)
Find the pair with the matching DAs.
Definition: pair.c:624
#define RDEBUG2(fmt,...)
Definition: log.h:244
uint8_t data[1]
Definition: eap_chbind.h:41
void eap_ttls_gen_challenge(SSL *s, uint8_t *buffer, size_t size)
Definition: mppe_keys.c:161
uint8_t data[]
Definition: eap_pwd.h:625
chbind_packet_t * eap_chbind_vp2packet(TALLOC_CTX *ctx, VALUE_PAIR *vps)
Definition: eap_chbind.c:245
Module failed, don't reply.
Definition: radiusd.h:90
#define TAG_ANY
Definition: pair.h:191
32 Bit Unix timestamp.
Definition: radius.h:36
static const void * fake
Definition: rlm_sql_null.c:33
ssize_t fr_radius_decode_pair(TALLOC_CTX *ctx, vp_cursor_t *cursor, fr_dict_attr_t const *parent, uint8_t const *data, size_t data_len, void *decoder_ctx)
Create a "normal" VALUE_PAIR from the given data.
log_lvl_t rad_debug_lvl
Global debugging level.
Definition: log.c:49
VALUE_PAIR * fr_cursor_next(vp_cursor_t *cursor)
Advanced the cursor to the next VALUE_PAIR.
Definition: cursor.c:263
void fr_radius_free(RADIUS_PACKET **)
Free a RADIUS_PACKET.
Definition: radius.c:1727
RADIUS_PACKET * packet
Incoming request.
Definition: radiusd.h:221
RFC2865/RFC5997 - Status Server (response)
Definition: radius.h:104
int request_data_add(REQUEST *request, void *unique_ptr, int unique_int, void *opaque, bool free_on_replace, bool free_on_parent, bool persist)
Add opaque data to a REQUEST.
Definition: request.c:279
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
int eap_tls_fail(eap_session_t *eap_session)
Send an EAP-TLS failure.
Definition: eap_tls.c:254
VALUE_PAIR * username
Definition: eap_chbind.h:46
VALUE_PAIR * fr_pair_afrom_da(TALLOC_CTX *ctx, fr_dict_attr_t const *da)
Dynamically allocate a new attribute.
Definition: pair.c:58
PW_CODE
RADIUS packet codes.
Definition: radius.h:90
fr_dict_attr_t const * da
Dictionary attribute defines the attribute.
Definition: pair.h:113
void fr_pair_value_bstrncpy(VALUE_PAIR *vp, void const *src, size_t len)
Copy data into an "string" data type.
Definition: pair.c:2043
String of printable characters.
Definition: radius.h:33
PW_TYPE type
Value type.
Definition: dict.h:80
#define PW_MSCHAP2_SUCCESS
Definition: radius.h:215
static int diameter_verify(REQUEST *request, uint8_t const *data, unsigned int data_len)
Definition: ttls.c:46
#define RCSID(id)
Definition: build.h:135
int eap_tls_request(eap_session_t *eap_session)
Frames the OpenSSL data that needs to be sent to the client in an EAP-Request.
Definition: eap_tls.c:299
32 Bit IPv4 Address.
Definition: radius.h:35
The module handled the request, so stop.
Definition: radiusd.h:92
fr_dict_t * fr_dict_internal
Internal server dictionary.
Definition: dict.c:81
fr_dict_attr_t const * fr_dict_root(fr_dict_t const *dict)
Return the root attribute of a dictionary.
Definition: dict.c:2339
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 RDEBUG(fmt,...)
Definition: log.h:243
uint32_t options
mainly for proxying EAP-MSCHAPv2.
Definition: radiusd.h:304
16 Bit unsigned integer.
Definition: radius.h:43
Raw octets.
Definition: radius.h:38
void fr_pair_value_memcpy(VALUE_PAIR *vp, uint8_t const *src, size_t len)
Copy data into an "octets" data type.
Definition: pair.c:1905
char const * server
Definition: radiusd.h:289
#define REQUEST_DATA_EAP_MSCHAP_TUNNEL_CALLBACK
Definition: eap.h:110