The FreeRADIUS server $Id: 15bac2a4c627c01d1aa2047687b3418955ac7f00 $
Loading...
Searching...
No Matches
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
26RCSID("$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 */
52static 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 */
144static 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
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) {
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 */
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 */
335static 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
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 */
485static 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 */
634unlang_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:576
int n
Definition acutest.h:577
#define RCSID(id)
Definition build.h:483
fr_pair_t * eap_chbind_packet2vp(TALLOC_CTX *ctx, chbind_packet_t *chbind)
Definition chbind.c:314
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
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
#define MEM(x)
Definition debug.h:36
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
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:573
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:580
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
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
fr_dict_t const * fr_dict_internal(void)
Definition dict_util.c:4610
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_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
HIDDEN fr_dict_attr_t const * attr_eap_channel_binding_message
Definition base.c:95
HIDDEN fr_dict_attr_t const * attr_eap_message
Definition base.c:96
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:427
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.
@ FR_TYPE_STRING
String of printable characters.
@ FR_TYPE_DATE
Unix time stamp, always has value >2^31.
@ FR_TYPE_UINT32
32 Bit unsigned integer.
@ FR_TYPE_UINT64
64 Bit unsigned integer.
@ FR_TYPE_OCTETS
Raw octets.
unsigned int uint32_t
long int ssize_t
unsigned char uint8_t
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:196
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:167
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
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
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
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
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:2784
fr_pair_t * fr_pair_copy(TALLOC_CTX *ctx, fr_pair_t const *vp)
Copy a single valuepair.
Definition pair.c:489
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
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_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
#define fr_assert(_expr)
Definition rad_assert.h:38
static fr_dict_t const * dict_radius
static fr_dict_attr_t const * attr_ms_chap_challenge
static fr_dict_attr_t const * attr_chap_challenge
static fr_dict_attr_t const * attr_user_name
#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
#define RETURN_MODULE_FAIL
Definition rcode.h:56
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
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
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
bool fr_pair_list_empty(fr_pair_list_t const *list)
Is a valuepair list empty.
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.
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
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