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: bd03c3da7b326b618cc5b029422639659d2c33e4 $
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: bd03c3da7b326b618cc5b029422639659d2c33e4 $")
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_pair_list_t *out,
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);
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  /*
208  * Do we have a vendor field?
209  */
210  if (flags & FR_DIAMETER_AVP_FLAG_VENDOR) {
211  vendor = fr_nbo_to_uint32(p);
212  p += 4;
213  value_len -= 4; /* -= 4 for the vendor ID field */
214 
215  our_parent = fr_dict_vendor_da_by_num(attr_vendor_specific, vendor);
216  if (!our_parent) {
217  if (flags & FR_DIAMETER_AVP_FLAG_MANDATORY) {
218  fr_strerror_printf("Mandatory bit set and no vendor %u found", vendor);
219  goto error;
220  }
221 
222  if (!tmp_ctx) {
223  fr_dict_attr_t *n;
224 
225  MEM(our_parent = n = fr_dict_attr_unknown_vendor_afrom_num(ctx, parent, vendor));
226  tmp_ctx = n;
227  } else {
228  MEM(our_parent = fr_dict_attr_unknown_vendor_afrom_num(tmp_ctx, parent, vendor));
229  }
230  }
231  } else {
232  our_parent = attr_radius;
233  }
234 
235  /*
236  * Is the attribute known?
237  */
238  da = fr_dict_attr_child_by_num(our_parent, attr);
239  if (!da) {
240  if (flags & FR_DIAMETER_AVP_FLAG_MANDATORY) {
241  fr_strerror_printf("Mandatory bit set and no attribute %u defined for parent %s", attr, parent->name);
242  goto error;
243  }
244 
245  MEM(da = fr_dict_attr_unknown_raw_afrom_num(vp, our_parent, attr));
246  }
247 
248  MEM(vp =fr_pair_afrom_da_nested(ctx, out, da));
249 
250  ret = fr_value_box_from_network(vp, &vp->data, vp->vp_type, vp->da,
251  &FR_DBUFF_TMP(p, (size_t)value_len), value_len, true);
252  if (ret < 0) {
253  /*
254  * Mandatory bit is set, and the attribute
255  * is malformed. Fail.
256  */
257  if (flags & FR_DIAMETER_AVP_FLAG_MANDATORY) {
258  fr_strerror_const("Mandatory bit is set and attribute is malformed");
259  goto error;
260  }
261 
262  fr_pair_raw_afrom_pair(vp, p, value_len);
263  }
264 
265  /*
266  * The length does NOT include the padding, so
267  * we've got to account for it here by rounding up
268  * to the nearest 4-byte boundary.
269  */
270  p += (value_len + 0x03) & ~0x03;
271 
272  if (vp->da->flags.is_unknown) continue;
273 
274  /*
275  * Ensure that the client is using the correct challenge.
276  *
277  * This weirdness is to protect against against replay
278  * attacks, where anyone observing the CHAP exchange could
279  * pose as that user, by simply choosing to use the same
280  * challenge.
281  * By using a challenge based on information from the
282  * current session, we can guarantee that the client is
283  * not *choosing* a challenge. We're a little forgiving in
284  * that we have loose checks on the length, and we do NOT
285  * check the Id (first octet of the response to the
286  * challenge) But if the client gets the challenge correct,
287  * we're not too worried about the Id.
288  */
289  if ((vp->da == attr_chap_challenge) || (vp->da == attr_ms_chap_challenge)) {
290  uint8_t challenge[17];
291  static const char label[] = "ttls challenge";
292 
293  if ((vp->vp_length < 8) || (vp->vp_length > 16)) {
294  fr_strerror_const("Tunneled challenge has invalid length");
295  goto error;
296  }
297 
298  /*
299  * TLSv1.3 exports a different key depending on the length
300  * requested so ask for *exactly* what the spec requires
301  */
302  if (SSL_export_keying_material(ssl, challenge, vp->vp_length + 1,
303  label, sizeof(label) - 1, NULL, 0, 0) != 1) {
304  fr_tls_strerror_printf("Failed generating phase2 challenge");
305  goto error;
306  }
307 
308  if (memcmp(challenge, vp->vp_octets, vp->vp_length) != 0) {
309  fr_strerror_const("Tunneled challenge is incorrect");
310  goto error;
311  }
312  }
313 
314  /*
315  * Diameter pads strings (i.e. User-Password) with trailing zeros.
316  */
317  if (vp->vp_type == FR_TYPE_STRING) fr_pair_value_strtrim(vp);
318  }
319 
320  /*
321  * We got this far. It looks OK.
322  */
323  talloc_free(tmp_ctx);
324  return p - data;
325 }
326 
327 /*
328  * Convert fr_pair_t's to diameter attributes, and write them
329  * to an SSL session.
330  *
331  * The ONLY fr_pair_t's which may be passed to this function
332  * are ones which can go inside of a RADIUS (i.e. diameter)
333  * packet. So no server-configuration attributes, or the like.
334  */
335 static int vp2diameter(request_t *request, fr_tls_session_t *tls_session, fr_pair_list_t *list)
336 {
337  /*
338  * RADIUS packets are no more than 4k in size, so if
339  * we've got more than 4k of data to write, it's very
340  * bad.
341  */
342  uint8_t buffer[4096];
343  uint8_t *p;
344  uint32_t attr;
345  uint32_t length;
346  uint32_t vendor;
347  size_t total;
348  uint64_t attr64;
349  fr_pair_t *vp;
350 
351  p = buffer;
352  total = 0;
353 
354  for (vp = fr_pair_list_head(list);
355  vp;
356  vp = fr_pair_list_next(list, vp)) {
357  /*
358  * Too much data: die.
359  */
360  if ((total + vp->vp_length + 12) >= sizeof(buffer)) {
361  RDEBUG2("output buffer is full!");
362  return 0;
363  }
364 
365  /*
366  * Hmm... we don't group multiple EAP-Messages
367  * together. Maybe we should...
368  */
369 
370  length = vp->vp_length;
371  vendor = fr_dict_vendor_num_by_da(vp->da);
372  if (vendor != 0) {
373  attr = vp->da->attr & 0xffff;
374  length |= ((uint32_t)1 << 31);
375  } else {
376  attr = vp->da->attr;
377  }
378 
379  /*
380  * Hmm... set the M bit for all attributes?
381  */
382  length |= (1 << 30);
383 
384  attr = ntohl(attr);
385 
386  memcpy(p, &attr, sizeof(attr));
387  p += 4;
388  total += 4;
389 
390  length += 8; /* includes 8 bytes of attr & length */
391 
392  if (vendor != 0) {
393  length += 4; /* include 4 bytes of vendor */
394 
395  length = ntohl(length);
396  memcpy(p, &length, sizeof(length));
397  p += 4;
398  total += 4;
399 
400  vendor = ntohl(vendor);
401  memcpy(p, &vendor, sizeof(vendor));
402  p += 4;
403  total += 4;
404  } else {
405  length = ntohl(length);
406  memcpy(p, &length, sizeof(length));
407  p += 4;
408  total += 4;
409  }
410 
411  switch (vp->vp_type) {
412  case FR_TYPE_DATE:
413  attr = htonl(fr_unix_time_to_sec(vp->vp_date)); /* stored in host order */
414  memcpy(p, &attr, sizeof(attr));
415  length = 4;
416  break;
417 
418  case FR_TYPE_UINT32:
419  attr = htonl(vp->vp_uint32); /* stored in host order */
420  memcpy(p, &attr, sizeof(attr));
421  length = 4;
422  break;
423 
424  case FR_TYPE_UINT64:
425  attr64 = htonll(vp->vp_uint64); /* stored in host order */
426  memcpy(p, &attr64, sizeof(attr64));
427  length = 8;
428  break;
429 
430  case FR_TYPE_IPV4_ADDR:
431  memcpy(p, &vp->vp_ipv4addr, 4); /* network order */
432  length = 4;
433  break;
434 
435  case FR_TYPE_STRING:
436  case FR_TYPE_OCTETS:
437  default:
438  memcpy(p, vp->vp_strvalue, vp->vp_length);
439  length = vp->vp_length;
440  break;
441  }
442 
443  /*
444  * Skip to the end of the data.
445  */
446  p += length;
447  total += length;
448 
449  /*
450  * Align the data to a multiple of 4 bytes.
451  */
452  if ((total & 0x03) != 0) {
453  size_t i;
454 
455  length = 4 - (total & 0x03);
456  for (i = 0; i < length; i++) {
457  *p = '\0';
458  p++;
459  total++;
460  }
461  }
462  } /* loop over the VP's to write. */
463 
464  /*
465  * Write the data in the buffer to the SSL session.
466  */
467  if (total > 0) {
468  (tls_session->record_from_buff)(&tls_session->clean_in, buffer, total);
469 
470  /*
471  * FIXME: Check the return code.
472  */
473  fr_tls_session_send(request, tls_session);
474  }
475 
476  /*
477  * Everything's OK.
478  */
479  return 1;
480 }
481 
482 /*
483  * Use a reply packet to determine what to do.
484  */
485 static unlang_action_t process_reply(rlm_rcode_t *p_result, module_ctx_t const *mctx, request_t *request)
486 {
487  eap_session_t *eap_session = talloc_get_type_abort(mctx->rctx, eap_session_t);
488  eap_tls_session_t *eap_tls_session = talloc_get_type_abort(eap_session->opaque, eap_tls_session_t);
489  fr_tls_session_t *tls_session = eap_tls_session->tls_session;
490  fr_pair_t *vp = NULL;
491  fr_pair_list_t tunnel_vps;
492  ttls_tunnel_t *t = tls_session->opaque;
493  fr_packet_t *reply = request->reply;
494 
495  fr_pair_list_init(&tunnel_vps);
496  fr_assert(eap_session->request == request->parent);
497 
498  /*
499  * If the response packet was Access-Accept, then
500  * we're OK. If not, die horribly.
501  *
502  * FIXME: Take MS-CHAP2-Success attribute, and
503  * tunnel it back to the client, to authenticate
504  * ourselves to the client.
505  *
506  * FIXME: If we have an Access-Challenge, then
507  * the Reply-Message is tunneled back to the client.
508  *
509  * FIXME: If we have an EAP-Message, then that message
510  * must be tunneled back to the client.
511  *
512  * FIXME: If we have an Access-Challenge with a State
513  * attribute, then do we tunnel that to the client, or
514  * keep track of it ourselves?
515  *
516  * FIXME: EAP-Messages can only start with 'identity',
517  * NOT 'eap start', so we should check for that....
518  */
519  switch (reply->code) {
521  RDEBUG2("Got tunneled Access-Accept");
522 
523  /*
524  * Copy what we need into the TTLS tunnel and leave
525  * the rest to be cleaned up.
526  */
527  if ((vp = fr_pair_find_by_da_nested(&request->reply_pairs, NULL, attr_ms_chap2_success))) {
528  RDEBUG2("Got MS-CHAP2-Success, tunneling it to the client in a challenge");
529  } else {
530  vp = fr_pair_find_by_da_nested(&request->reply_pairs, NULL, attr_eap_channel_binding_message);
531  }
532  if (vp) {
533  t->authenticated = true;
534  fr_pair_prepend(&tunnel_vps, fr_pair_copy(tls_session, vp));
536  break;
537  }
538 
539  /*
540  * Success: Automatically return MPPE keys.
541  */
542  return eap_ttls_success(p_result, request, eap_session);
543 
545  REDEBUG("Got tunneled Access-Reject");
546  eap_tls_fail(request, eap_session);
548 
549  /*
550  * Handle Access-Challenge, but only if we
551  * send tunneled reply data. This is because
552  * an Access-Challenge means that we MUST tunnel
553  * a Reply-Message to the client.
554  */
556  RDEBUG2("Got tunneled Access-Challenge");
557 
558  /*
559  * Copy what we need into the TTLS tunnel and leave
560  * the rest to be cleaned up.
561  */
562  vp = NULL;
563  while ((vp = fr_pair_list_next(&request->reply_pairs, vp))) {
564  if ((vp->da == attr_eap_message) || (vp->da == attr_reply_message)) {
565  fr_pair_prepend(&tunnel_vps, fr_pair_copy(tls_session, vp));
566  } else if (vp->da == attr_eap_channel_binding_message) {
567  fr_pair_prepend(&tunnel_vps, fr_pair_copy(tls_session, vp));
568  }
569  }
570  break;
571 
572  default:
573  REDEBUG("Unknown RADIUS packet type %d: rejecting tunneled user", reply->code);
574  eap_tls_fail(request, eap_session);
576  }
577 
578 
579  /*
580  * Pack any tunneled VPs and send them back
581  * to the supplicant.
582  */
583  if (!fr_pair_list_empty(&tunnel_vps)) {
584  RDEBUG2("Sending tunneled reply attributes");
585  log_request_pair_list(L_DBG_LVL_2, request, NULL, &tunnel_vps, NULL);
586 
587  vp2diameter(request, tls_session, &tunnel_vps);
588  fr_pair_list_free(&tunnel_vps);
589  }
590 
591  eap_tls_request(request, eap_session);
593 }
594 
596 {
597  eap_tls_session_t *eap_tls_session = talloc_get_type_abort(eap_session->opaque, eap_tls_session_t);
598  fr_tls_session_t *tls_session = eap_tls_session->tls_session;
599  eap_tls_prf_label_t prf_label;
600 
601  eap_crypto_prf_label_init(&prf_label, eap_session,
602  "ttls keying material",
603  sizeof("ttls keying material") - 1);
604  /*
605  * Success: Automatically return MPPE keys.
606  */
607  if (eap_tls_success(request, eap_session, &prf_label) < 0) RETURN_MODULE_FAIL;
608 
609  /*
610  * Result is always OK, even if we fail to persist the
611  * session data.
612  */
613  *p_result = RLM_MODULE_OK;
614 
615  /*
616  * Write the session to the session cache
617  *
618  * We do this here (instead of relying on OpenSSL to call the
619  * session caching callback), because we only want to write
620  * session data to the cache if all phases were successful.
621  *
622  * If we wrote out the cache data earlier, and the server
623  * exited whilst the session was in progress, the supplicant
624  * could resume the session (and get access) even if phase2
625  * never completed.
626  */
627  return fr_tls_cache_pending_push(request, tls_session);
628 }
629 
630 
631 /*
632  * Process the "diameter" contents of the tunneled data.
633  */
634 unlang_action_t eap_ttls_process(request_t *request, eap_session_t *eap_session, fr_tls_session_t *tls_session)
635 {
636  fr_pair_t *vp = NULL;
637  ttls_tunnel_t *t;
638  uint8_t const *data;
639  size_t data_len;
640  chbind_packet_t *chbind;
642 
643  /*
644  * Just look at the buffer directly, without doing
645  * record_to_buff.
646  */
647  data_len = tls_session->clean_out.used;
648  tls_session->clean_out.used = 0;
649  data = tls_session->clean_out.data;
650 
651  t = (ttls_tunnel_t *) tls_session->opaque;
652 
653  /*
654  * If there's no data, maybe this is an ACK to an
655  * MS-CHAP2-Success.
656  */
657  if (data_len == 0) {
658  if (t->authenticated) {
659  RDEBUG2("Got ACK, and the user was already authenticated");
660  return eap_ttls_success(&request->rcode, request, eap_session);
661  } /* else no session, no data, die. */
662 
663  /*
664  * FIXME: Call SSL_get_error() to see what went
665  * wrong.
666  */
667  RDEBUG2("SSL_read Error");
668  return UNLANG_ACTION_FAIL;
669  }
670 
671  if (!diameter_verify(request, data, data_len)) return UNLANG_ACTION_FAIL;
672 
673  /*
674  * Add the tunneled attributes to the request request.
675  */
676  if (eap_ttls_decode_pair(request, request->request_ctx, &request->request_pairs, fr_dict_root(fr_dict_internal()),
677  data, data_len, tls_session->ssl) < 0) {
678  RPEDEBUG("Decoding TTLS TLVs failed");
679  return UNLANG_ACTION_FAIL;
680  }
681 
682  /*
683  * Update other items in the request_t data structure.
684  */
685 
686  /*
687  * No User-Name, try to create one from stored data.
688  */
689  username = fr_pair_find_by_da(&request->request_pairs, NULL, attr_user_name);
690  if (!username) {
691  /*
692  * No User-Name in the stored data, look for
693  * an EAP-Identity, and pull it out of there.
694  */
695  if (!t->username) {
696  vp = fr_pair_find_by_da(&request->request_pairs, NULL, attr_eap_message);
697  if (vp &&
698  (vp->vp_length >= EAP_HEADER_LEN + 2) &&
699  (vp->vp_strvalue[0] == FR_EAP_CODE_RESPONSE) &&
700  (vp->vp_strvalue[EAP_HEADER_LEN] == FR_EAP_METHOD_IDENTITY) &&
701  (vp->vp_strvalue[EAP_HEADER_LEN + 1] != 0)) {
702  /*
703  * Create & remember a User-Name
704  */
706  t->username->vp_tainted = true;
707 
709  (char const *)vp->vp_octets + 5, vp->vp_length - 5, true);
710 
711  RDEBUG2("Got tunneled identity of %pV", &t->username->data);
712  } else {
713  /*
714  * Don't reject the request outright,
715  * as it's permitted to do EAP without
716  * user-name.
717  */
718  RWDEBUG2("No EAP-Identity found to start EAP conversation");
719  }
720  } /* else there WAS a t->username */
721 
722  if (t->username) {
723  vp = fr_pair_copy(request->request_ctx, t->username);
724  fr_pair_append(&request->request_pairs, vp);
725  }
726  } /* else the request ALREADY had a User-Name */
727 
728  /*
729  * Process channel binding.
730  */
731  chbind = eap_chbind_vp2packet(request, &request->request_pairs);
732  if (chbind) {
733  fr_radius_packet_code_t chbind_code;
734  CHBIND_REQ *req = talloc_zero(request, CHBIND_REQ);
735 
736  RDEBUG2("received chbind request");
737  req->request = chbind;
738  if (username) {
739  req->username = username;
740  } else {
741  req->username = NULL;
742  }
743  chbind_code = chbind_process(request, req);
744 
745  /* encapsulate response here */
746  if (req->response) {
747  RDEBUG2("sending chbind response");
748  fr_pair_append(&request->reply_pairs,
749  eap_chbind_packet2vp(request->reply_ctx, req->response));
750  } else {
751  RDEBUG2("no chbind response");
752  }
753 
754  /* clean up chbind req */
755  talloc_free(req);
756 
757  if (chbind_code != FR_RADIUS_CODE_ACCESS_ACCEPT) return UNLANG_ACTION_FAIL;
758  }
759 
760  (void) unlang_module_yield(request, process_reply, NULL, 0, eap_session);
761  /*
762  * Call authentication recursively, which will
763  * do PAP, CHAP, MS-CHAP, etc.
764  */
765  return eap_virtual_server(request, eap_session, t->server_cs);
766 }
unlang_action_t
Returned by unlang_op_t calls, determine the next action of the interpreter.
Definition: action.h:35
@ UNLANG_ACTION_FAIL
Encountered an unexpected error.
Definition: action.h:36
static int const char char buffer[256]
Definition: acutest.h:574
int n
Definition: acutest.h:577
#define RCSID(id)
Definition: build.h:481
fr_radius_packet_code_t chbind_process(request_t *request, CHBIND_REQ *chbind)
Definition: chbind.c:170
chbind_packet_t * eap_chbind_vp2packet(TALLOC_CTX *ctx, fr_pair_list_t *vps)
Definition: chbind.c:269
fr_pair_t * eap_chbind_packet2vp(TALLOC_CTX *ctx, chbind_packet_t *chbind)
Definition: chbind.c:314
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:514
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:2695
static fr_dict_attr_t * fr_dict_attr_unknown_vendor_afrom_num(TALLOC_CTX *ctx, fr_dict_attr_t const *parent, unsigned int vendor)
Definition: dict.h:570
fr_dict_t const * fr_dict_by_protocol_name(char const *name)
Lookup a protocol by its name.
Definition: dict_util.c:2577
fr_dict_attr_t const * fr_dict_root(fr_dict_t const *dict)
Return the root attribute of a dictionary.
Definition: dict_util.c:2400
static fr_dict_attr_t * fr_dict_attr_unknown_raw_afrom_num(TALLOC_CTX *ctx, fr_dict_attr_t const *parent, unsigned int attr)
Definition: dict.h:577
fr_dict_t const * fr_dict_internal(void)
Definition: dict_util.c:4610
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:3328
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:212
void eap_crypto_prf_label_init(eap_tls_prf_label_t *prf_label, eap_session_t *eap_session, char const *keying_prf_label, size_t keying_prf_label_len)
Initialize the PRF label fields.
Definition: crypto.c:48
@ 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.
CONF_SECTION * server_cs
Definition: eap_ttls.h:46
fr_pair_t * username
Definition: eap_ttls.h:44
bool authenticated
Definition: eap_ttls.h:45
HIDDEN fr_dict_attr_t const * attr_reply_message
Definition: rlm_eap_ttls.c:93
if(rcode > 0)
Definition: fd_read.h:9
HIDDEN fr_dict_attr_t const * attr_eap_channel_binding_message
Definition: base.c:93
HIDDEN fr_dict_attr_t const * attr_eap_message
Definition: base.c:94
unlang_action_t eap_virtual_server(request_t *request, eap_session_t *eap_session, CONF_SECTION *server_cs)
Run a subrequest through a virtual server.
Definition: base.c:421
void * opaque
Opaque data used by EAP methods.
Definition: session.h:62
request_t * request
Current request.
Definition: session.h:51
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:830
#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
void * rctx
Resume ctx that a module previously set.
Definition: module_ctx.h:45
Temporary structure to hold arguments for module calls.
Definition: module_ctx.h:41
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:194
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:165
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:693
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:283
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:1345
void fr_pair_list_init(fr_pair_list_t *list)
Initialise a pair list header.
Definition: pair.c:46
fr_pair_t * fr_pair_afrom_da_nested(TALLOC_CTX *ctx, fr_pair_list_t *list, fr_dict_attr_t const *da)
Create a pair (and all intermediate parents), and append it to the list.
Definition: pair.c:467
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:2784
fr_pair_t * fr_pair_copy(TALLOC_CTX *ctx, fr_pair_t const *vp)
Copy a single valuepair.
Definition: pair.c:489
fr_pair_t * fr_pair_find_by_da_nested(fr_pair_list_t const *list, fr_pair_t const *prev, fr_dict_attr_t const *da)
Find a pair with a matching fr_dict_attr_t, by walking the nested fr_dict_attr_t tree.
Definition: pair.c:770
int fr_pair_value_strtrim(fr_pair_t *vp)
Trim the length of the string buffer to match the length of the C string.
Definition: pair.c:2677
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:1314
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:593
static fr_dict_t const * dict_radius
Definition: radclient-ng.c:105
static fr_dict_attr_t const * attr_ms_chap_challenge
Definition: radclient-ng.c:118
static fr_dict_attr_t const * attr_chap_challenge
Definition: radclient-ng.c:126
static fr_dict_attr_t const * attr_user_name
Definition: radclient-ng.c:128
#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
#define RETURN_MODULE_REJECT
Definition: rcode.h:55
#define RETURN_MODULE_INVALID
Definition: rcode.h:59
#define RETURN_MODULE_OK
Definition: rcode.h:57
rlm_rcode_t
Return codes indicating the result of the module call.
Definition: rcode.h:40
@ RLM_MODULE_OK
The module is OK, continue.
Definition: rcode.h:43
static fr_dict_attr_t const * attr_ms_chap2_success
username
Definition: rlm_securid.c:420
unlang_action_t unlang_module_yield(request_t *request, module_method_t resume, unlang_module_signal_t signal, fr_signal_t sigmask, void *rctx)
Yield a request back to the interpreter from within a module.
Definition: module.c:419
RETURN_MODULE_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:506
int eap_tls_success(request_t *request, eap_session_t *eap_session, eap_tls_prf_label_t *prf_label)
Send an EAP-TLS success.
Definition: tls.c:264
int eap_tls_request(request_t *request, eap_session_t *eap_session)
Frames the OpenSSL data that needs to be sent to the client in an EAP-Request.
Definition: tls.c:372
int eap_tls_fail(request_t *request, eap_session_t *eap_session)
Send an EAP-TLS failure.
Definition: tls.c:322
fr_tls_session_t * tls_session
TLS session used to authenticate peer or tunnel sensitive data.
Definition: tls.h:129
Tracks the state of an EAP-TLS session.
Definition: tls.h:126
unlang_action_t eap_ttls_process(request_t *request, eap_session_t *eap_session, fr_tls_session_t *tls_session)
Definition: ttls.c:634
#define FR_DIAMETER_AVP_FLAG_MANDATORY
Definition: ttls.c:34
static unlang_action_t process_reply(rlm_rcode_t *p_result, module_ctx_t const *mctx, request_t *request)
Definition: ttls.c:485
unlang_action_t eap_ttls_success(rlm_rcode_t *p_result, request_t *request, eap_session_t *eap_session)
Definition: ttls.c:595
static int vp2diameter(request_t *request, fr_tls_session_t *tls_session, fr_pair_list_t *list)
Definition: ttls.c:335
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_pair_list_t *out, 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
static fr_slen_t parent
Definition: pair.h:851
#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:1754
static fr_slen_t data
Definition: value.h:1265
static size_t char ** out
Definition: value.h:997