2 * rlm_eap_peap.c contains the interfaces that are called from eap
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.
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.
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
20 * Copyright 2003 Alan DeKok <aland@freeradius.org>
21 * Copyright 2006 The FreeRADIUS server project
24 #include <freeradius-devel/ident.h>
29 typedef struct rlm_eap_peap_t {
34 fr_tls_server_conf_t *tls_conf;
37 * Default tunneled EAP type
39 char *default_eap_type_name;
43 * Use the reply attributes from the tunneled session in
44 * the non-tunneled reply to the client.
46 int use_tunneled_reply;
49 * Use SOME of the request attributes from outside of the
50 * tunneled session in the tunneled request
52 int copy_request_to_tunnel;
56 * Proxy tunneled session as EAP, or as de-capsulated
59 int proxy_tunneled_request_as_eap;
63 * Virtual server for inner tunnel session.
68 * Do we do SoH request?
71 char *soh_virtual_server;
74 * Do we do require a client cert?
80 static CONF_PARSER module_config[] = {
81 { "tls", PW_TYPE_STRING_PTR,
82 offsetof(rlm_eap_peap_t, tls_conf_name), NULL, NULL },
84 { "default_eap_type", PW_TYPE_STRING_PTR,
85 offsetof(rlm_eap_peap_t, default_eap_type_name), NULL, "mschapv2" },
87 { "copy_request_to_tunnel", PW_TYPE_BOOLEAN,
88 offsetof(rlm_eap_peap_t, copy_request_to_tunnel), NULL, "no" },
90 { "use_tunneled_reply", PW_TYPE_BOOLEAN,
91 offsetof(rlm_eap_peap_t, use_tunneled_reply), NULL, "no" },
94 { "proxy_tunneled_request_as_eap", PW_TYPE_BOOLEAN,
95 offsetof(rlm_eap_peap_t, proxy_tunneled_request_as_eap), NULL, "yes" },
98 { "virtual_server", PW_TYPE_STRING_PTR,
99 offsetof(rlm_eap_peap_t, virtual_server), NULL, NULL },
101 { "soh", PW_TYPE_BOOLEAN,
102 offsetof(rlm_eap_peap_t, soh), NULL, "no" },
104 { "require_client_cert", PW_TYPE_BOOLEAN,
105 offsetof(rlm_eap_peap_t, req_client_cert), NULL, "no" },
107 { "soh_virtual_server", PW_TYPE_STRING_PTR,
108 offsetof(rlm_eap_peap_t, soh_virtual_server), NULL, NULL },
110 { NULL, -1, 0, NULL, NULL } /* end the list */
117 static int eappeap_attach(CONF_SECTION *cs, void **instance)
119 rlm_eap_peap_t *inst;
121 *instance = inst = talloc_zero(cs, rlm_eap_peap_t);
122 if (!inst) return -1;
125 * Parse the configuration attributes.
127 if (cf_section_parse(cs, inst, module_config) < 0) {
132 * Convert the name to an integer, to make it easier to
135 inst->default_eap_type = eaptype_name2type(inst->default_eap_type_name);
136 if (inst->default_eap_type < 0) {
137 radlog(L_ERR, "rlm_eap_peap: Unknown EAP type %s",
138 inst->default_eap_type_name);
143 * Read tls configuration, either from group given by 'tls'
144 * option, or from the eap-tls configuration.
146 inst->tls_conf = eaptls_conf_parse(cs, "tls");
148 if (!inst->tls_conf) {
149 radlog(L_ERR, "rlm_eap_peap: Failed initializing SSL context");
157 * Free the PEAP per-session data
159 static void peap_free(void *p)
161 peap_tunnel_t *t = (peap_tunnel_t *) p;
165 pairfree(&t->username);
167 pairfree(&t->accept_vps);
168 pairfree(&t->soh_reply_vps);
175 * Free the PEAP per-session data
177 static peap_tunnel_t *peap_alloc(rlm_eap_peap_t *inst)
181 t = rad_malloc(sizeof(*t));
182 memset(t, 0, sizeof(*t));
184 t->default_eap_type = inst->default_eap_type;
185 t->copy_request_to_tunnel = inst->copy_request_to_tunnel;
186 t->use_tunneled_reply = inst->use_tunneled_reply;
188 t->proxy_tunneled_request_as_eap = inst->proxy_tunneled_request_as_eap;
190 t->virtual_server = inst->virtual_server;
192 t->soh_virtual_server = inst->soh_virtual_server;
193 t->session_resumption_state = PEAP_RESUMPTION_MAYBE;
199 * Send an initial eap-tls request to the peer, using the libeap functions.
201 static int eappeap_initiate(void *type_arg, EAP_HANDLER *handler)
205 rlm_eap_peap_t *inst;
207 int client_cert = FALSE;
208 REQUEST *request = handler->request;
213 handler->finished = FALSE;
216 * Check if we need a client certificate.
218 client_cert = inst->req_client_cert;
221 * EAP-TLS-Require-Client-Cert attribute will override
222 * the require_client_cert configuration option.
224 vp = pairfind(handler->request->config_items, PW_EAP_TLS_REQUIRE_CLIENT_CERT, 0, TAG_ANY);
226 client_cert = vp->vp_integer;
229 ssn = eaptls_session(inst->tls_conf, handler, client_cert);
234 handler->opaque = ((void *)ssn);
235 handler->free_opaque = session_free;
238 * Set up type-specific information.
240 ssn->prf_label = "client EAP encryption";
243 * As it is a poorly designed protocol, PEAP uses
244 * bits in the TLS header to indicate PEAP
245 * version numbers. For now, we only support
246 * PEAP version 0, so it doesn't matter too much.
247 * However, if we support later versions of PEAP,
248 * we will need this flag to indicate which
249 * version we're currently dealing with.
251 ssn->peap_flag = 0x00;
254 * PEAP version 0 requires 'include_length = no',
255 * so rather than hoping the user figures it out,
258 ssn->length_flag = 0;
261 * TLS session initialization is over. Now handle TLS
262 * related handshaking or application data.
264 status = eaptls_start(handler->eap_ds, ssn->peap_flag);
265 RDEBUG2("Start returned %d", status);
271 * The next stage to process the packet.
273 handler->stage = AUTHENTICATE;
279 * Do authentication, by letting EAP-TLS do most of the work.
281 static int eappeap_authenticate(void *arg, EAP_HANDLER *handler)
284 fr_tls_status_t status;
285 rlm_eap_peap_t *inst = (rlm_eap_peap_t *) arg;
286 tls_session_t *tls_session = (tls_session_t *) handler->opaque;
287 peap_tunnel_t *peap = tls_session->opaque;
288 REQUEST *request = handler->request;
291 * Session resumption requires the storage of data, so
292 * allocate it if it doesn't already exist.
294 if (!tls_session->opaque) {
295 peap = tls_session->opaque = peap_alloc(inst);
296 tls_session->free_opaque = peap_free;
299 status = eaptls_process(handler);
300 RDEBUG2("eaptls_process returned %d\n", status);
303 * EAP-TLS handshake was successful, tell the
304 * client to keep talking.
306 * If this was EAP-TLS, we would just return
307 * an EAP-TLS-Success packet here.
310 RDEBUG2("FR_TLS_SUCCESS");
311 peap->status = PEAP_STATUS_TUNNEL_ESTABLISHED;
315 * The TLS code is still working on the TLS
316 * exchange, and it's a valid TLS request.
321 * FIXME: If the SSL session is established, grab the state
322 * and EAP id from the inner tunnel, and update it with
323 * the expected EAP id!
325 RDEBUG2("FR_TLS_HANDLED");
329 * Handshake is done, proceed with decoding tunneled
333 RDEBUG2("FR_TLS_OK");
337 * Anything else: fail.
340 RDEBUG2("FR_TLS_OTHERS");
345 * Session is established, proceed with decoding
348 RDEBUG2("Session established. Decoding tunneled attributes.");
351 * We may need PEAP data associated with the session, so
352 * allocate it here, if it wasn't already alloacted.
354 if (!tls_session->opaque) {
355 tls_session->opaque = peap_alloc(inst);
356 tls_session->free_opaque = peap_free;
360 * Process the PEAP portion of the request.
362 rcode = eappeap_process(handler, tls_session);
364 case RLM_MODULE_REJECT:
365 eaptls_fail(handler, 0);
368 case RLM_MODULE_HANDLED:
369 eaptls_request(handler->eap_ds, tls_session);
374 * Move the saved VP's from the Access-Accept to
377 peap = tls_session->opaque;
378 if (peap->soh_reply_vps) {
379 RDEBUG2("Using saved attributes from the SoH reply");
380 debug_pair_list(peap->soh_reply_vps);
381 pairadd(&handler->request->reply->vps, peap->soh_reply_vps);
382 peap->soh_reply_vps = NULL;
384 if (peap->accept_vps) {
385 RDEBUG2("Using saved attributes from the original Access-Accept");
386 debug_pair_list(peap->accept_vps);
387 pairadd(&handler->request->reply->vps, peap->accept_vps);
388 peap->accept_vps = NULL;
392 * Success: Automatically return MPPE keys.
394 return eaptls_success(handler, 0);
397 * No response packet, MUST be proxying it.
398 * The main EAP module will take care of discovering
399 * that the request now has a "proxy" packet, and
400 * will proxy it, rather than returning an EAP packet.
402 case RLM_MODULE_UPDATED:
404 rad_assert(handler->request->proxy != NULL);
413 eaptls_fail(handler, 0);
419 * The module name should be the only globally exported symbol.
420 * That is, everything else should be 'static'.
422 EAP_TYPE rlm_eap_peap = {
424 eappeap_attach, /* attach */
425 eappeap_initiate, /* Start the initial request */
426 NULL, /* authorization */
427 eappeap_authenticate, /* authentication */