The FreeRADIUS server $Id: 15bac2a4c627c01d1aa2047687b3418955ac7f00 $
Loading...
Searching...
No Matches
rlm_eap_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: 2df37f0e540692ac185cb0d4c079d883f5b665a5 $
19 * @file rlm_eap_ttls.c
20 * @brief 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: 2df37f0e540692ac185cb0d4c079d883f5b665a5 $")
27USES_APPLE_DEPRECATED_API /* OpenSSL API has been deprecated by Apple */
28
29#include <freeradius-devel/eap/tls.h>
30#include <freeradius-devel/eap/chbind.h>
31#include <freeradius-devel/tls/strerror.h>
32
33typedef struct {
34 SSL_CTX *ssl_ctx; //!< Thread local SSL_CTX.
36
37typedef struct {
38 /*
39 * TLS configuration
40 */
41 char const *tls_conf_name;
42 fr_tls_conf_t *tls_conf;
43
44 /*
45 * RFC 5281 (TTLS) says that the length field MUST NOT be
46 * in fragments after the first one. However, we've done
47 * it that way for years, and no one has complained.
48 *
49 * In the interests of allowing the server to follow the
50 * RFC, we add the option here. If set to "no", it sends
51 * the length field in ONLY the first fragment.
52 */
54
55 /*
56 * Virtual server for inner tunnel session.
57 */
60
61 /*
62 * Do we do require a client cert?
63 */
66
71
73 { FR_CONF_OFFSET("tls", rlm_eap_ttls_t, tls_conf_name) },
74 { FR_CONF_DEPRECATED("copy_request_to_tunnel", rlm_eap_ttls_t, NULL), .dflt = "no" },
75 { FR_CONF_DEPRECATED("use_tunneled_reply", rlm_eap_ttls_t, NULL), .dflt = "no" },
78 .uctx = &(virtual_server_cf_parse_uctx_t){ .process_module_name = "radius"} },
79 { FR_CONF_OFFSET("include_length", rlm_eap_ttls_t, include_length), .dflt = "yes" },
80 { FR_CONF_OFFSET("require_client_cert", rlm_eap_ttls_t, req_client_cert), .dflt = "no" },
82};
83
85static fr_dict_t const *dict_radius;
86
89 { .out = &dict_freeradius, .proto = "freeradius" },
90 { .out = &dict_radius, .proto = "radius" },
91 { NULL }
92};
93
95
105
108 { .out = &attr_eap_tls_require_client_cert, .name = "EAP-TLS-Require-Client-Cert", .type = FR_TYPE_UINT32, .dict = &dict_freeradius },
109
110 { .out = &attr_chap_challenge, .name = "CHAP-Challenge", .type = FR_TYPE_OCTETS, .dict = &dict_radius },
111 { .out = &attr_eap_message, .name = "EAP-Message", .type = FR_TYPE_OCTETS, .dict = &dict_radius },
112 { .out = &attr_ms_chap_challenge, .name = "Vendor-Specific.Microsoft.CHAP-Challenge", .type = FR_TYPE_OCTETS, .dict = &dict_radius },
113 { .out = &attr_ms_chap2_success, .name = "Vendor-Specific.Microsoft.CHAP2-Success", .type = FR_TYPE_OCTETS, .dict = &dict_radius },
114 { .out = &attr_reply_message, .name = "Reply-Message", .type = FR_TYPE_STRING, .dict = &dict_radius },
115 { .out = &attr_eap_channel_binding_message, .name = "Vendor-Specific.UKERNA.EAP-Channel-Binding-Message", .type = FR_TYPE_OCTETS, .dict = &dict_radius },
116 { .out = &attr_user_name, .name = "User-Name", .type = FR_TYPE_STRING, .dict = &dict_radius },
117 { .out = &attr_user_password, .name = "User-Password", .type = FR_TYPE_STRING, .dict = &dict_radius },
118 { .out = &attr_vendor_specific, .name = "Vendor-Specific", .type = FR_TYPE_VSA, .dict = &dict_radius },
119 { NULL }
120};
121
122
123#define FR_DIAMETER_AVP_FLAG_VENDOR 0x80
124#define FR_DIAMETER_AVP_FLAG_MANDATORY 0x40
125/*
126 * 0 1 2 3
127 * 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
128 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
129 * | AVP Code |
130 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
131 * |V M r r r r r r| AVP Length |
132 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
133 * | Vendor-ID (opt) |
134 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
135 * | Data ...
136 * +-+-+-+-+-+-+-+-+
137 */
138
139/*
140 * Verify that the diameter packet is valid.
141 */
142static int diameter_verify(request_t *request, uint8_t const *data, unsigned int data_len)
143{
144 uint32_t attr;
145 uint32_t length;
146 unsigned int hdr_len;
147 unsigned int remaining = data_len;
148
149 while (remaining > 0) {
150 hdr_len = 12;
151
152 if (remaining < hdr_len) {
153 RDEBUG2("Diameter attribute is too small (%u) to contain a Diameter header", remaining);
154 return 0;
155 }
156
157 memcpy(&attr, data, sizeof(attr));
158 attr = ntohl(attr);
159 memcpy(&length, data + 4, sizeof(length));
160 length = ntohl(length);
161
162 if ((data[4] & 0x80) != 0) {
163 if (remaining < 16) {
164 RDEBUG2("Diameter attribute is too small to contain a Diameter header with Vendor-Id");
165 return 0;
166 }
167
168 hdr_len = 16;
169 }
170
171 /*
172 * Get the length. If it's too big, die.
173 */
174 length &= 0x00ffffff;
175
176 /*
177 * Too short or too long is bad.
178 */
179 if (length <= (hdr_len - 4)) {
180 RDEBUG2("Tunneled attribute %u is too short (%u < %u) to contain anything useful.", attr,
181 length, hdr_len);
182 return 0;
183 }
184
185 if (length > remaining) {
186 RDEBUG2("Tunneled attribute %u is longer than room remaining in the packet (%u > %u).", attr,
187 length, remaining);
188 return 0;
189 }
190
191 /*
192 * Check for broken implementations, which don't
193 * pad the AVP to a 4-octet boundary.
194 */
195 if (remaining == length) break;
196
197 /*
198 * The length does NOT include the padding, so
199 * we've got to account for it here by rounding up
200 * to the nearest 4-byte boundary.
201 */
202 length += 0x03;
203 length &= ~0x03;
204
205 /*
206 * If the rest of the diameter packet is larger than
207 * this attribute, continue.
208 *
209 * Otherwise, if the attribute over-flows the end
210 * of the packet, die.
211 */
212 if (remaining < length) {
213 REDEBUG2("Diameter attribute overflows packet!");
214 return 0;
215 }
216
217 /*
218 * remaining > length, continue.
219 */
220 remaining -= length;
221 data += length;
222 }
223
224 /*
225 * We got this far. It looks OK.
226 */
227 return 1;
228}
229
230/*
231 * Convert diameter attributes to our fr_pair_t's
232 */
233static ssize_t eap_ttls_decode_pair(request_t *request, TALLOC_CTX *ctx, fr_pair_list_t *out,
234 fr_dict_attr_t const *parent,
235 uint8_t const *data, size_t data_len,
236 void *decode_ctx)
237{
238 uint8_t const *p = data, *end = p + data_len;
239
240 fr_pair_t *vp = NULL;
241 SSL *ssl = decode_ctx;
242 fr_dict_attr_t const *attr_radius;
243 fr_dict_attr_t const *da;
244 TALLOC_CTX *tmp_ctx = NULL;
245
246 attr_radius = fr_dict_root(dict_radius);
247
248 while (p < end) {
249 ssize_t ret;
250 uint32_t attr, vendor;
251 uint64_t value_len;
252 uint8_t flags;
253 fr_dict_attr_t const *our_parent = parent;
254
255 if ((end - p) < 8) {
256 fr_strerror_printf("Malformed diameter attribute at offset %zu. Needed at least 8 bytes, got %zu bytes",
257 p - data, end - p);
258 error:
259 talloc_free(tmp_ctx);
261 return -1;
262 }
263
264 RDEBUG3("%04zu %02x%02x%02x%02x %02x%02x%02x%02x ...", p - data,
265 p[0], p[1], p[2], p[3], p[4], p[5], p[6], p[7]);
266
267 attr = fr_nbo_to_uint32(p);
268 p += 4;
269
270 flags = p[0];
271 p++;
272
273 value_len = fr_nbo_to_uint64v(p, 3); /* Yes, that is a 24 bit length field */
274 p += 3;
275
276 if (value_len < 8) {
277 fr_strerror_printf("Malformed diameter attribute at offset %zu. Needed at least length of 8, got %u",
278 p - data, (unsigned int) value_len);
279 goto error;
280 }
281
282 /*
283 * Account for the 8 bytes we've already read from the packet.
284 */
285 if ((p + ((value_len + 0x03) & ~0x03)) - 8 > end) {
286 fr_strerror_printf("Malformed diameter attribute at offset %zu. Value length %u overflows input",
287 p - data, (unsigned int) value_len);
288 goto error;
289 }
290
291 value_len -= 8; /* -= 8 for AVP code (4), flags (1), AVP length (3) */
292
293 /*
294 * Do we have a vendor field?
295 */
296 if (flags & FR_DIAMETER_AVP_FLAG_VENDOR) {
297 vendor = fr_nbo_to_uint32(p);
298 p += 4;
299 value_len -= 4; /* -= 4 for the vendor ID field */
300
302 if (!our_parent) {
303 if (flags & FR_DIAMETER_AVP_FLAG_MANDATORY) {
304 fr_strerror_printf("Mandatory bit set and no vendor %u found", vendor);
305 goto error;
306 }
307
308 if (!tmp_ctx) {
310
311 MEM(our_parent = n = fr_dict_attr_unknown_vendor_afrom_num(ctx, parent, vendor));
312 tmp_ctx = n;
313 } else {
314 MEM(our_parent = fr_dict_attr_unknown_vendor_afrom_num(tmp_ctx, parent, vendor));
315 }
316 }
317 } else {
318 our_parent = attr_radius;
319 }
320
321 /*
322 * Is the attribute known?
323 */
324 da = fr_dict_attr_child_by_num(our_parent, attr);
325 if (!da) {
326 if (flags & FR_DIAMETER_AVP_FLAG_MANDATORY) {
327 fr_strerror_printf("Mandatory bit set and no attribute %u defined for parent %s", attr, parent->name);
328 goto error;
329 }
330
331 MEM(da = fr_dict_attr_unknown_raw_afrom_num(vp, our_parent, attr));
332 }
333
334 MEM(vp =fr_pair_afrom_da_nested(ctx, out, da));
335
336 ret = fr_value_box_from_network(vp, &vp->data, vp->vp_type, vp->da,
337 &FR_DBUFF_TMP(p, (size_t)value_len), value_len, true);
338 if (ret < 0) {
339 /*
340 * Mandatory bit is set, and the attribute
341 * is malformed. Fail.
342 */
343 if (flags & FR_DIAMETER_AVP_FLAG_MANDATORY) {
344 fr_strerror_const("Mandatory bit is set and attribute is malformed");
345 goto error;
346 }
347
348 fr_pair_raw_afrom_pair(vp, p, value_len);
349 }
350
351 /*
352 * The length does NOT include the padding, so
353 * we've got to account for it here by rounding up
354 * to the nearest 4-byte boundary.
355 */
356 p += (value_len + 0x03) & ~0x03;
357
358 if (vp->da->flags.is_unknown) continue;
359
360 /*
361 * Ensure that the client is using the correct challenge.
362 *
363 * This weirdness is to protect against against replay
364 * attacks, where anyone observing the CHAP exchange could
365 * pose as that user, by simply choosing to use the same
366 * challenge.
367 * By using a challenge based on information from the
368 * current session, we can guarantee that the client is
369 * not *choosing* a challenge. We're a little forgiving in
370 * that we have loose checks on the length, and we do NOT
371 * check the Id (first octet of the response to the
372 * challenge) But if the client gets the challenge correct,
373 * we're not too worried about the Id.
374 */
376 uint8_t challenge[17];
377 static const char label[] = "ttls challenge";
378
379 if ((vp->vp_length < 8) || (vp->vp_length > 16)) {
380 fr_strerror_const("Tunneled challenge has invalid length");
381 goto error;
382 }
383
384 /*
385 * TLSv1.3 exports a different key depending on the length
386 * requested so ask for *exactly* what the spec requires
387 */
388 if (SSL_export_keying_material(ssl, challenge, vp->vp_length + 1,
389 label, sizeof(label) - 1, NULL, 0, 0) != 1) {
390 fr_tls_strerror_printf("Failed generating phase2 challenge");
391 goto error;
392 }
393
394 if (memcmp(challenge, vp->vp_octets, vp->vp_length) != 0) {
395 fr_strerror_const("Tunneled challenge is incorrect");
396 goto error;
397 }
398 }
399
400 /*
401 * Diameter pads strings (i.e. User-Password) with trailing zeros.
402 */
403 if (vp->vp_type == FR_TYPE_STRING) fr_pair_value_strtrim(vp);
404 }
405
406 /*
407 * We got this far. It looks OK.
408 */
409 talloc_free(tmp_ctx);
410 return p - data;
411}
412
413/*
414 * Convert fr_pair_t's to diameter attributes, and write them
415 * to an SSL session.
416 *
417 * The ONLY fr_pair_t's which may be passed to this function
418 * are ones which can go inside of a RADIUS (i.e. diameter)
419 * packet. So no server-configuration attributes, or the like.
420 */
421static int vp2diameter(request_t *request, fr_tls_session_t *tls_session, fr_pair_list_t *list)
422{
423 /*
424 * RADIUS packets are no more than 4k in size, so if
425 * we've got more than 4k of data to write, it's very
426 * bad.
427 */
428 uint8_t buffer[4096];
429 uint8_t *p;
430 uint32_t attr;
431 uint32_t length;
432 uint32_t vendor;
433 size_t total;
434 uint64_t attr64;
435 fr_pair_t *vp;
436
437 p = buffer;
438 total = 0;
439
440 for (vp = fr_pair_list_head(list);
441 vp;
442 vp = fr_pair_list_next(list, vp)) {
443 /*
444 * Too much data: die.
445 */
446 if ((total + vp->vp_length + 12) >= sizeof(buffer)) {
447 RDEBUG2("output buffer is full!");
448 return 0;
449 }
450
451 /*
452 * Hmm... we don't group multiple EAP-Messages
453 * together. Maybe we should...
454 */
455
456 length = vp->vp_length;
457 vendor = fr_dict_vendor_num_by_da(vp->da);
458 if (vendor != 0) {
459 attr = vp->da->attr & 0xffff;
460 length |= ((uint32_t)1 << 31);
461 } else {
462 attr = vp->da->attr;
463 }
464
465 /*
466 * Hmm... set the M bit for all attributes?
467 */
468 length |= (1 << 30);
469
470 attr = ntohl(attr);
471
472 memcpy(p, &attr, sizeof(attr));
473 p += 4;
474 total += 4;
475
476 length += 8; /* includes 8 bytes of attr & length */
477
478 if (vendor != 0) {
479 length += 4; /* include 4 bytes of vendor */
480
481 length = ntohl(length);
482 memcpy(p, &length, sizeof(length));
483 p += 4;
484 total += 4;
485
486 vendor = ntohl(vendor);
487 memcpy(p, &vendor, sizeof(vendor));
488 p += 4;
489 total += 4;
490 } else {
491 length = ntohl(length);
492 memcpy(p, &length, sizeof(length));
493 p += 4;
494 total += 4;
495 }
496
497 switch (vp->vp_type) {
498 case FR_TYPE_DATE:
499 attr = htonl(fr_unix_time_to_sec(vp->vp_date)); /* stored in host order */
500 memcpy(p, &attr, sizeof(attr));
501 length = 4;
502 break;
503
504 case FR_TYPE_UINT32:
505 attr = htonl(vp->vp_uint32); /* stored in host order */
506 memcpy(p, &attr, sizeof(attr));
507 length = 4;
508 break;
509
510 case FR_TYPE_UINT64:
511 attr64 = htonll(vp->vp_uint64); /* stored in host order */
512 memcpy(p, &attr64, sizeof(attr64));
513 length = 8;
514 break;
515
517 memcpy(p, &vp->vp_ipv4addr, 4); /* network order */
518 length = 4;
519 break;
520
521 case FR_TYPE_STRING:
522 case FR_TYPE_OCTETS:
523 default:
524 memcpy(p, vp->vp_strvalue, vp->vp_length);
525 length = vp->vp_length;
526 break;
527 }
528
529 /*
530 * Skip to the end of the data.
531 */
532 p += length;
533 total += length;
534
535 /*
536 * Align the data to a multiple of 4 bytes.
537 */
538 if ((total & 0x03) != 0) {
539 size_t i;
540
541 length = 4 - (total & 0x03);
542 for (i = 0; i < length; i++) {
543 *p = '\0';
544 p++;
545 total++;
546 }
547 }
548 } /* loop over the VP's to write. */
549
550 /*
551 * Write the data in the buffer to the SSL session.
552 */
553 if (total > 0) {
554 (tls_session->record_from_buff)(&tls_session->clean_in, buffer, total);
555
556 /*
557 * FIXME: Check the return code.
558 */
559 fr_tls_session_send(request, tls_session);
560 }
561
562 /*
563 * Everything's OK.
564 */
565 return 1;
566}
567
568
570{
571 eap_tls_session_t *eap_tls_session = talloc_get_type_abort(eap_session->opaque, eap_tls_session_t);
572 fr_tls_session_t *tls_session = eap_tls_session->tls_session;
573 eap_tls_prf_label_t prf_label;
574
575 eap_crypto_prf_label_init(&prf_label, eap_session,
576 "ttls keying material",
577 sizeof("ttls keying material") - 1);
578 /*
579 * Success: Automatically return MPPE keys.
580 */
581 if (eap_tls_success(request, eap_session, &prf_label) < 0) RETURN_UNLANG_FAIL;
582
583 /*
584 * Result is always OK, even if we fail to persist the
585 * session data.
586 */
587 p_result->rcode = RLM_MODULE_OK;
588
589 /*
590 * Write the session to the session cache
591 *
592 * We do this here (instead of relying on OpenSSL to call the
593 * session caching callback), because we only want to write
594 * session data to the cache if all phases were successful.
595 *
596 * If we wrote out the cache data earlier, and the server
597 * exited whilst the session was in progress, the supplicant
598 * could resume the session (and get access) even if phase2
599 * never completed.
600 */
601 return fr_tls_cache_pending_push(request, tls_session);
602}
603
604
605/*
606 * Use a reply packet to determine what to do.
607 */
609{
610 eap_session_t *eap_session = talloc_get_type_abort(mctx->rctx, eap_session_t);
611 eap_tls_session_t *eap_tls_session = talloc_get_type_abort(eap_session->opaque, eap_tls_session_t);
612 fr_tls_session_t *tls_session = eap_tls_session->tls_session;
613 fr_pair_t *vp = NULL;
614 fr_pair_list_t tunnel_vps;
615 ttls_tunnel_t *t = tls_session->opaque;
616 fr_packet_t *reply = request->reply;
617
618 fr_pair_list_init(&tunnel_vps);
619 fr_assert(eap_session->request == request->parent);
620
621 /*
622 * If the response packet was Access-Accept, then
623 * we're OK. If not, die horribly.
624 *
625 * FIXME: Take MS-CHAP2-Success attribute, and
626 * tunnel it back to the client, to authenticate
627 * ourselves to the client.
628 *
629 * FIXME: If we have an Access-Challenge, then
630 * the Reply-Message is tunneled back to the client.
631 *
632 * FIXME: If we have an EAP-Message, then that message
633 * must be tunneled back to the client.
634 *
635 * FIXME: If we have an Access-Challenge with a State
636 * attribute, then do we tunnel that to the client, or
637 * keep track of it ourselves?
638 *
639 * FIXME: EAP-Messages can only start with 'identity',
640 * NOT 'eap start', so we should check for that....
641 */
642 switch (reply->code) {
644 RDEBUG2("Got tunneled Access-Accept");
645
646 /*
647 * Copy what we need into the TTLS tunnel and leave
648 * the rest to be cleaned up.
649 */
650 if ((vp = fr_pair_find_by_da_nested(&request->reply_pairs, NULL, attr_ms_chap2_success))) {
651 RDEBUG2("Got MS-CHAP2-Success, tunneling it to the client in a challenge");
652 } else {
653 vp = fr_pair_find_by_da_nested(&request->reply_pairs, NULL, attr_eap_channel_binding_message);
654 }
655 if (vp) {
656 t->authenticated = true;
657 fr_pair_prepend(&tunnel_vps, fr_pair_copy(tls_session, vp));
659 break;
660 }
661
662 /*
663 * Success: Automatically return MPPE keys.
664 */
665 return eap_ttls_success(p_result, request, eap_session);
666
668 REDEBUG("Got tunneled Access-Reject");
669 eap_tls_fail(request, eap_session);
671
672 /*
673 * Handle Access-Challenge, but only if we
674 * send tunneled reply data. This is because
675 * an Access-Challenge means that we MUST tunnel
676 * a Reply-Message to the client.
677 */
679 RDEBUG2("Got tunneled Access-Challenge");
680
681 /*
682 * Copy what we need into the TTLS tunnel and leave
683 * the rest to be cleaned up.
684 */
685 vp = NULL;
686 while ((vp = fr_pair_list_next(&request->reply_pairs, vp))) {
687 if ((vp->da == attr_eap_message) || (vp->da == attr_reply_message)) {
688 fr_pair_prepend(&tunnel_vps, fr_pair_copy(tls_session, vp));
689 } else if (vp->da == attr_eap_channel_binding_message) {
690 fr_pair_prepend(&tunnel_vps, fr_pair_copy(tls_session, vp));
691 }
692 }
693 break;
694
695 default:
696 REDEBUG("Unknown RADIUS packet type %d: rejecting tunneled user", reply->code);
697 eap_tls_fail(request, eap_session);
699 }
700
701
702 /*
703 * Pack any tunneled VPs and send them back
704 * to the supplicant.
705 */
706 if (!fr_pair_list_empty(&tunnel_vps)) {
707 RDEBUG2("Sending tunneled reply attributes");
708 log_request_pair_list(L_DBG_LVL_2, request, NULL, &tunnel_vps, NULL);
709
710 vp2diameter(request, tls_session, &tunnel_vps);
711 fr_pair_list_free(&tunnel_vps);
712 }
713
714 eap_tls_request(request, eap_session);
716}
717
718/*
719 * Process the "diameter" contents of the tunneled data.
720 */
722 request_t *request, eap_session_t *eap_session, fr_tls_session_t *tls_session)
723{
724 fr_pair_t *vp = NULL;
725 ttls_tunnel_t *t;
726 uint8_t const *data;
727 size_t data_len;
728 chbind_packet_t *chbind;
730 rlm_eap_ttls_t *inst = talloc_get_type_abort(mctx->mi->data, rlm_eap_ttls_t);
731
732 /*
733 * Just look at the buffer directly, without doing
734 * record_to_buff.
735 */
736 data_len = tls_session->clean_out.used;
737 tls_session->clean_out.used = 0;
738 data = tls_session->clean_out.data;
739
740 t = (ttls_tunnel_t *) tls_session->opaque;
741
742 /*
743 * If there's no data, maybe this is an ACK to an
744 * MS-CHAP2-Success.
745 */
746 if (data_len == 0) {
747 if (t->authenticated) {
748 RDEBUG2("Got ACK, and the user was already authenticated");
749 return eap_ttls_success(p_result, request, eap_session);
750 } /* else no session, no data, die. */
751
752 /*
753 * FIXME: Call SSL_get_error() to see what went
754 * wrong.
755 */
756 RDEBUG2("SSL_read Error");
757 return UNLANG_ACTION_FAIL;
758 }
759
760 if (!diameter_verify(request, data, data_len)) return UNLANG_ACTION_FAIL;
761
762 /*
763 * Add the tunneled attributes to the request request.
764 */
765 if (eap_ttls_decode_pair(request, request->request_ctx, &request->request_pairs, fr_dict_root(fr_dict_internal()),
766 data, data_len, tls_session->ssl) < 0) {
767 RPEDEBUG("Decoding TTLS TLVs failed");
768 return UNLANG_ACTION_FAIL;
769 }
770
771 /*
772 * Update other items in the request_t data structure.
773 */
774
775 /*
776 * No User-Name, try to create one from stored data.
777 */
778 username = fr_pair_find_by_da(&request->request_pairs, NULL, attr_user_name);
779 if (!username) {
780 /*
781 * No User-Name in the stored data, look for
782 * an EAP-Identity, and pull it out of there.
783 */
784 if (!t->username) {
785 vp = fr_pair_find_by_da(&request->request_pairs, NULL, attr_eap_message);
786 if (vp &&
787 (vp->vp_length >= EAP_HEADER_LEN + 2) &&
788 (vp->vp_strvalue[0] == FR_EAP_CODE_RESPONSE) &&
789 (vp->vp_strvalue[EAP_HEADER_LEN] == FR_EAP_METHOD_IDENTITY) &&
790 (vp->vp_strvalue[EAP_HEADER_LEN + 1] != 0)) {
791 /*
792 * Create & remember a User-Name
793 */
795 t->username->vp_tainted = true;
796
798 (char const *)vp->vp_octets + 5, vp->vp_length - 5, true);
799
800 RDEBUG2("Got tunneled identity of %pV", &t->username->data);
801 } else {
802 /*
803 * Don't reject the request outright,
804 * as it's permitted to do EAP without
805 * user-name.
806 */
807 RWDEBUG2("No EAP-Identity found to start EAP conversation");
808 }
809 } /* else there WAS a t->username */
810
811 if (t->username) {
812 vp = fr_pair_copy(request->request_ctx, t->username);
813 fr_pair_append(&request->request_pairs, vp);
814 }
815 } /* else the request ALREADY had a User-Name */
816
817 /*
818 * Process channel binding.
819 */
820 chbind = eap_chbind_vp2packet(request, &request->request_pairs);
821 if (chbind) {
822 fr_radius_packet_code_t chbind_code;
823 CHBIND_REQ *req = talloc_zero(request, CHBIND_REQ);
824
825 RDEBUG2("received chbind request");
826 req->request = chbind;
827 if (username) {
828 req->username = username;
829 } else {
830 req->username = NULL;
831 }
832 chbind_code = chbind_process(request, req);
833
834 /* encapsulate response here */
835 if (req->response) {
836 RDEBUG2("sending chbind response");
837 fr_pair_append(&request->reply_pairs,
838 eap_chbind_packet2vp(request->reply_ctx, req->response));
839 } else {
840 RDEBUG2("no chbind response");
841 }
842
843 /* clean up chbind req */
844 talloc_free(req);
845
846 if (chbind_code != FR_RADIUS_CODE_ACCESS_ACCEPT) return UNLANG_ACTION_FAIL;
847 }
848
849 /*
850 * For this round, when the virtual server returns
851 * we run the process reply function.
852 */
853 if (unlikely(unlang_module_yield(request, process_reply, NULL, 0, eap_session) != UNLANG_ACTION_YIELD)) {
854 return UNLANG_ACTION_FAIL;
855 }
856
857 /*
858 * Call authentication recursively, which will
859 * do PAP, CHAP, MS-CHAP, etc.
860 */
861 return eap_virtual_server(request, eap_session, inst->virtual_server);
862}
863
864/*
865 * Allocate the TTLS per-session data
866 */
867static ttls_tunnel_t *ttls_alloc(TALLOC_CTX *ctx)
868{
869 ttls_tunnel_t *t;
870
871 t = talloc_zero(ctx, ttls_tunnel_t);
872
873 return t;
874}
875
877{
878 eap_session_t *eap_session = talloc_get_type_abort(mctx->rctx, eap_session_t);
879 eap_tls_session_t *eap_tls_session = talloc_get_type_abort(eap_session->opaque, eap_tls_session_t);
880 fr_tls_session_t *tls_session = eap_tls_session->tls_session;
881
882 ttls_tunnel_t *tunnel = talloc_get_type_abort(tls_session->opaque, ttls_tunnel_t);
883
884 if ((eap_tls_session->state == EAP_TLS_INVALID) || (eap_tls_session->state == EAP_TLS_FAIL)) {
885 REDEBUG("[eap-tls process] = %s", fr_table_str_by_value(eap_tls_status_table, eap_tls_session->state, "<INVALID>"));
886 } else {
887 RDEBUG2("[eap-tls process] = %s", fr_table_str_by_value(eap_tls_status_table, eap_tls_session->state, "<INVALID>"));
888 }
889
890 switch (eap_tls_session->state) {
891 /*
892 * EAP-TLS handshake was successful, tell the
893 * client to keep talking.
894 *
895 * If this was EAP-TLS, we would just return
896 * an EAP-TLS-Success packet here.
897 */
899 if (SSL_session_reused(tls_session->ssl)) {
900 RDEBUG2("Skipping Phase2 due to session resumption");
901 return eap_ttls_success(p_result, request, eap_session);
902 }
903
904 if (tunnel && tunnel->authenticated) return eap_ttls_success(p_result, request, eap_session);
905
906 eap_tls_request(request, eap_session);
908
909 /*
910 * The TLS code is still working on the TLS
911 * exchange, and it's a valid TLS request.
912 * do nothing.
913 */
914 case EAP_TLS_HANDLED:
916
917 /*
918 * Handshake is done, proceed with decoding tunneled
919 * data.
920 */
922 break;
923
924 /*
925 * Anything else: fail.
926 */
927 default:
929 }
930
931 /*
932 * Session is established, proceed with decoding
933 * tunneled data.
934 */
935 RDEBUG2("Session established. Decoding Diameter attributes");
936
937 /*
938 * Process the TTLS portion of the request.
939 */
940 return eap_ttls_process(p_result, mctx, request, eap_session, tls_session);
941}
942
943/*
944 * Do authentication, by letting EAP-TLS do most of the work.
945 */
947 request_t *request)
948{
949 eap_session_t *eap_session = eap_session_get(request->parent);
950
951 /*
952 * Setup the resumption frame to process the result
953 */
954 (void)unlang_module_yield(request, mod_handshake_resume, NULL, 0, eap_session);
955
956 /*
957 * Process TLS layer until done.
958 */
959 return eap_tls_process(request, eap_session);
960}
961
963{
964 rlm_eap_ttls_t *inst = talloc_get_type_abort(mctx->mi->data, rlm_eap_ttls_t);
965 rlm_eap_ttls_thread_t *t = talloc_get_type_abort(mctx->thread, rlm_eap_ttls_thread_t);
966 eap_session_t *eap_session = eap_session_get(request->parent);
967
968 eap_tls_session_t *eap_tls_session;
969 fr_tls_session_t *tls_session;
970 fr_pair_t *vp;
971 bool client_cert;
972
973 /*
974 * EAP-TLS-Require-Client-Cert attribute will override
975 * the require_client_cert configuration option.
976 */
977 vp = fr_pair_find_by_da(&request->control_pairs, NULL, attr_eap_tls_require_client_cert);
978 if (vp) {
979 client_cert = vp->vp_uint32 ? true : false;
980 } else {
981 client_cert = inst->req_client_cert;
982 }
983
984 eap_session->opaque = eap_tls_session = eap_tls_session_init(request, eap_session, t->ssl_ctx, client_cert);
985 if (!eap_tls_session) RETURN_UNLANG_FAIL;
986 tls_session = eap_tls_session->tls_session;
987
988 eap_tls_session->include_length = inst->include_length;
989
990 /*
991 * TLS session initialization is over. Now handle TLS
992 * related handshaking or application data.
993 */
994 if (eap_tls_start(request, eap_session) < 0) {
995 talloc_free(eap_tls_session);
997 }
998
999 tls_session->opaque = ttls_alloc(tls_session);
1000
1001 eap_session->process = mod_handshake_process;
1002
1004}
1005
1006/*
1007 * Send an initial eap-tls request to the peer, using the libeap functions.
1008 */
1010{
1011 rlm_eap_ttls_t *inst = talloc_get_type_abort(mctx->mi->data, rlm_eap_ttls_t);
1012 eap_session_t *eap_session = eap_session_get(request->parent);
1013
1014 eap_session->tls = true;
1015
1016 (void) unlang_module_yield(request, mod_session_init_resume, NULL, 0, NULL);
1017
1018 if (inst->tls_conf->new_session) return fr_tls_new_session_push(request, inst->tls_conf);
1019
1021}
1022
1024{
1025 rlm_eap_ttls_t *inst = talloc_get_type_abort(mctx->mi->data, rlm_eap_ttls_t);
1026 rlm_eap_ttls_thread_t *t = talloc_get_type_abort(mctx->thread, rlm_eap_ttls_thread_t);
1027
1028 t->ssl_ctx = fr_tls_ctx_alloc(inst->tls_conf, false);
1029 if (!t->ssl_ctx) return -1;
1030
1031 return 0;
1032}
1033
1035{
1036 rlm_eap_ttls_thread_t *t = talloc_get_type_abort(mctx->thread, rlm_eap_ttls_thread_t);
1037
1038 if (likely(t->ssl_ctx != NULL)) SSL_CTX_free(t->ssl_ctx);
1039 t->ssl_ctx = NULL;
1040
1041 return 0;
1042}
1043
1044/*
1045 * Attach the module.
1046 */
1047static int mod_instantiate(module_inst_ctx_t const *mctx)
1048{
1049 rlm_eap_ttls_t *inst = talloc_get_type_abort(mctx->mi->data, rlm_eap_ttls_t);
1050 CONF_SECTION *conf = mctx->mi->conf;
1051
1052 inst->server_cs = virtual_server_cs(inst->virtual_server);
1053
1054 /*
1055 * Read tls configuration, either from group given by 'tls'
1056 * option, or from the eap-tls configuration.
1057 */
1058 inst->tls_conf = eap_tls_conf_parse(conf);
1059 if (!inst->tls_conf) {
1060 cf_log_err(conf, "Failed initializing SSL context");
1061 return -1;
1062 }
1063
1064 return 0;
1065}
1066
1067/*
1068 * The module name should be the only globally exported symbol.
1069 * That is, everything else should be 'static'.
1070 */
1073 .common = {
1074 .magic = MODULE_MAGIC_INIT,
1075 .name = "eap_ttls",
1076
1077 .inst_size = sizeof(rlm_eap_ttls_t),
1079 .instantiate = mod_instantiate, /* Create new submodule instance */
1080
1081 .thread_inst_size = sizeof(rlm_eap_ttls_thread_t),
1082 .thread_instantiate = mod_thread_instantiate,
1083 .thread_detach = mod_thread_detach,
1084 },
1085 .provides = { FR_EAP_METHOD_TTLS },
1086 .session_init = mod_session_init, /* Initialise a new EAP session */
1087};
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
@ UNLANG_ACTION_CALCULATE_RESULT
Calculate a new section rlm_rcode_t value.
Definition action.h:37
@ UNLANG_ACTION_YIELD
Temporarily pause execution until an event occurs.
Definition action.h:41
static int const char char buffer[256]
Definition acutest.h:576
int n
Definition acutest.h:577
#define USES_APPLE_DEPRECATED_API
Definition build.h:472
#define RCSID(id)
Definition build.h:485
#define unlikely(_x)
Definition build.h:383
#define UNUSED
Definition build.h:317
#define CONF_PARSER_TERMINATOR
Definition cf_parse.h:660
cf_parse_t func
Override default parsing behaviour for the specified type with a custom parsing function.
Definition cf_parse.h:614
#define FR_CONF_DEPRECATED(_name, _struct, _field)
conf_parser_t entry which raises an error if a matching CONF_PAIR is found
Definition cf_parse.h:412
#define FR_CONF_OFFSET(_name, _struct, _field)
conf_parser_t which parses a single CONF_PAIR, writing the result to a field in a struct
Definition cf_parse.h:283
@ CONF_FLAG_REQUIRED
Error out if no matching CONF_PAIR is found, and no dflt value is set.
Definition cf_parse.h:432
@ CONF_FLAG_NOT_EMPTY
CONF_PAIR is required to have a non zero length value.
Definition cf_parse.h:450
#define FR_CONF_OFFSET_TYPE_FLAGS(_name, _type, _flags, _struct, _field)
conf_parser_t which parses a single CONF_PAIR, writing the result to a field in a struct
Definition cf_parse.h:241
Defines a CONF_PAIR to C data type mapping.
Definition cf_parse.h:597
A section grouping multiple CONF_PAIR.
Definition cf_priv.h:101
#define cf_log_err(_cf, _fmt,...)
Definition cf_util.h:286
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:598
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:605
fr_dict_attr_t const * fr_dict_root(fr_dict_t const *dict)
Return the root attribute of a dictionary.
Definition dict_util.c:2496
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:2791
fr_dict_attr_t const ** out
Where to write a pointer to the resolved fr_dict_attr_t.
Definition dict.h:287
fr_dict_t const ** out
Where to write a pointer to the loaded/resolved fr_dict_t.
Definition dict.h:300
fr_dict_t const * fr_dict_internal(void)
Definition dict_util.c:4749
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:3424
Specifies an attribute which must be present for the module to function.
Definition dict.h:286
Specifies a dictionary which must be loaded/loadable for the module to function.
Definition dict.h:299
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:213
#define MODULE_MAGIC_INIT
Stop people using different module/library/server versions together.
Definition dl_module.h:63
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_TTLS
Definition types.h:66
@ FR_EAP_METHOD_IDENTITY
Definition types.h:46
rlm_rcode_t rcode
The current rcode, from executing the instruction or merging the result from a frame.
Definition interpret.h:134
unlang_action_t eap_virtual_server(request_t *request, eap_session_t *eap_session, virtual_server_t *virtual_server)
Run a subrequest through a virtual server.
Definition base.c:427
static eap_session_t * eap_session_get(request_t *request)
Definition session.h:83
void * opaque
Opaque data used by EAP methods.
Definition session.h:63
bool tls
Whether EAP method uses TLS.
Definition session.h:71
module_method_t process
Callback that should be used to process the next round.
Definition session.h:65
request_t * request
Current request.
Definition session.h:52
Tracks the progress of a single session of any EAP method.
Definition session.h:41
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:828
#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_VOID
User data.
@ FR_TYPE_VSA
Vendor-Specific, for RADIUS attribute 26.
@ FR_TYPE_OCTETS
Raw octets.
unsigned int uint32_t
long int ssize_t
unsigned char uint8_t
module_instance_t const * mi
Instance of the module being instantiated.
Definition module_ctx.h:42
void * thread
Thread specific instance data.
Definition module_ctx.h:43
void * rctx
Resume ctx that a module previously set.
Definition module_ctx.h:45
void * thread
Thread instance data.
Definition module_ctx.h:67
module_instance_t const * mi
Instance of the module being instantiated.
Definition module_ctx.h:64
module_instance_t * mi
Instance of the module being instantiated.
Definition module_ctx.h:51
Temporary structure to hold arguments for module calls.
Definition module_ctx.h:41
Temporary structure to hold arguments for instantiation calls.
Definition module_ctx.h:50
Temporary structure to hold arguments for thread_instantiation calls.
Definition module_ctx.h:63
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:777
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:700
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:287
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:2790
fr_pair_t * fr_pair_copy(TALLOC_CTX *ctx, fr_pair_t const *vp)
Copy a single valuepair.
Definition pair.c:495
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:2683
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:473
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:600
static const conf_parser_t config[]
Definition base.c:186
#define fr_assert(_expr)
Definition rad_assert.h:38
#define REDEBUG(fmt,...)
Definition radclient.h:52
#define RDEBUG2(fmt,...)
Definition radclient.h:54
static rs_t * conf
Definition radsniff.c:53
#define RETURN_UNLANG_HANDLED
Definition rcode.h:61
#define RETURN_UNLANG_INVALID
Definition rcode.h:62
#define RETURN_UNLANG_FAIL
Definition rcode.h:59
#define RETURN_UNLANG_REJECT
Definition rcode.h:58
#define RETURN_UNLANG_OK
Definition rcode.h:60
@ RLM_MODULE_OK
The module is OK, continue.
Definition rcode.h:45
static unlang_action_t mod_handshake_process(UNUSED unlang_result_t *p_result, UNUSED module_ctx_t const *mctx, request_t *request)
static unlang_action_t mod_handshake_resume(unlang_result_t *p_result, module_ctx_t const *mctx, request_t *request)
static fr_dict_attr_t const * attr_user_password
char const * tls_conf_name
virtual_server_t * virtual_server
static fr_dict_attr_t const * attr_eap_message
static fr_dict_attr_t const * attr_eap_channel_binding_message
#define FR_DIAMETER_AVP_FLAG_MANDATORY
static fr_dict_t const * dict_freeradius
static fr_dict_attr_t const * attr_eap_tls_require_client_cert
fr_pair_t * username
SSL_CTX * ssl_ctx
Thread local SSL_CTX.
static fr_dict_attr_t const * attr_ms_chap2_success
static unlang_action_t mod_session_init_resume(unlang_result_t *p_result, module_ctx_t const *mctx, request_t *request)
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_vendor_specific
static fr_dict_attr_t const * attr_reply_message
static unlang_action_t eap_ttls_success(unlang_result_t *p_result, request_t *request, eap_session_t *eap_session)
static int vp2diameter(request_t *request, fr_tls_session_t *tls_session, fr_pair_list_t *list)
static unlang_action_t process_reply(unlang_result_t *p_result, module_ctx_t const *mctx, request_t *request)
static int diameter_verify(request_t *request, uint8_t const *data, unsigned int data_len)
static int mod_thread_instantiate(module_thread_inst_ctx_t const *mctx)
fr_tls_conf_t * tls_conf
CONF_SECTION * server_cs
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)
static fr_dict_attr_t const * attr_user_name
static conf_parser_t submodule_config[]
#define FR_DIAMETER_AVP_FLAG_VENDOR
static unlang_action_t mod_session_init(UNUSED unlang_result_t *p_result, module_ctx_t const *mctx, request_t *request)
fr_dict_attr_autoload_t rlm_eap_ttls_dict_attr[]
static int mod_thread_detach(module_thread_inst_ctx_t const *mctx)
static unlang_action_t eap_ttls_process(unlang_result_t *p_result, module_ctx_t const *mctx, request_t *request, eap_session_t *eap_session, fr_tls_session_t *tls_session)
static int mod_instantiate(module_inst_ctx_t const *mctx)
fr_dict_autoload_t rlm_eap_ttls_dict[]
rlm_eap_submodule_t rlm_eap_ttls
static ttls_tunnel_t * ttls_alloc(TALLOC_CTX *ctx)
username
CONF_SECTION * conf
Module's instance configuration.
Definition module.h:349
size_t inst_size
Size of the module's instance data.
Definition module.h:212
void * data
Module's instance data.
Definition module.h:291
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:429
eap_aka_sim_process_conf_t * inst
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
module_t common
Common fields provided by all modules.
Definition submodule.h:50
Interface exported by EAP submodules.
Definition submodule.h:49
#define fr_table_str_by_value(_table, _number, _def)
Convert an integer to a string.
Definition table.h:772
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
eap_tls_session_t * eap_tls_session_init(request_t *request, eap_session_t *eap_session, SSL_CTX *ssl_ctx, bool client_cert)
Create a new fr_tls_session_t associated with an eap_session_t.
Definition tls.c:1134
int eap_tls_start(request_t *request, eap_session_t *eap_session)
Send an initial EAP-TLS request to the peer.
Definition tls.c:239
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
USES_APPLE_DEPRECATED_API fr_table_num_ordered_t const eap_tls_status_table[]
Definition tls.c:80
fr_tls_conf_t * eap_tls_conf_parse(CONF_SECTION *cs)
Parse TLS configuration.
Definition tls.c:1266
unlang_action_t eap_tls_process(request_t *request, eap_session_t *eap_session)
Process an EAP TLS request.
Definition tls.c:966
eap_tls_status_t state
The state of the EAP-TLS session.
Definition tls.h:127
@ EAP_TLS_INVALID
Invalid, don't reply.
Definition tls.h:91
@ EAP_TLS_HANDLED
TLS code has handled it.
Definition tls.h:94
@ EAP_TLS_RECORD_RECV_COMPLETE
Received final fragment of a record.
Definition tls.h:111
@ EAP_TLS_FAIL
Fail, send fail.
Definition tls.h:93
@ EAP_TLS_ESTABLISHED
Session established, send success (or start phase2).
Definition tls.h:92
fr_tls_session_t * tls_session
TLS session used to authenticate peer or tunnel sensitive data.
Definition tls.h:129
bool include_length
A flag to include length in every TLS Data/Alert packet.
Definition tls.h:138
Tracks the state of an EAP-TLS session.
Definition tls.h:126
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:69
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:42
static fr_slen_t parent
Definition pair.h:841
#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:1913
static fr_slen_t data
Definition value.h:1291
static size_t char ** out
Definition value.h:1023
int virtual_server_cf_parse(UNUSED TALLOC_CTX *ctx, void *out, UNUSED void *parent, CONF_ITEM *ci, UNUSED conf_parser_t const *rule)
Wrapper for the config parser to allow pass1 resolution of virtual servers.
CONF_SECTION * virtual_server_cs(virtual_server_t const *vs)
Return the configuration section for a virtual server.
Additional validation rules for virtual server lookup.