The FreeRADIUS server  $Id: 15bac2a4c627c01d1aa2047687b3418955ac7f00 $
ttls.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: 3d9f4f3637711ad12cbd39bf532bc448a5dd6cd3 $
19  * @file ttls.c
20  * @brief Library functions for EAP-TTLS as defined by RFC 5281
21  *
22  * @copyright 2003 Alan DeKok (aland@freeradius.org)
23  * @copyright 2006 The FreeRADIUS server project
24  */
25 
26 RCSID("$Id: 3d9f4f3637711ad12cbd39bf532bc448a5dd6cd3 $")
27 
28 #include <freeradius-devel/eap/chbind.h>
29 #include <freeradius-devel/tls/log.h>
30 #include <freeradius-devel/tls/strerror.h>
31 #include "eap_ttls.h"
32 
33 #define FR_DIAMETER_AVP_FLAG_VENDOR 0x80
34 #define FR_DIAMETER_AVP_FLAG_MANDATORY 0x40
35 /*
36  * 0 1 2 3
37  * 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
38  * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
39  * | AVP Code |
40  * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
41  * |V M r r r r r r| AVP Length |
42  * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
43  * | Vendor-ID (opt) |
44  * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
45  * | Data ...
46  * +-+-+-+-+-+-+-+-+
47  */
48 
49 /*
50  * Verify that the diameter packet is valid.
51  */
52 static int diameter_verify(request_t *request, uint8_t const *data, unsigned int data_len)
53 {
54  uint32_t attr;
55  uint32_t length;
56  unsigned int hdr_len;
57  unsigned int remaining = data_len;
58 
59  while (remaining > 0) {
60  hdr_len = 12;
61 
62  if (remaining < hdr_len) {
63  RDEBUG2("Diameter attribute is too small (%u) to contain a Diameter header", remaining);
64  return 0;
65  }
66 
67  memcpy(&attr, data, sizeof(attr));
68  attr = ntohl(attr);
69  memcpy(&length, data + 4, sizeof(length));
70  length = ntohl(length);
71 
72  if ((data[4] & 0x80) != 0) {
73  if (remaining < 16) {
74  RDEBUG2("Diameter attribute is too small to contain a Diameter header with Vendor-Id");
75  return 0;
76  }
77 
78  hdr_len = 16;
79  }
80 
81  /*
82  * Get the length. If it's too big, die.
83  */
84  length &= 0x00ffffff;
85 
86  /*
87  * Too short or too long is bad.
88  */
89  if (length <= (hdr_len - 4)) {
90  RDEBUG2("Tunneled attribute %u is too short (%u < %u) to contain anything useful.", attr,
91  length, hdr_len);
92  return 0;
93  }
94 
95  if (length > remaining) {
96  RDEBUG2("Tunneled attribute %u is longer than room remaining in the packet (%u > %u).", attr,
97  length, remaining);
98  return 0;
99  }
100 
101  /*
102  * Check for broken implementations, which don't
103  * pad the AVP to a 4-octet boundary.
104  */
105  if (remaining == length) break;
106 
107  /*
108  * The length does NOT include the padding, so
109  * we've got to account for it here by rounding up
110  * to the nearest 4-byte boundary.
111  */
112  length += 0x03;
113  length &= ~0x03;
114 
115  /*
116  * If the rest of the diameter packet is larger than
117  * this attribute, continue.
118  *
119  * Otherwise, if the attribute over-flows the end
120  * of the packet, die.
121  */
122  if (remaining < length) {
123  REDEBUG2("Diameter attribute overflows packet!");
124  return 0;
125  }
126 
127  /*
128  * remaining > length, continue.
129  */
130  remaining -= length;
131  data += length;
132  }
133 
134  /*
135  * We got this far. It looks OK.
136  */
137  return 1;
138 }
139 
140 
141 /*
142  * Convert diameter attributes to our fr_pair_t's
143  */
144 static ssize_t eap_ttls_decode_pair(request_t *request, TALLOC_CTX *ctx, fr_dcursor_t *cursor,
145  fr_dict_attr_t const *parent,
146  uint8_t const *data, size_t data_len,
147  void *decode_ctx)
148 {
149  uint8_t const *p = data, *end = p + data_len;
150 
151  fr_pair_t *vp = NULL;
152  SSL *ssl = decode_ctx;
153  fr_dict_t const *dict_radius;
154  fr_dict_attr_t const *attr_radius;
155  fr_dict_attr_t const *da;
156  TALLOC_CTX *tmp_ctx = NULL;
157 
159  fr_assert(dict_radius != NULL);
160  attr_radius = fr_dict_root(dict_radius);
161 
162  while (p < end) {
163  ssize_t ret;
164  uint32_t attr, vendor;
165  uint64_t value_len;
166  uint8_t flags;
167  fr_dict_attr_t const *our_parent = parent;
168 
169  if ((end - p) < 8) {
170  fr_strerror_printf("Malformed diameter attribute at offset %zu. Needed at least 8 bytes, got %zu bytes",
171  p - data, end - p);
172  error:
173  talloc_free(tmp_ctx);
174  fr_dcursor_free_list(cursor);
175  return -1;
176  }
177 
178  RDEBUG3("%04zu %02x%02x%02x%02x %02x%02x%02x%02x ...", p - data,
179  p[0], p[1], p[2], p[3], p[4], p[5], p[6], p[7]);
180 
181  attr = fr_nbo_to_uint32(p);
182  p += 4;
183 
184  flags = p[0];
185  p++;
186 
187  value_len = fr_nbo_to_uint64v(p, 3); /* Yes, that is a 24 bit length field */
188  p += 3;
189 
190  if (value_len < 8) {
191  fr_strerror_printf("Malformed diameter attribute at offset %zu. Needed at least length of 8, got %u",
192  p - data, (unsigned int) value_len);
193  goto error;
194  }
195 
196  /*
197  * Account for the 8 bytes we've already read from the packet.
198  */
199  if ((p + ((value_len + 0x03) & ~0x03)) - 8 > end) {
200  fr_strerror_printf("Malformed diameter attribute at offset %zu. Value length %u overflows input",
201  p - data, (unsigned int) value_len);
202  goto error;
203  }
204 
205  value_len -= 8; /* -= 8 for AVP code (4), flags (1), AVP length (3) */
206 
207  MEM(vp = fr_pair_alloc_null(ctx));
208 
209  /*
210  * Do we have a vendor field?
211  */
212  if (flags & FR_DIAMETER_AVP_FLAG_VENDOR) {
213  vendor = fr_nbo_to_uint32(p);
214  p += 4;
215  value_len -= 4; /* -= 4 for the vendor ID field */
216 
217  our_parent = fr_dict_vendor_da_by_num(attr_vendor_specific, vendor);
218  if (!our_parent) {
219  if (flags & FR_DIAMETER_AVP_FLAG_MANDATORY) {
220  fr_strerror_printf("Mandatory bit set and no vendor %u found", vendor);
221  talloc_free(vp);
222  goto error;
223  }
224 
225  if (!tmp_ctx) {
226  fr_dict_attr_t *n;
227 
228  MEM(our_parent = n = fr_dict_unknown_vendor_afrom_num(ctx, parent, vendor));
229  tmp_ctx = n;
230  } else {
231  MEM(our_parent = fr_dict_unknown_vendor_afrom_num(tmp_ctx, parent, vendor));
232  }
233  }
234  } else {
235  our_parent = attr_radius;
236  }
237 
238  /*
239  * Is the attribute known?
240  */
241  da = fr_dict_attr_child_by_num(our_parent, attr);
242  if (da) {
243  goto reinit;
244 
245  } else {
246  if (flags & FR_DIAMETER_AVP_FLAG_MANDATORY) {
247  fr_strerror_printf("Mandatory bit set and no attribute %u defined for parent %s", attr, parent->name);
248  talloc_free(vp);
249  goto error;
250  }
251 
252  MEM(da = fr_dict_unknown_attr_afrom_num(vp, our_parent, attr));
253 
254  reinit:
255  if (fr_pair_reinit_from_da(NULL, vp, da) < 0) {
256  talloc_free(vp);
257  goto error;
258  }
259  }
260 
261  ret = fr_value_box_from_network(vp, &vp->data, vp->vp_type, vp->da,
262  &FR_DBUFF_TMP(p, (size_t)value_len), value_len, true);
263  if (ret < 0) {
264  /*
265  * Mandatory bit is set, and the attribute
266  * is malformed. Fail.
267  */
268  if (flags & FR_DIAMETER_AVP_FLAG_MANDATORY) {
269  fr_strerror_const("Mandatory bit is set and attribute is malformed");
270  talloc_free(vp);
271  goto error;
272  }
273 
274  fr_pair_raw_afrom_pair(vp, p, value_len);
275  }
276 
277  /*
278  * The length does NOT include the padding, so
279  * we've got to account for it here by rounding up
280  * to the nearest 4-byte boundary.
281  */
282  p += (value_len + 0x03) & ~0x03;
283  fr_dcursor_append(cursor, vp);
284 
285  if (vp->da->flags.is_unknown) continue;
286 
287  /*
288  * Ensure that the client is using the correct challenge.
289  *
290  * This weirdness is to protect against against replay
291  * attacks, where anyone observing the CHAP exchange could
292  * pose as that user, by simply choosing to use the same
293  * challenge.
294  * By using a challenge based on information from the
295  * current session, we can guarantee that the client is
296  * not *choosing* a challenge. We're a little forgiving in
297  * that we have loose checks on the length, and we do NOT
298  * check the Id (first octet of the response to the
299  * challenge) But if the client gets the challenge correct,
300  * we're not too worried about the Id.
301  */
302  if ((vp->da == attr_chap_challenge) || (vp->da == attr_ms_chap_challenge)) {
303  uint8_t challenge[17];
304  static const char label[] = "ttls challenge";
305 
306  if ((vp->vp_length < 8) || (vp->vp_length > 16)) {
307  fr_strerror_const("Tunneled challenge has invalid length");
308  goto error;
309  }
310 
311  /*
312  * TLSv1.3 exports a different key depending on the length
313  * requested so ask for *exactly* what the spec requires
314  */
315  if (SSL_export_keying_material(ssl, challenge, vp->vp_length + 1,
316  label, sizeof(label) - 1, NULL, 0, 0) != 1) {
317  fr_tls_strerror_printf("Failed generating phase2 challenge");
318  goto error;
319  }
320 
321  if (memcmp(challenge, vp->vp_octets, vp->vp_length) != 0) {
322  fr_strerror_const("Tunneled challenge is incorrect");
323  goto error;
324  }
325  }
326 
327  /*
328  * Diameter pads strings (i.e. User-Password) with trailing zeros.
329  */
330  if (vp->vp_type == FR_TYPE_STRING) fr_pair_value_strdup(vp, vp->vp_strvalue, vp->vp_tainted);
331  }
332 
333  /*
334  * We got this far. It looks OK.
335  */
336  talloc_free(tmp_ctx);
337  return p - data;
338 }
339 
340 /*
341  * Convert fr_pair_t's to diameter attributes, and write them
342  * to an SSL session.
343  *
344  * The ONLY fr_pair_t's which may be passed to this function
345  * are ones which can go inside of a RADIUS (i.e. diameter)
346  * packet. So no server-configuration attributes, or the like.
347  */
348 static int vp2diameter(request_t *request, fr_tls_session_t *tls_session, fr_pair_list_t *list)
349 {
350  /*
351  * RADIUS packets are no more than 4k in size, so if
352  * we've got more than 4k of data to write, it's very
353  * bad.
354  */
355  uint8_t buffer[4096];
356  uint8_t *p;
357  uint32_t attr;
358  uint32_t length;
359  uint32_t vendor;
360  size_t total;
361  uint64_t attr64;
362  fr_pair_t *vp;
363 
364  p = buffer;
365  total = 0;
366 
367  for (vp = fr_pair_list_head(list);
368  vp;
369  vp = fr_pair_list_next(list, vp)) {
370  /*
371  * Too much data: die.
372  */
373  if ((total + vp->vp_length + 12) >= sizeof(buffer)) {
374  RDEBUG2("output buffer is full!");
375  return 0;
376  }
377 
378  /*
379  * Hmm... we don't group multiple EAP-Messages
380  * together. Maybe we should...
381  */
382 
383  length = vp->vp_length;
384  vendor = fr_dict_vendor_num_by_da(vp->da);
385  if (vendor != 0) {
386  attr = vp->da->attr & 0xffff;
387  length |= ((uint32_t)1 << 31);
388  } else {
389  attr = vp->da->attr;
390  }
391 
392  /*
393  * Hmm... set the M bit for all attributes?
394  */
395  length |= (1 << 30);
396 
397  attr = ntohl(attr);
398 
399  memcpy(p, &attr, sizeof(attr));
400  p += 4;
401  total += 4;
402 
403  length += 8; /* includes 8 bytes of attr & length */
404 
405  if (vendor != 0) {
406  length += 4; /* include 4 bytes of vendor */
407 
408  length = ntohl(length);
409  memcpy(p, &length, sizeof(length));
410  p += 4;
411  total += 4;
412 
413  vendor = ntohl(vendor);
414  memcpy(p, &vendor, sizeof(vendor));
415  p += 4;
416  total += 4;
417  } else {
418  length = ntohl(length);
419  memcpy(p, &length, sizeof(length));
420  p += 4;
421  total += 4;
422  }
423 
424  switch (vp->vp_type) {
425  case FR_TYPE_DATE:
426  attr = htonl(fr_unix_time_to_sec(vp->vp_date)); /* stored in host order */
427  memcpy(p, &attr, sizeof(attr));
428  length = 4;
429  break;
430 
431  case FR_TYPE_UINT32:
432  attr = htonl(vp->vp_uint32); /* stored in host order */
433  memcpy(p, &attr, sizeof(attr));
434  length = 4;
435  break;
436 
437  case FR_TYPE_UINT64:
438  attr64 = htonll(vp->vp_uint64); /* stored in host order */
439  memcpy(p, &attr64, sizeof(attr64));
440  length = 8;
441  break;
442 
443  case FR_TYPE_IPV4_ADDR:
444  memcpy(p, &vp->vp_ipv4addr, 4); /* network order */
445  length = 4;
446  break;
447 
448  case FR_TYPE_STRING:
449  case FR_TYPE_OCTETS:
450  default:
451  memcpy(p, vp->vp_strvalue, vp->vp_length);
452  length = vp->vp_length;
453  break;
454  }
455 
456  /*
457  * Skip to the end of the data.
458  */
459  p += length;
460  total += length;
461 
462  /*
463  * Align the data to a multiple of 4 bytes.
464  */
465  if ((total & 0x03) != 0) {
466  size_t i;
467 
468  length = 4 - (total & 0x03);
469  for (i = 0; i < length; i++) {
470  *p = '\0';
471  p++;
472  total++;
473  }
474  }
475  } /* loop over the VP's to write. */
476 
477  /*
478  * Write the data in the buffer to the SSL session.
479  */
480  if (total > 0) {
481  (tls_session->record_from_buff)(&tls_session->clean_in, buffer, total);
482 
483  /*
484  * FIXME: Check the return code.
485  */
486  fr_tls_session_send(request, tls_session);
487  }
488 
489  /*
490  * Everything's OK.
491  */
492  return 1;
493 }
494 
495 /*
496  * Use a reply packet to determine what to do.
497  */
498 static rlm_rcode_t CC_HINT(nonnull) process_reply(NDEBUG_UNUSED eap_session_t *eap_session, fr_tls_session_t *tls_session,
499  request_t *request,
500  fr_packet_t *reply, fr_pair_list_t *reply_list)
501 {
503  fr_pair_t *vp;
504  fr_pair_list_t tunnel_vps;
505 
506  ttls_tunnel_t *t = tls_session->opaque;
507 
508  fr_pair_list_init(&tunnel_vps);
509  fr_assert(eap_session->request == request);
510 
511  /*
512  * If the response packet was Access-Accept, then
513  * we're OK. If not, die horribly.
514  *
515  * FIXME: Take MS-CHAP2-Success attribute, and
516  * tunnel it back to the client, to authenticate
517  * ourselves to the client.
518  *
519  * FIXME: If we have an Access-Challenge, then
520  * the Reply-Message is tunneled back to the client.
521  *
522  * FIXME: If we have an EAP-Message, then that message
523  * must be tunneled back to the client.
524  *
525  * FIXME: If we have an Access-Challenge with a State
526  * attribute, then do we tunnel that to the client, or
527  * keep track of it ourselves?
528  *
529  * FIXME: EAP-Messages can only start with 'identity',
530  * NOT 'eap start', so we should check for that....
531  */
532  switch (reply->code) {
534  {
535  RDEBUG2("Got tunneled Access-Accept");
536 
537  rcode = RLM_MODULE_OK;
538 
539  /*
540  * Copy what we need into the TTLS tunnel and leave
541  * the rest to be cleaned up.
542  */
543  for (vp = fr_pair_list_head(reply_list);
544  vp;
545  vp = fr_pair_list_next(reply_list, vp)) {
546  if (vp->da == attr_ms_chap2_success) {
547  RDEBUG2("Got MS-CHAP2-Success, tunneling it to the client in a challenge");
548 
549  rcode = RLM_MODULE_HANDLED;
550  t->authenticated = true;
551  fr_pair_prepend(&tunnel_vps, fr_pair_copy(tls_session, vp));
552  } else if (vp->da == attr_eap_channel_binding_message) {
553  rcode = RLM_MODULE_HANDLED;
554  t->authenticated = true;
555  fr_pair_prepend(&tunnel_vps, fr_pair_copy(tls_session, vp));
556  }
557  }
558  }
559  break;
560 
562  REDEBUG("Got tunneled Access-Reject");
563  rcode = RLM_MODULE_REJECT;
564  break;
565 
566  /*
567  * Handle Access-Challenge, but only if we
568  * send tunneled reply data. This is because
569  * an Access-Challenge means that we MUST tunnel
570  * a Reply-Message to the client.
571  */
573  RDEBUG2("Got tunneled Access-Challenge");
574 
575  /*
576  * Copy what we need into the TTLS tunnel and leave
577  * the rest to be cleaned up.
578  */
579  for (vp = fr_pair_list_head(reply_list);
580  vp;
581  vp = fr_pair_list_next(reply_list, vp)) {
582  if ((vp->da == attr_eap_message) || (vp->da == attr_reply_message)) {
583  fr_pair_prepend(&tunnel_vps, fr_pair_copy(tls_session, vp));
584  } else if (vp->da == attr_eap_channel_binding_message) {
585  fr_pair_prepend(&tunnel_vps, fr_pair_copy(tls_session, vp));
586  }
587  }
588  rcode = RLM_MODULE_HANDLED;
589  break;
590 
591  default:
592  REDEBUG("Unknown RADIUS packet type %d: rejecting tunneled user", reply->code);
593  rcode = RLM_MODULE_INVALID;
594  break;
595  }
596 
597 
598  /*
599  * Pack any tunneled VPs and send them back
600  * to the supplicant.
601  */
602  if (!fr_pair_list_empty(&tunnel_vps)) {
603  RDEBUG2("Sending tunneled reply attributes");
604  log_request_pair_list(L_DBG_LVL_2, request, NULL, &tunnel_vps, NULL);
605 
606  vp2diameter(request, tls_session, &tunnel_vps);
607  fr_pair_list_free(&tunnel_vps);
608  }
609 
610  return rcode;
611 }
612 
613 
614 /*
615  * Process the "diameter" contents of the tunneled data.
616  */
617 fr_radius_packet_code_t eap_ttls_process(request_t *request, eap_session_t *eap_session, fr_tls_session_t *tls_session)
618 {
620  rlm_rcode_t rcode;
621  fr_pair_t *vp = NULL;
622  fr_dcursor_t cursor;
623  ttls_tunnel_t *t;
624  uint8_t const *data;
625  size_t data_len;
626  chbind_packet_t *chbind;
628 
629  /*
630  * Just look at the buffer directly, without doing
631  * record_to_buff.
632  */
633  data_len = tls_session->clean_out.used;
634  tls_session->clean_out.used = 0;
635  data = tls_session->clean_out.data;
636 
637  t = (ttls_tunnel_t *) tls_session->opaque;
638 
639  /*
640  * If there's no data, maybe this is an ACK to an
641  * MS-CHAP2-Success.
642  */
643  if (data_len == 0) {
644  if (t->authenticated) {
645  RDEBUG2("Got ACK, and the user was already authenticated");
647  goto finish;
648  } /* else no session, no data, die. */
649 
650  /*
651  * FIXME: Call SSL_get_error() to see what went
652  * wrong.
653  */
654  RDEBUG2("SSL_read Error");
656  goto finish;
657  }
658 
659  if (!diameter_verify(request, data, data_len)) {
661  goto finish;
662  }
663 
664  /*
665  * Add the tunneled attributes to the request request.
666  */
667  fr_pair_dcursor_init(&cursor, &request->request_pairs);
668  if (eap_ttls_decode_pair(request, request->request_ctx, &cursor, fr_dict_root(fr_dict_internal()),
669  data, data_len, tls_session->ssl) < 0) {
670  RPEDEBUG("Decoding TTLS TLVs failed");
672  goto finish;
673  }
674 
675  /*
676  * Update other items in the request_t data structure.
677  */
678 
679  /*
680  * No User-Name, try to create one from stored data.
681  */
682  username = fr_pair_find_by_da(&request->request_pairs, NULL, attr_user_name);
683  if (!username) {
684  /*
685  * No User-Name in the stored data, look for
686  * an EAP-Identity, and pull it out of there.
687  */
688  if (!t->username) {
689  vp = fr_pair_find_by_da(&request->request_pairs, NULL, attr_eap_message);
690  if (vp &&
691  (vp->vp_length >= EAP_HEADER_LEN + 2) &&
692  (vp->vp_strvalue[0] == FR_EAP_CODE_RESPONSE) &&
693  (vp->vp_strvalue[EAP_HEADER_LEN] == FR_EAP_METHOD_IDENTITY) &&
694  (vp->vp_strvalue[EAP_HEADER_LEN + 1] != 0)) {
695  /*
696  * Create & remember a User-Name
697  */
699  t->username->vp_tainted = true;
700 
702  (char const *)vp->vp_octets + 5, vp->vp_length - 5, true);
703 
704  RDEBUG2("Got tunneled identity of %pV", &t->username->data);
705  } else {
706  /*
707  * Don't reject the request outright,
708  * as it's permitted to do EAP without
709  * user-name.
710  */
711  RWDEBUG2("No EAP-Identity found to start EAP conversation");
712  }
713  } /* else there WAS a t->username */
714 
715  if (t->username) {
716  vp = fr_pair_copy(request->request_ctx, t->username);
717  fr_pair_append(&request->request_pairs, vp);
718  }
719  } /* else the request ALREADY had a User-Name */
720 
721  /*
722  * Process channel binding.
723  */
724  chbind = eap_chbind_vp2packet(request, &request->request_pairs);
725  if (chbind) {
726  fr_radius_packet_code_t chbind_code;
727  CHBIND_REQ *req = talloc_zero(request, CHBIND_REQ);
728 
729  RDEBUG2("received chbind request");
730  req->request = chbind;
731  if (username) {
732  req->username = username;
733  } else {
734  req->username = NULL;
735  }
736  chbind_code = chbind_process(request, req);
737 
738  /* encapsulate response here */
739  if (req->response) {
740  RDEBUG2("sending chbind response");
741  fr_pair_append(&request->reply_pairs,
742  eap_chbind_packet2vp(request->reply_ctx, req->response));
743  } else {
744  RDEBUG2("no chbind response");
745  }
746 
747  /* clean up chbind req */
748  talloc_free(req);
749 
750  if (chbind_code != FR_RADIUS_CODE_ACCESS_ACCEPT) {
751  code = chbind_code;
752  goto finish;
753  }
754  }
755 
756  /*
757  * Call authentication recursively, which will
758  * do PAP, CHAP, MS-CHAP, etc.
759  */
760  eap_virtual_server(request, eap_session, t->virtual_server);
761 
762  /*
763  * Decide what to do with the reply.
764  */
765  if (!request->reply->code) {
766  RDEBUG2("No tunneled reply was found for request %" PRIu64 ", and the request was not "
767  "proxied: rejecting the user", request->number);
769  } else {
770  /*
771  * Returns RLM_MODULE_FOO, and we want to return FR_FOO
772  */
773  rcode = process_reply(eap_session, tls_session, request, request->reply, &request->reply_pairs);
774  switch (rcode) {
775  case RLM_MODULE_REJECT:
777  break;
778 
779  case RLM_MODULE_HANDLED:
781  break;
782 
783  case RLM_MODULE_OK:
785  break;
786 
787  default:
789  break;
790  }
791  }
792 
793 finish:
794  return code;
795 }
static int const char char buffer[256]
Definition: acutest.h:574
int n
Definition: acutest.h:577
#define RCSID(id)
Definition: build.h:444
#define NDEBUG_UNUSED
Definition: build.h:324
fr_radius_packet_code_t chbind_process(request_t *request, CHBIND_REQ *chbind)
Definition: chbind.c:169
chbind_packet_t * eap_chbind_vp2packet(TALLOC_CTX *ctx, fr_pair_list_t *vps)
Definition: chbind.c:268
fr_pair_t * eap_chbind_packet2vp(TALLOC_CTX *ctx, chbind_packet_t *chbind)
Definition: chbind.c:313
chbind_packet_t * response
Definition: chbind.h:49
fr_pair_t * username
Definition: chbind.h:47
chbind_packet_t * request
Definition: chbind.h:48
#define FR_DBUFF_TMP(_start, _len_or_end)
Creates a compound literal to pass into functions which accept a dbuff.
Definition: dbuff.h:509
static int fr_dcursor_append(fr_dcursor_t *cursor, void *v)
Insert a single item at the end of the list.
Definition: dcursor.h:405
static void fr_dcursor_free_list(fr_dcursor_t *cursor)
Free the current item and all items after it.
Definition: dcursor.h:659
fr_radius_packet_code_t
RADIUS packet codes.
Definition: defs.h:31
@ FR_RADIUS_CODE_ACCESS_CHALLENGE
RFC2865 - Access-Challenge.
Definition: defs.h:43
@ 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 * fr_dict_vendor_da_by_num(fr_dict_attr_t const *vendor_root, uint32_t vendor_pen)
Return vendor attribute for the specified dictionary and pen.
Definition: dict_util.c:2292
fr_dict_t const * fr_dict_by_protocol_name(char const *name)
Lookup a protocol by its name.
Definition: dict_util.c:2174
fr_dict_attr_t const * fr_dict_root(fr_dict_t const *dict)
Return the root attribute of a dictionary.
Definition: dict_util.c:1997
fr_dict_attr_t * fr_dict_unknown_vendor_afrom_num(TALLOC_CTX *ctx, fr_dict_attr_t const *parent, unsigned int vendor))
Build an unknown vendor, parented by a VSA attribute.
Definition: dict_unknown.c:272
fr_dict_t const * fr_dict_internal(void)
Definition: dict_util.c:4204
fr_dict_attr_t const * fr_dict_attr_child_by_num(fr_dict_attr_t const *parent, unsigned int attr)
Check if a child attribute exists in a parent using an attribute number.
Definition: dict_util.c:2925
fr_dict_attr_t * fr_dict_unknown_attr_afrom_num(TALLOC_CTX *ctx, fr_dict_attr_t const *parent, unsigned int num))
Initialise a fr_dict_attr_t from a number.
Definition: dict_unknown.c:345
static uint32_t fr_dict_vendor_num_by_da(fr_dict_attr_t const *da)
Return the vendor number for an attribute.
Definition: dict_ext.h:182
@ FR_EAP_CODE_RESPONSE
Definition: types.h:38
#define EAP_HEADER_LEN
Definition: types.h:34
@ FR_EAP_METHOD_IDENTITY
Definition: types.h:46
Declarations for EAP-TTLS as defined by RFC 5281.
fr_pair_t * username
Definition: eap_ttls.h:46
bool authenticated
Definition: eap_ttls.h:47
HIDDEN fr_dict_attr_t const * attr_reply_message
Definition: rlm_eap_ttls.c:94
char const * virtual_server
Definition: eap_ttls.h:48
HIDDEN fr_dict_attr_t const * attr_eap_channel_binding_message
Definition: base.c:89
HIDDEN fr_dict_attr_t const * attr_eap_message
Definition: base.c:90
rlm_rcode_t eap_virtual_server(UNUSED request_t *request, UNUSED eap_session_t *eap_session, UNUSED char const *virtual_server)
Run a subrequest through a virtual server, managing the eap_session_t of the child.
Definition: base.c:401
Tracks the progress of a single session of any EAP method.
Definition: session.h:40
void log_request_pair_list(fr_log_lvl_t lvl, request_t *request, fr_pair_t const *parent, fr_pair_list_t const *vps, char const *prefix)
Print a fr_pair_list_t.
Definition: log.c:821
#define RDEBUG3(fmt,...)
Definition: log.h:343
#define RWDEBUG2(fmt,...)
Definition: log.h:362
#define RPEDEBUG(fmt,...)
Definition: log.h:376
#define REDEBUG2(fmt,...)
Definition: log.h:372
talloc_free(reap)
@ L_DBG_LVL_2
2nd highest priority debug messages (-xx | -X).
Definition: log.h:71
@ FR_TYPE_IPV4_ADDR
32 Bit IPv4 Address.
Definition: merged_model.c:86
@ FR_TYPE_STRING
String of printable characters.
Definition: merged_model.c:83
@ FR_TYPE_DATE
Unix time stamp, always has value >2^31.
Definition: merged_model.c:111
@ FR_TYPE_UINT32
32 Bit unsigned integer.
Definition: merged_model.c:99
@ FR_TYPE_UINT64
64 Bit unsigned integer.
Definition: merged_model.c:100
@ FR_TYPE_OCTETS
Raw octets.
Definition: merged_model.c:84
unsigned int uint32_t
Definition: merged_model.c:33
long int ssize_t
Definition: merged_model.c:24
unsigned char uint8_t
Definition: merged_model.c:30
static uint64_t fr_nbo_to_uint64v(uint8_t const *data, size_t data_len)
Read an unsigned 64bit integer from wire format (big endian) with a variable length encoding.
Definition: nbo.h:187
static uint32_t fr_nbo_to_uint32(uint8_t const data[static sizeof(uint32_t)])
Read an unsigned 32bit integer from wire format (big endian)
Definition: nbo.h:158
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
fr_pair_t * fr_pair_alloc_null(TALLOC_CTX *ctx)
Dynamically allocate a new attribute with no fr_dict_attr_t assigned.
Definition: pair.c:167
fr_pair_t * fr_pair_afrom_da(TALLOC_CTX *ctx, fr_dict_attr_t const *da)
Dynamically allocate a new attribute and assign a fr_dict_attr_t.
Definition: pair.c:278
int fr_pair_value_strdup(fr_pair_t *vp, char const *src, bool tainted)
Copy data into an "string" data type.
Definition: pair.c:2631
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
void fr_pair_list_init(fr_pair_list_t *list)
Initialise a pair list header.
Definition: pair.c:46
int fr_pair_value_bstrndup(fr_pair_t *vp, char const *src, size_t len, bool tainted)
Copy data into a "string" type value pair.
Definition: pair.c:2781
int fr_pair_reinit_from_da(fr_pair_list_t *list, fr_pair_t *vp, fr_dict_attr_t const *da)
Re-initialise an attribute with a different da.
Definition: pair.c:309
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_prepend(fr_pair_list_t *list, fr_pair_t *to_add)
Add a VP to the start of the list.
Definition: pair.c:1309
int fr_pair_raw_afrom_pair(fr_pair_t *vp, uint8_t const *data, size_t data_len)
Mark malformed attribute as raw.
Definition: pair.c:588
static fr_dict_t const * dict_radius
Definition: radclient-ng.c:102
static fr_dict_attr_t const * attr_ms_chap_challenge
Definition: radclient-ng.c:115
static fr_dict_attr_t const * attr_chap_challenge
Definition: radclient-ng.c:123
static fr_dict_attr_t const * attr_user_name
Definition: radclient-ng.c:125
#define REDEBUG(fmt,...)
Definition: radclient.h:52
#define RDEBUG2(fmt,...)
Definition: radclient.h:54
static fr_dict_attr_t const * attr_vendor_specific
Definition: radsnmp.c:113
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_REJECT
Immediately reject the request.
Definition: rcode.h:41
@ RLM_MODULE_HANDLED
The module handled the request, so stop.
Definition: rcode.h:44
static fr_dict_attr_t const * attr_ms_chap2_success
username
Definition: rlm_securid.c:420
if(!subtype_vp) goto fail
fr_assert(0)
MEM(pair_append_request(&vp, attr_eap_aka_sim_identity) >=0)
fr_pair_t * vp
Stores an attribute, a value and various bits of other data.
Definition: pair.h:68
fr_dict_attr_t const *_CONST da
Dictionary attribute defines the attribute number, vendor and type of the pair.
Definition: pair.h:69
static int64_t fr_unix_time_to_sec(fr_unix_time_t delta)
Definition: time.h:504
#define FR_DIAMETER_AVP_FLAG_MANDATORY
Definition: ttls.c:34
static rlm_rcode_t process_reply(NDEBUG_UNUSED eap_session_t *eap_session, fr_tls_session_t *tls_session, request_t *request, fr_packet_t *reply, fr_pair_list_t *reply_list)
Definition: ttls.c:498
fr_radius_packet_code_t eap_ttls_process(request_t *request, eap_session_t *eap_session, fr_tls_session_t *tls_session)
Definition: ttls.c:617
static int vp2diameter(request_t *request, fr_tls_session_t *tls_session, fr_pair_list_t *list)
Definition: ttls.c:348
static int diameter_verify(request_t *request, uint8_t const *data, unsigned int data_len)
Definition: ttls.c:52
static ssize_t eap_ttls_decode_pair(request_t *request, TALLOC_CTX *ctx, fr_dcursor_t *cursor, fr_dict_attr_t const *parent, uint8_t const *data, size_t data_len, void *decode_ctx)
Definition: ttls.c:144
#define FR_DIAMETER_AVP_FLAG_VENDOR
Definition: ttls.c:33
unsigned int code
Packet code (type).
Definition: packet.h:61
fr_pair_t * fr_pair_list_head(fr_pair_list_t const *list)
Get the head of a valuepair list.
Definition: pair_inline.c:43
bool fr_pair_list_empty(fr_pair_list_t const *list)
Is a valuepair list empty.
Definition: pair_inline.c:125
fr_pair_t * fr_pair_list_next(fr_pair_list_t const *list, fr_pair_t const *item))
Get the next item in a valuepair list after a specific entry.
Definition: pair_inline.c:70
void fr_pair_list_free(fr_pair_list_t *list)
Free memory used by a valuepair list.
Definition: pair_inline.c:113
#define fr_pair_dcursor_init(_cursor, _list)
Initialises a special dcursor with callbacks that will maintain the attr sublists correctly.
Definition: pair.h:590
static fr_slen_t parent
Definition: pair.h:844
#define fr_strerror_printf(_fmt,...)
Log to thread local error buffer.
Definition: strerror.h:64
#define fr_strerror_const(_msg)
Definition: strerror.h:223
ssize_t fr_value_box_from_network(TALLOC_CTX *ctx, fr_value_box_t *dst, fr_type_t type, fr_dict_attr_t const *enumv, fr_dbuff_t *dbuff, size_t len, bool tainted)
Decode a fr_value_box_t from serialized binary data.
Definition: value.c:1709
static fr_slen_t data
Definition: value.h:1259
int nonnull(2, 5))