The FreeRADIUS server $Id: 15bac2a4c627c01d1aa2047687b3418955ac7f00 $
Loading...
Searching...
No Matches
rlm_eap_peap.c
Go to the documentation of this file.
1/*
2 * rlm_eap_peap.c contains the interfaces that are called from eap
3 *
4 * Version: $Id: 09eed869b36e6a7d79a82824f617870c24348ccb $
5 *
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2 of the License, or
9 * (at your option) any later version.
10 *
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License
17 * along with this program; if not, write to the Free Software
18 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
19 *
20 * @copyright 2003 Alan DeKok (aland@freeradius.org)
21 * @copyright 2006 The FreeRADIUS server project
22 */
23RCSID("$Id: 09eed869b36e6a7d79a82824f617870c24348ccb $")
24
25#include <freeradius-devel/eap/tls.h>
26
27typedef struct {
28 SSL_CTX *ssl_ctx; //!< Thread local SSL_CTX.
30
31typedef struct {
32 char const *tls_conf_name; //!< TLS configuration.
33 fr_tls_conf_t *tls_conf;
34
35 bool use_tunneled_reply; //!< Use the reply attributes from the tunneled session in
36 //!< the non-tunneled reply to the client.
37
38 bool copy_request_to_tunnel; //!< Use SOME of the request attributes from outside of the
39 //!< tunneled session in the tunneled request.
40
41 virtual_server_t *virtual_server; //!< Virtual server for inner tunnel session.
43
44 bool req_client_cert; //!< Do we do require a client cert?
46
56
62
70
71#define EAP_TLV_SUCCESS (1)
72#define EAP_TLV_FAILURE (2)
73#define EAP_TLV_ACK_RESULT (3)
74
75#define FR_PEAP_EXTENSIONS_TYPE 33
76
78 { FR_CONF_OFFSET("tls", rlm_eap_peap_t, tls_conf_name) },
79
80 { FR_CONF_DEPRECATED("copy_request_to_tunnel", rlm_eap_peap_t, NULL), .dflt = "no" },
81
82 { FR_CONF_DEPRECATED("use_tunneled_reply", rlm_eap_peap_t, NULL), .dflt = "no" },
83
86 .uctx = &(virtual_server_cf_parse_uctx_t){ .process_module_name = "radius"} },
87 { FR_CONF_OFFSET("require_client_cert", rlm_eap_peap_t, req_client_cert), .dflt = "no" },
88
90};
91
93static fr_dict_t const *dict_radius;
94
97 { .out = &dict_freeradius, .proto = "freeradius" },
98 { .out = &dict_radius, .proto = "radius" },
99 { NULL }
100};
101
104
107
110 { .out = &attr_auth_type, .name = "Auth-Type", .type = FR_TYPE_UINT32, .dict = &dict_freeradius },
111 { .out = &attr_eap_tls_require_client_cert, .name = "EAP-TLS-Require-Client-Cert", .type = FR_TYPE_UINT32, .dict = &dict_freeradius },
112
113 { .out = &attr_eap_message, .name = "EAP-Message", .type = FR_TYPE_OCTETS, .dict = &dict_radius },
114 { .out = &attr_user_name, .name = "User-Name", .type = FR_TYPE_STRING, .dict = &dict_radius },
115 { NULL }
116};
117
118
119/*
120 * Send protected EAP-Failure
121 *
122 * Result-TLV = Failure
123 */
124static int eap_peap_failure(request_t *request, eap_session_t *eap_session, fr_tls_session_t *tls_session)
125{
126 uint8_t tlv_packet[11];
127
128 RDEBUG2("FAILURE");
129
130 tlv_packet[0] = FR_EAP_CODE_REQUEST;
131 tlv_packet[1] = eap_session->this_round->response->id +1;
132 tlv_packet[2] = 0;
133 tlv_packet[3] = 11; /* length of this packet */
134 tlv_packet[4] = FR_PEAP_EXTENSIONS_TYPE;
135 tlv_packet[5] = 0x80;
136 tlv_packet[6] = EAP_TLV_ACK_RESULT;
137 tlv_packet[7] = 0;
138 tlv_packet[8] = 2; /* length of the data portion */
139 tlv_packet[9] = 0;
140 tlv_packet[10] = EAP_TLV_FAILURE;
141
142 (tls_session->record_from_buff)(&tls_session->clean_in, tlv_packet, 11);
143
144 /*
145 * FIXME: Check the return code.
146 */
147 fr_tls_session_send(request, tls_session);
148
149 return 1;
150}
151
152/*
153 * Send protected EAP-Success
154 *
155 * Result-TLV = Success
156 */
157static int eap_peap_success(request_t *request, eap_session_t *eap_session, fr_tls_session_t *tls_session)
158{
159 uint8_t tlv_packet[11];
160
161 RDEBUG2("SUCCESS");
162
163 tlv_packet[0] = FR_EAP_CODE_REQUEST;
164 tlv_packet[1] = eap_session->this_round->response->id +1;
165 tlv_packet[2] = 0;
166 tlv_packet[3] = 11; /* length of this packet */
167 tlv_packet[4] = FR_PEAP_EXTENSIONS_TYPE;
168 tlv_packet[5] = 0x80; /* mandatory AVP */
169 tlv_packet[6] = EAP_TLV_ACK_RESULT;
170 tlv_packet[7] = 0;
171 tlv_packet[8] = 2; /* length of the data portion */
172 tlv_packet[9] = 0;
173 tlv_packet[10] = EAP_TLV_SUCCESS;
174
175 (tls_session->record_from_buff)(&tls_session->clean_in, tlv_packet, 11);
176
177 /*
178 * FIXME: Check the return code.
179 */
180 fr_tls_session_send(request, tls_session);
181
182 return 1;
183}
184
185
186static int eap_peap_identity(request_t *request, eap_session_t *eap_session, fr_tls_session_t *tls_session)
187{
188 eap_packet_raw_t eap_packet;
189
190 eap_packet.code = FR_EAP_CODE_REQUEST;
191 eap_packet.id = eap_session->this_round->response->id + 1;
192 eap_packet.length[0] = 0;
193 eap_packet.length[1] = EAP_HEADER_LEN + 1;
194 eap_packet.data[0] = FR_EAP_METHOD_IDENTITY;
195
196 (tls_session->record_from_buff)(&tls_session->clean_in, &eap_packet, sizeof(eap_packet));
197 fr_tls_session_send(request, tls_session);
198 (tls_session->record_init)(&tls_session->clean_in);
199
200 return 1;
201}
202
203/*
204 * Verify the tunneled EAP message.
205 */
206static int eap_peap_verify(request_t *request, peap_tunnel_t *peap_tunnel,
207 uint8_t const *data, size_t data_len)
208{
209 eap_packet_raw_t const *eap_packet = (eap_packet_raw_t const *) data;
210 eap_type_t eap_method;
211
212 /*
213 * No data, OR only 1 byte of EAP type.
214 */
215 if (!data || (data_len == 0) || ((data_len <= 1) && (data[0] != FR_EAP_METHOD_IDENTITY))) return 0;
216
217 /*
218 * Since the full EAP header is sent for the EAP Extensions type (Type 33),
219 * but not for other Types, it is difficult for the implementation to distinguish
220 * an Extensions Request (Code 1) from an EAP Type 1 (Identity) Request packet.
221 *
222 * i.e. The only way to validate PEAP inner method packets properly is to know
223 * we just send a protected success/failure.
224 */
225 switch (peap_tunnel->status) {
228 if (eap_packet->data[0] != FR_PEAP_EXTENSIONS_TYPE) {
229 REDEBUG("Invalid inner tunnel data, expected method (%u), got (%u)",
230 FR_PEAP_EXTENSIONS_TYPE, eap_packet->data[0]);
231 return -1;
232 }
233 return 0;
234
235 default:
236 break;
237 }
238
239 eap_method = data[0]; /* Inner EAP header misses off code and identifier */
240 switch (eap_method) {
242 RDEBUG2("Received EAP-Identity-Response");
243 return 0;
244
245 /*
246 * We normally do Microsoft MS-CHAPv2 (26), versus
247 * Cisco MS-CHAPv2 (29).
248 */
250 default:
251 RDEBUG2("EAP method %s (%d)", eap_type2name(eap_method), eap_method);
252 return 0;
253 }
254
255}
256
257/*
258 * Convert a pseudo-EAP packet to a list of fr_pair_t's.
259 */
260static void eap_peap_inner_to_pairs(TALLOC_CTX *ctx, fr_pair_list_t *pairs,
261 eap_round_t *eap_round,
262 uint8_t const *data, size_t data_len)
263{
264 size_t total;
265 uint8_t *p;
266 fr_pair_t *vp = NULL;
267
268 if (data_len > 65535) return; /* paranoia */
269
271 total = data_len;
272 if (total > 249) total = 249;
273
274 /*
275 * Hand-build an EAP packet from the crap in PEAP version 0.
276 */
277 MEM(fr_pair_value_mem_alloc(vp, &p, EAP_HEADER_LEN + total, false) == 0);
279 p[1] = eap_round->response->id;
280 p[2] = (data_len + EAP_HEADER_LEN) >> 8;
281 p[3] = (data_len + EAP_HEADER_LEN) & 0xff;
282 memcpy(p + EAP_HEADER_LEN, data, total);
283
284 fr_pair_append(pairs, vp);
285 while (total < data_len) {
287 fr_pair_value_memdup(vp, data + total, (data_len - total), false);
288
289 total += vp->vp_length;
290
291 fr_pair_append(pairs, vp);
292 }
293}
294
295
296/*
297 * Convert a list of fr_pair_t's to an EAP packet, through the
298 * simple expedient of dumping the EAP message
299 */
300static int eap_peap_inner_from_pairs(request_t *request, fr_tls_session_t *tls_session, fr_pair_list_t *vps)
301{
302 fr_pair_t *this;
303
305
306 /*
307 * Send the EAP data in the first attribute, WITHOUT the
308 * header.
309 */
310 this = fr_pair_list_head(vps);
311 (tls_session->record_from_buff)(&tls_session->clean_in, this->vp_octets + EAP_HEADER_LEN,
312 this->vp_length - EAP_HEADER_LEN);
313
314 /*
315 * Send the rest of the EAP data, but skipping the first VP.
316 */
317 for (this = fr_pair_list_next(vps, this);
318 this;
319 this = fr_pair_list_next(vps, this)) {
320 (tls_session->record_from_buff)(&tls_session->clean_in, this->vp_octets, this->vp_length);
321 }
322
323 fr_tls_session_send(request, tls_session);
324
325 return 1;
326}
327
328
329/*
330 * See if there's a TLV in the response.
331 */
332static int eap_peap_check_tlv(request_t *request, uint8_t const *data, size_t data_len)
333{
334 eap_packet_raw_t const *eap_packet = (eap_packet_raw_t const *) data;
335
336 if (data_len < 11) return 0;
337
338 /*
339 * Look for success or failure.
340 */
341 if ((eap_packet->code == FR_EAP_CODE_RESPONSE) &&
342 (eap_packet->data[0] == FR_PEAP_EXTENSIONS_TYPE)) {
343 if (data[10] == EAP_TLV_SUCCESS) {
344 return 1;
345 }
346
347 if (data[10] == EAP_TLV_FAILURE) {
348 RDEBUG2("Client rejected our response. The password is probably incorrect");
349 return 0;
350 }
351 }
352
353 RDEBUG2("Unknown TLV %02x", data[10]);
354
355 return 0;
356}
357
358
359/*
360 * Use a reply packet to determine what to do.
361 */
362static unlang_action_t process_reply(unlang_result_t *p_result, request_t *request, UNUSED void *uctx)
363{
364 eap_session_t *eap_session = talloc_get_type_abort(uctx, eap_session_t);
365 eap_tls_session_t *eap_tls_session = talloc_get_type_abort(eap_session->opaque, eap_tls_session_t);
366 fr_tls_session_t *tls_session = eap_tls_session->tls_session;
367 fr_pair_list_t vps;
368 peap_tunnel_t *t = tls_session->opaque;
369 request_t *parent = request->parent;
370 fr_packet_t *reply = request->reply;
371
372 p_result->priority = MOD_PRIORITY_MAX;
373
374 if (RDEBUG_ENABLED2) {
375
376 /*
377 * Note that we don't do *anything* with the reply
378 * attributes.
379 */
380 if (FR_RADIUS_PACKET_CODE_VALID(reply->code)) {
381 RDEBUG2("Got tunneled reply %s", fr_radius_packet_name[reply->code]);
382 } else {
383 RDEBUG2("Got tunneled reply code %i", reply->code);
384 }
385 log_request_pair_list(L_DBG_LVL_2, request, NULL, &request->reply_pairs, NULL);
386 }
387
388 switch (reply->code) {
390 RDEBUG2("Tunneled authentication was successful");
392 eap_peap_success(request, eap_session, tls_session);
394
396 RDEBUG2("Tunneled authentication was rejected");
398 eap_peap_failure(request, eap_session, tls_session);
400
402 RDEBUG2("Got tunneled Access-Challenge");
403
404 /*
405 * PEAP takes only EAP-Message attributes inside
406 * of the tunnel. Any Reply-Message in the
407 * Access-Challenge is ignored.
408 */
409 fr_pair_list_init(&vps);
410 MEM(fr_pair_list_copy_by_da(t, &vps, &request->reply_pairs, attr_eap_message, 0) >= 0);
411
412 /*
413 * Handle the ACK, by tunneling any necessary reply
414 * VP's back to the client.
415 */
416 if (!fr_pair_list_empty(&vps)) {
417 eap_peap_inner_from_pairs(parent, tls_session, &vps);
418 fr_pair_list_free(&vps);
419 }
421
422 default:
423 RDEBUG2("Unknown RADIUS packet type %d: rejecting tunneled user", reply->code);
425 }
426}
427
428
429static char const *peap_state(peap_tunnel_t *t)
430{
431 switch (t->status) {
433 return "TUNNEL ESTABLISHED";
434
436 return "WAITING FOR INNER IDENTITY";
437
439 return "send tlv success";
440
442 return "send tlv failure";
443
445 return "phase2_init";
446
448 return "phase2";
449
450 default:
451 break;
452 }
453 return "?";
454}
455
456/*
457 * Process the pseudo-EAP contents of the tunneled data.
458 */
460 eap_session_t *eap_session, fr_tls_session_t *tls_session)
461{
462 peap_tunnel_t *t = tls_session->opaque;
463 request_t *child = NULL;
464 fr_pair_t *vp;
466 uint8_t const *data;
467 size_t data_len;
468 eap_round_t *eap_round = eap_session->this_round;
469 rlm_eap_peap_t *inst = talloc_get_type_abort(mctx->mi->data, rlm_eap_peap_t);
470
471 /*
472 * Just look at the buffer directly, without doing
473 * record_to_buff. This lets us avoid another data copy.
474 */
475 data_len = tls_session->clean_out.used;
476 tls_session->clean_out.used = 0;
477 data = tls_session->clean_out.data;
478
479 RDEBUG2("PEAP state %s", peap_state(t));
480
481 if ((t->status != PEAP_STATUS_TUNNEL_ESTABLISHED) && (eap_peap_verify(request, t, data, data_len) < 0)) {
482 REDEBUG("Tunneled data is invalid");
484 }
485
486 switch (t->status) {
488 /* FIXME: should be no data in the buffer here, check & assert? */
489
490 if (SSL_session_reused(tls_session->ssl)) {
491 RDEBUG2("Skipping Phase2 because of session resumption");
493 /* we're good, send success TLV */
495 eap_peap_success(request, eap_session, tls_session);
496
497 } else {
498 /* send an identity request */
501 eap_peap_identity(request, eap_session, tls_session);
502 }
503 rcode = RLM_MODULE_HANDLED;
504 goto finish;
505
507 /* we're expecting an identity response */
508 if (data[0] != FR_EAP_METHOD_IDENTITY) {
509 REDEBUG("Expected EAP-Identity, got something else");
510 rcode = RLM_MODULE_REJECT;
511 goto finish;
512 }
513
514 /*
515 * Save it for later.
516 */
518 t->username->vp_tainted = true;
519
520 fr_pair_value_bstrndup(t->username, (char const *)data + 1, data_len - 1, true);
521
522 RDEBUG2("Got inner identity \"%pV\"", &t->username->data);
524 break;
525
526 /*
527 * If we authenticated the user, then it's OK.
528 */
530 if (eap_peap_check_tlv(request, data, data_len)) {
531 RDEBUG2("Success");
532 rcode = RLM_MODULE_OK;
533 goto finish;
534 }
535
536 /*
537 * Otherwise, the client rejected the session
538 * resumption. If the session is being re-used,
539 * we need to do a full authentication.
540 *
541 * We do this by sending an EAP-Identity request
542 * inside of the PEAP tunnel.
543 */
545 RDEBUG2("Client rejected session resumption. Re-starting full authentication");
546
547 /*
548 * Mark session resumption status.
549 */
552
553 eap_peap_identity(request, eap_session, tls_session);
554 rcode = RLM_MODULE_HANDLED;
555 goto finish;
556 }
557
558 REDEBUG("Sent a success, but received something weird in return");
559 rcode = RLM_MODULE_REJECT;
560 goto finish;
561
562 /*
563 * Supplicant ACKs our failure.
564 */
566 RINDENT();
567 REDEBUG("The users session was previously rejected: returning reject (again.)");
568 RIDEBUG("This means you need to read the PREVIOUS messages in the debug output");
569 RIDEBUG("to find out the reason why the user was rejected");
570 RIDEBUG("Look for \"reject\" or \"fail\". Those earlier messages will tell you");
571 RIDEBUG("what went wrong, and how to fix the problem");
572 REXDENT();
573
575
577 RDEBUG2("In state machine in phase2 init?");
578 break;
579
581 break;
582
583 default:
584 REDEBUG("Unhandled state in peap");
585 rcode = RLM_MODULE_REJECT;
586 goto finish;
587 }
588
589 MEM(child = unlang_subrequest_alloc(request, request->proto_dict));
590 fr_assert(fr_pair_list_empty(&child->request_pairs));
591
592 switch (t->status) {
593 /*
594 * If we're in PHASE2_INIT, the phase2 method hasn't been
595 * sent an Identity packet yet; do so from the stored
596 * username and this will kick off the phase2 eap method
597 */
599 {
600 size_t len;
601 uint8_t *q;
602
604
605 len = t->username->vp_length + EAP_HEADER_LEN + 1;
607
608 MEM(vp = fr_pair_afrom_da(child->request_ctx, attr_eap_message));
609 MEM(fr_pair_value_mem_alloc(vp, &q, len, false) == 0);
611 q[1] = eap_round->response->id;
612 q[2] = (len >> 8) & 0xff;
613 q[3] = len & 0xff;
615 memcpy(q + EAP_HEADER_LEN + 1,
616 t->username->vp_strvalue, t->username->vp_length);
617 fr_pair_append(&child->request_pairs, vp);
618 }
619 break;
620
622 eap_peap_inner_to_pairs(child->request_ctx, &child->request_pairs,
623 eap_round, data, data_len);
624 if (fr_pair_list_empty(&child->request_pairs)) {
625 TALLOC_FREE(child);
626 RDEBUG2("Unable to convert tunneled EAP packet to internal server data structures");
627 rcode = RLM_MODULE_REJECT;
628 goto finish;
629 }
630 break;
631
632 default:
633 REDEBUG("Invalid state change in PEAP");
634 rcode = RLM_MODULE_REJECT;
635 goto finish;
636 }
637
638 RDEBUG2("Got tunneled request");
639 log_request_pair_list(L_DBG_LVL_2, request, NULL, &child->request_pairs, NULL);
640
641 /*
642 * Update other items in the request_t data structure.
643 */
644 if (!t->username) {
645 /*
646 * There's no User-Name in the tunneled session,
647 * so we add one here, by pulling it out of the
648 * EAP-Identity packet.
649 */
650 if ((data[0] == FR_EAP_METHOD_IDENTITY) && (data_len > 1)) {
652 fr_assert(t->username != NULL);
653 t->username->vp_tainted = true;
654
655 fr_pair_value_bstrndup(t->username, (char const *)data + 1, data_len - 1, true);
656
657 RDEBUG2("Got tunneled identity of %pV", &t->username->data);
658 }
659 } /* else there WAS a t->username */
660
661 if (t->username) {
662 vp = fr_pair_copy(child->request_ctx, t->username);
663 fr_pair_append(&child->request_pairs, vp);
664 RDEBUG2("Setting request.User-Name from tunneled (inner) identity \"%s\"",
665 vp->vp_strvalue);
666 } else {
667 RDEBUG2("No tunnel username (SSL resumption?)");
668 }
669
670 /*
671 * Set the child up for execution. This represents
672 * a pseudo protocol inside of PEAPs inner EAP method.
673 */
674 if (unlang_subrequest_child_push(&eap_session->submodule_result, child,
675 child,
676 false, UNLANG_SUB_FRAME) < 0) goto finish;
677
678 /*
679 * Setup a function in thie child to process the
680 * result of the subrequest.
681 */
683 child,
684 NULL,
685 /*
686 * Run in the child after the virtual sever executes.
687 * This sets the rcode for the subrequest, which is
688 * written to eap_session->submodule_result.
689 */
691 NULL, 0,
692 UNLANG_SUB_FRAME, eap_session) != UNLANG_ACTION_PUSHED_CHILD) goto finish;
693
694 /*
695 * Run inner tunnel in the context of the child
696 */
697 if (unlikely(eap_virtual_server(child, eap_session, inst->virtual_server) == UNLANG_ACTION_FAIL)) {
698 rcode = RLM_MODULE_FAIL;
699 goto finish;
700 }
701
702 /*
703 * We now yield to the subrequest. unlang_subrequest_child_push
704 * pushed a new frame in the context of the parent which'll start
705 * the subrequest.
706 */
708
709finish:
710 if (child) {
711 /*
712 * We can't just free the child, we need to detach it
713 * and then let the interpreter to unwind and eventually
714 * free the request.
715 */
716 request_detach(child);
718 }
719
720 RETURN_UNLANG_RCODE(rcode);
721}
722
723/*
724 * Allocate the PEAP per-session data
725 */
726static peap_tunnel_t *peap_alloc(TALLOC_CTX *ctx)
727{
728 peap_tunnel_t *t;
729
730 t = talloc_zero(ctx, peap_tunnel_t);
732
733 return t;
734}
735
736/*
737 * Construct the reply appropriately based on the rcode from PEAP processing.
738 */
740{
741 eap_session_t *eap_session = talloc_get_type_abort(mctx->rctx, eap_session_t);
742 eap_tls_session_t *eap_tls_session = talloc_get_type_abort(eap_session->opaque, eap_tls_session_t);
743 fr_tls_session_t *tls_session = eap_tls_session->tls_session;
744
745 RDEBUG3("Tunneled request complete");
746
747 switch (eap_session->submodule_result.rcode) {
749 eap_tls_fail(request, eap_session);
750 break;
751
753 eap_tls_request(request, eap_session);
754 break;
755
756 case RLM_MODULE_OK:
757 {
758 eap_tls_prf_label_t prf_label;
759
760 eap_crypto_prf_label_init(&prf_label, eap_session,
761 "client EAP encryption",
762 sizeof("client EAP encryption") - 1);
763
764 /*
765 * Success: Automatically return MPPE keys.
766 */
767 if (eap_tls_success(request, eap_session, &prf_label) > 0) RETURN_UNLANG_FAIL;
768 p_result->rcode = RLM_MODULE_OK;
769
770 /*
771 * Write the session to the session cache
772 *
773 * We do this here (instead of relying on OpenSSL to call the
774 * session caching callback), because we only want to write
775 * session data to the cache if all phases were successful.
776 *
777 * If we wrote out the cache data earlier, and the server
778 * exited whilst the session was in progress, the supplicant
779 * could resume the session (and get access) even if phase2
780 * never completed.
781 */
782 return fr_tls_cache_pending_push(request, tls_session);
783 }
784
785 /*
786 * No response packet, MUST be proxying it.
787 * The main EAP module will take care of discovering
788 * that the request now has a "proxy" packet, and
789 * will proxy it, rather than returning an EAP packet.
790 */
792 break;
793
794 default:
795 eap_tls_fail(request, eap_session);
796 break;
797 }
798
800}
801
803{
804 eap_session_t *eap_session = talloc_get_type_abort(mctx->rctx, eap_session_t);
805 eap_tls_session_t *eap_tls_session = talloc_get_type_abort(eap_session->opaque, eap_tls_session_t);
806 fr_tls_session_t *tls_session = eap_tls_session->tls_session;
807 peap_tunnel_t *peap = talloc_get_type_abort(tls_session->opaque, peap_tunnel_t);
808
809 if ((eap_tls_session->state == EAP_TLS_INVALID) || (eap_tls_session->state == EAP_TLS_FAIL)) {
810 REDEBUG("[eap-tls process] = %s", fr_table_str_by_value(eap_tls_status_table, eap_tls_session->state, "<INVALID>"));
811 } else {
812 RDEBUG2("[eap-tls process] = %s", fr_table_str_by_value(eap_tls_status_table, eap_tls_session->state, "<INVALID>"));
813 }
814
815 switch (eap_tls_session->state) {
816 /*
817 * EAP-TLS handshake was successful, tell the
818 * client to keep talking.
819 *
820 * If this was EAP-TLS, we would just return
821 * an EAP-TLS-Success packet here.
822 */
825 break;
826
827 /*
828 * The TLS code is still working on the TLS
829 * exchange, and it's a valid TLS request.
830 * do nothing.
831 */
832 case EAP_TLS_HANDLED:
833 /*
834 * FIXME: If the SSL session is established, grab the state
835 * and EAP id from the inner tunnel, and update it with
836 * the expected EAP id!
837 */
839
840 /*
841 * Handshake is done, proceed with decoding tunneled
842 * data.
843 */
845 /*
846 * TLSv1.3 makes application data immediately
847 * available when the handshake is finished.
848 */
849 if (SSL_is_init_finished(tls_session->ssl) && (peap->status == PEAP_STATUS_INVALID)) {
851 }
852 break;
853
854 /*
855 * Anything else: fail.
856 */
857 default:
859 }
860
861 /*
862 * Session is established, proceed with decoding
863 * tunneled data.
864 */
865 RDEBUG2("Session established. Decoding tunneled data");
866
867 /*
868 * We may need PEAP data associated with the session, so
869 * allocate it here, if it wasn't already alloacted.
870 */
871 if (!tls_session->opaque) tls_session->opaque = peap_alloc(tls_session);
872
873 /*
874 * Setup the resume point to prepare the correct reply based on
875 * the rcode coming back from PEAP processing.
876 */
877 (void) unlang_module_yield(request, process_rcode, NULL, 0, eap_session);
878
879 /*
880 * Process the PEAP portion of the request.
881 */
882 return eap_peap_process(&eap_session->submodule_result, mctx, request, eap_session, tls_session);
883}
884
885/*
886 * Do authentication, by letting EAP-TLS do most of the work.
887 */
889 request_t *request)
890{
891 eap_session_t *eap_session = eap_session_get(request->parent);
892
893 /*
894 * Setup the resumption frame to process the result
895 */
896 (void)unlang_module_yield(request, mod_handshake_resume, NULL, 0, eap_session);
897
898 /*
899 * Process TLS layer until done.
900 */
901 return eap_tls_process(request, eap_session);
902}
903
905{
906 rlm_eap_peap_t *inst = talloc_get_type_abort(mctx->mi->data, rlm_eap_peap_t);
907 rlm_eap_peap_thread_t *t = talloc_get_type_abort(mctx->thread, rlm_eap_peap_thread_t);
908 eap_session_t *eap_session = eap_session_get(request->parent);
909 eap_tls_session_t *eap_tls_session;
910 fr_tls_session_t *tls_session;
911
912 fr_pair_t *vp;
913 bool client_cert;
914
915 /*
916 * EAP-TLS-Require-Client-Cert attribute will override
917 * the require_client_cert configuration option.
918 */
919 vp = fr_pair_find_by_da(&request->control_pairs, NULL, attr_eap_tls_require_client_cert);
920 if (vp) {
921 client_cert = vp->vp_uint32 ? true : false;
922 } else {
923 client_cert = inst->req_client_cert;
924 }
925
926 eap_session->opaque = eap_tls_session = eap_tls_session_init(request, eap_session, t->ssl_ctx, client_cert);
927 if (!eap_tls_session) RETURN_UNLANG_FAIL;
928
929 tls_session = eap_tls_session->tls_session;
930
931 /*
932 * As it is a poorly designed protocol, PEAP uses
933 * bits in the TLS header to indicate PEAP
934 * version numbers. For now, we only support
935 * PEAP version 0, so it doesn't matter too much.
936 * However, if we support later versions of PEAP,
937 * we will need this flag to indicate which
938 * version we're currently dealing with.
939 */
940 eap_tls_session->base_flags = 0x00;
941
942 /*
943 * PEAP version 0 requires 'include_length = no',
944 * so rather than hoping the user figures it out,
945 * we force it here.
946 */
947 eap_tls_session->include_length = false;
948
949 /*
950 * TLS session initialization is over. Now handle TLS
951 * related handshaking or application data.
952 */
953 if (eap_tls_start(request, eap_session) < 0) {
954 talloc_free(eap_tls_session);
956 }
957
958 /*
959 * Session resumption requires the storage of data, so
960 * allocate it if it doesn't already exist.
961 */
962 tls_session->opaque = peap_alloc(tls_session);
963
964 eap_session->process = mod_handshake_process;
965
967}
968
969/*
970 * Send an initial eap-tls request to the peer, using the libeap functions.
971 */
973{
974 rlm_eap_peap_t *inst = talloc_get_type_abort(mctx->mi->data, rlm_eap_peap_t);
975 eap_session_t *eap_session = eap_session_get(request->parent);
976
977 eap_session->tls = true;
978
979 (void) unlang_module_yield(request, mod_session_init_resume, NULL, 0, NULL);
980
981 if (inst->tls_conf->new_session) return fr_tls_new_session_push(request, inst->tls_conf);
982
984}
985
987{
988 rlm_eap_peap_t *inst = talloc_get_type_abort(mctx->mi->data, rlm_eap_peap_t);
989 rlm_eap_peap_thread_t *t = talloc_get_type_abort(mctx->thread, rlm_eap_peap_thread_t);
990
991 t->ssl_ctx = fr_tls_ctx_alloc(inst->tls_conf, false);
992 if (!t->ssl_ctx) return -1;
993
994 return 0;
995}
996
998{
999 rlm_eap_peap_thread_t *t = talloc_get_type_abort(mctx->thread, rlm_eap_peap_thread_t);
1000
1001 if (likely(t->ssl_ctx != NULL)) SSL_CTX_free(t->ssl_ctx);
1002 t->ssl_ctx = NULL;
1003
1004 return 0;
1005}
1006
1007/*
1008 * Attach the module.
1009 */
1010static int mod_instantiate(module_inst_ctx_t const *mctx)
1011{
1012 rlm_eap_peap_t *inst = talloc_get_type_abort(mctx->mi->data, rlm_eap_peap_t);
1013 CONF_SECTION *conf = mctx->mi->conf;
1014
1015 fr_assert(inst->virtual_server);
1016
1017 inst->server_cs = virtual_server_cs(inst->virtual_server);
1018
1019 /*
1020 * Read tls configuration, either from group given by 'tls'
1021 * option, or from the eap-tls configuration.
1022 */
1023 inst->tls_conf = eap_tls_conf_parse(conf);
1024 if (!inst->tls_conf) {
1025 cf_log_err(conf, "Failed initializing SSL context");
1026 return -1;
1027 }
1028
1029 return 0;
1030}
1031
1032/*
1033 * The module name should be the only globally exported symbol.
1034 * That is, everything else should be 'static'.
1035 */
1038 .common = {
1039 .magic = MODULE_MAGIC_INIT,
1040 .name = "eap_peap",
1041 .inst_size = sizeof(rlm_eap_peap_t),
1043 .instantiate = mod_instantiate,
1044
1045 .thread_inst_size = sizeof(rlm_eap_peap_thread_t),
1046 .thread_instantiate = mod_thread_instantiate,
1047 .thread_detach = mod_thread_detach,
1048 },
1049 .provides = { FR_EAP_METHOD_PEAP },
1050 .session_init = mod_session_init, /* Initialise a new EAP session */
1051};
unlang_action_t
Returned by unlang_op_t calls, determine the next action of the interpreter.
Definition action.h:35
@ UNLANG_ACTION_PUSHED_CHILD
unlang_t pushed a new child onto the stack, execute it instead of continuing.
Definition action.h:39
@ 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
#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:662
cf_parse_t func
Override default parsing behaviour for the specified type with a custom parsing function.
Definition cf_parse.h:616
#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:414
#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:284
@ CONF_FLAG_REQUIRED
Error out if no matching CONF_PAIR is found, and no dflt value is set.
Definition cf_parse.h:434
@ CONF_FLAG_NOT_EMPTY
CONF_PAIR is required to have a non zero length value.
Definition cf_parse.h:452
#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:599
A section grouping multiple CONF_PAIR.
Definition cf_priv.h:101
#define cf_log_err(_cf, _fmt,...)
Definition cf_util.h:289
eap_packet_t * response
Packet we received from the peer.
Definition compose.h:49
uint8_t id
Definition compose.h:37
Contains a pair of request and response packets.
Definition compose.h:48
#define MEM(x)
Definition debug.h:36
@ 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 ** out
Where to write a pointer to the resolved fr_dict_attr_t.
Definition dict.h:274
fr_dict_t const ** out
Where to write a pointer to the loaded/resolved fr_dict_t.
Definition dict.h:287
Specifies an attribute which must be present for the module to function.
Definition dict.h:273
Specifies a dictionary which must be loaded/loadable for the module to function.
Definition dict.h:286
#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
char const * eap_type2name(eap_type_t method)
Return an EAP-name for a particular type.
Definition types.c:54
@ FR_EAP_CODE_RESPONSE
Definition types.h:38
@ FR_EAP_CODE_REQUEST
Definition types.h:37
uint8_t data[1]
Definition types.h:125
enum eap_type eap_type_t
uint8_t code
Definition types.h:122
#define EAP_HEADER_LEN
Definition types.h:34
uint8_t length[2]
Definition types.h:124
uint8_t id
Definition types.h:123
@ FR_EAP_METHOD_MSCHAPV2
Definition types.h:71
@ FR_EAP_METHOD_IDENTITY
Definition types.h:46
@ FR_EAP_METHOD_PEAP
Definition types.h:70
Structure to represent packet format of eap on wire
Definition types.h:121
#define unlang_function_push_with_result(_result_p, _request, _func, _repeat, _signal, _sigmask, _top_frame, _uctx)
Push a generic function onto the unlang stack that produces a result.
Definition function.h:144
void unlang_interpret_signal(request_t *request, fr_signal_t action)
Send a signal (usually stop) to a request.
Definition interpret.c:1397
unlang_mod_action_t priority
The priority or action for that rcode.
Definition interpret.h:136
#define UNLANG_SUB_FRAME
Definition interpret.h:37
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
unlang_result_t submodule_result
Result of last submodule call.
Definition session.h:47
eap_round_t * this_round
The EAP response we're processing, and the EAP request we're building.
Definition session.h:60
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 REXDENT()
Exdent (unindent) R* messages by one level.
Definition log.h:443
#define RDEBUG3(fmt,...)
Definition log.h:343
#define RINDENT()
Indent R* messages by one level.
Definition log.h:430
talloc_free(reap)
@ L_DBG_LVL_2
2nd highest priority debug messages (-xx | -X).
Definition log.h:71
@ FR_TYPE_STRING
String of printable characters.
@ FR_TYPE_UINT32
32 Bit unsigned integer.
@ FR_TYPE_VOID
User data.
@ FR_TYPE_OCTETS
Raw octets.
unsigned char uint8_t
@ MOD_PRIORITY_MAX
Definition mod_action.h:56
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
int fr_pair_list_copy_by_da(TALLOC_CTX *ctx, fr_pair_list_t *to, fr_pair_list_t const *from, fr_dict_attr_t const *da, unsigned int count)
Duplicate pairs in a list matching the specified da.
Definition pair.c:2409
int fr_pair_value_memdup(fr_pair_t *vp, uint8_t const *src, size_t len, bool tainted)
Copy data into an "octets" data type.
Definition pair.c:2938
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:698
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:1343
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:2788
fr_pair_t * fr_pair_copy(TALLOC_CTX *ctx, fr_pair_t const *vp)
Copy a single valuepair.
Definition pair.c:493
int fr_pair_value_mem_alloc(fr_pair_t *vp, uint8_t **out, size_t size, bool tainted)
Pre-allocate a memory buffer for a "octets" type value pair.
Definition pair.c:2887
static const conf_parser_t config[]
Definition base.c:186
char const * fr_radius_packet_name[FR_RADIUS_CODE_MAX]
Definition base.c:114
#define fr_assert(_expr)
Definition rad_assert.h:38
#define REDEBUG(fmt,...)
Definition radclient.h:52
#define RDEBUG_ENABLED2()
Definition radclient.h:50
#define RDEBUG2(fmt,...)
Definition radclient.h:54
#define FR_RADIUS_PACKET_CODE_VALID(_x)
Definition radius.h:52
static rs_t * conf
Definition radsniff.c:53
#define RIDEBUG(fmt,...)
Definition radsniff.h:65
#define RETURN_UNLANG_HANDLED
Definition rcode.h:61
#define RETURN_UNLANG_RCODE(_rcode)
Definition rcode.h:57
#define RETURN_UNLANG_FAIL
Definition rcode.h:59
#define RETURN_UNLANG_REJECT
Definition rcode.h:58
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:45
@ RLM_MODULE_FAIL
Module failed, don't reply.
Definition rcode.h:44
@ RLM_MODULE_REJECT
Immediately reject the request.
Definition rcode.h:43
@ RLM_MODULE_UPDATED
OK (pairs modified).
Definition rcode.h:51
@ RLM_MODULE_HANDLED
The module handled the request, so stop.
Definition rcode.h:46
int request_detach(request_t *child)
Unlink a subrequest from its parent.
Definition request.c:542
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)
bool copy_request_to_tunnel
Use SOME of the request attributes from outside of the tunneled session in the tunneled request.
#define EAP_TLV_FAILURE
peap_status
@ PEAP_STATUS_PHASE2_INIT
@ PEAP_STATUS_TUNNEL_ESTABLISHED
@ PEAP_STATUS_PHASE2
@ PEAP_STATUS_INNER_IDENTITY_REQ_SENT
@ PEAP_STATUS_SENT_TLV_SUCCESS
@ PEAP_STATUS_SENT_TLV_FAILURE
@ PEAP_STATUS_INVALID
static unlang_action_t process_reply(unlang_result_t *p_result, request_t *request, UNUSED void *uctx)
fr_dict_attr_t const * attr_eap_message
peap_resumption
@ PEAP_RESUMPTION_YES
@ PEAP_RESUMPTION_NO
@ PEAP_RESUMPTION_MAYBE
static peap_tunnel_t * peap_alloc(TALLOC_CTX *ctx)
virtual_server_t * virtual_server
Virtual server for inner tunnel session.
static fr_dict_t const * dict_freeradius
fr_dict_attr_t const * attr_eap_tls_require_client_cert
static int eap_peap_success(request_t *request, eap_session_t *eap_session, fr_tls_session_t *tls_session)
SSL_CTX * ssl_ctx
Thread local SSL_CTX.
fr_dict_attr_autoload_t rlm_eap_peap_dict_attr[]
fr_dict_autoload_t rlm_eap_peap_dict[]
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 int eap_peap_identity(request_t *request, eap_session_t *eap_session, fr_tls_session_t *tls_session)
#define FR_PEAP_EXTENSIONS_TYPE
fr_dict_attr_t const * attr_auth_type
static unlang_action_t eap_peap_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)
char const * tls_conf_name
TLS configuration.
fr_tls_conf_t * tls_conf
static int eap_peap_check_tlv(request_t *request, uint8_t const *data, size_t data_len)
static void eap_peap_inner_to_pairs(TALLOC_CTX *ctx, fr_pair_list_t *pairs, eap_round_t *eap_round, uint8_t const *data, size_t data_len)
peap_status status
bool home_access_accept
peap_resumption session_resumption_state
bool req_client_cert
Do we do require a client cert?
rlm_eap_submodule_t rlm_eap_peap
bool use_tunneled_reply
Use the reply attributes from the tunneled session in the non-tunneled reply to the client.
static int mod_thread_instantiate(module_thread_inst_ctx_t const *mctx)
static int eap_peap_inner_from_pairs(request_t *request, fr_tls_session_t *tls_session, fr_pair_list_t *vps)
static unlang_action_t process_rcode(unlang_result_t *p_result, module_ctx_t const *mctx, request_t *request)
static char const * peap_state(peap_tunnel_t *t)
#define EAP_TLV_SUCCESS
fr_dict_attr_t const * attr_user_name
static conf_parser_t submodule_config[]
static int eap_peap_failure(request_t *request, eap_session_t *eap_session, fr_tls_session_t *tls_session)
static unlang_action_t mod_session_init(UNUSED unlang_result_t *p_result, module_ctx_t const *mctx, request_t *request)
static int eap_peap_verify(request_t *request, peap_tunnel_t *peap_tunnel, uint8_t const *data, size_t data_len)
static int mod_thread_detach(module_thread_inst_ctx_t const *mctx)
static int mod_instantiate(module_inst_ctx_t const *mctx)
fr_pair_t * username
CONF_SECTION * server_cs
#define EAP_TLV_ACK_RESULT
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
@ FR_SIGNAL_CANCEL
Request has been cancelled.
Definition signal.h:40
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
module_t common
Common fields provided by all modules.
Definition submodule.h:50
Interface exported by EAP submodules.
Definition submodule.h:49
request_t * unlang_subrequest_alloc(request_t *parent, fr_dict_t const *namespace)
Allocate a subrequest to run through a virtual server at some point in the future.
Definition subrequest.c:304
int unlang_subrequest_child_push(unlang_result_t *p_result, request_t *child, void const *unique_session_ptr, bool free_child, bool top_frame)
Push a pre-existing child back onto the stack as a subrequest.
Definition subrequest.c:428
#define fr_table_str_by_value(_table, _number, _def)
Convert an integer to a string.
Definition table.h:772
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
int base_flags
Some protocols use the reserved bits of the EAP-TLS flags (such as PEAP).
Definition tls.h:132
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
static fr_slen_t data
Definition value.h:1291
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.