#include <freeradius-devel/ident.h>
RCSID("$Id$")
#include <freeradius-devel/autoconf.h>
#include "eap_peap.h"
typedef struct rlm_eap_peap_t {
char *default_eap_type_name;
int default_eap_type;
int use_tunneled_reply;
int copy_request_to_tunnel;
#ifdef WITH_PROXY
int proxy_tunneled_request_as_eap;
#endif
char *virtual_server;
int soh;
char *soh_virtual_server;
} rlm_eap_peap_t;
static CONF_PARSER module_config[] = {
{ "default_eap_type", PW_TYPE_STRING_PTR,
offsetof(rlm_eap_peap_t, default_eap_type_name), NULL, "mschapv2" },
{ "copy_request_to_tunnel", PW_TYPE_BOOLEAN,
offsetof(rlm_eap_peap_t, copy_request_to_tunnel), NULL, "no" },
{ "use_tunneled_reply", PW_TYPE_BOOLEAN,
offsetof(rlm_eap_peap_t, use_tunneled_reply), NULL, "no" },
#ifdef WITH_PROXY
{ "proxy_tunneled_request_as_eap", PW_TYPE_BOOLEAN,
offsetof(rlm_eap_peap_t, proxy_tunneled_request_as_eap), NULL, "yes" },
#endif
{ "virtual_server", PW_TYPE_STRING_PTR,
offsetof(rlm_eap_peap_t, virtual_server), NULL, NULL },
{ "soh", PW_TYPE_BOOLEAN,
offsetof(rlm_eap_peap_t, soh), NULL, "no" },
{ "soh_virtual_server", PW_TYPE_STRING_PTR,
offsetof(rlm_eap_peap_t, soh_virtual_server), NULL, NULL },
{ NULL, -1, 0, NULL, NULL }
};
static int eappeap_detach(void *arg)
{
rlm_eap_peap_t *inst = (rlm_eap_peap_t *) arg;
free(inst);
return 0;
}
static int eappeap_attach(CONF_SECTION *cs, void **instance)
{
rlm_eap_peap_t *inst;
inst = malloc(sizeof(*inst));
if (!inst) {
radlog(L_ERR, "rlm_eap_peap: out of memory");
return -1;
}
memset(inst, 0, sizeof(*inst));
if (cf_section_parse(cs, inst, module_config) < 0) {
eappeap_detach(inst);
return -1;
}
if (inst->soh && !inst->soh_virtual_server) {
radlog(L_ERR, "rlm_eap_peap: You MUST specify a value for \"soh_virtual_server\"");
eappeap_detach(inst);
return -1;
}
inst->default_eap_type = eaptype_name2type(inst->default_eap_type_name);
if (inst->default_eap_type < 0) {
radlog(L_ERR, "rlm_eap_peap: Unknown EAP type %s",
inst->default_eap_type_name);
eappeap_detach(inst);
return -1;
}
*instance = inst;
return 0;
}
static void peap_free(void *p)
{
peap_tunnel_t *t = (peap_tunnel_t *) p;
if (!t) return;
pairfree(&t->username);
pairfree(&t->state);
pairfree(&t->accept_vps);
pairfree(&t->soh_reply_vps);
free(t);
}
static peap_tunnel_t *peap_alloc(rlm_eap_peap_t *inst)
{
peap_tunnel_t *t;
t = rad_malloc(sizeof(*t));
memset(t, 0, sizeof(*t));
t->default_eap_type = inst->default_eap_type;
t->copy_request_to_tunnel = inst->copy_request_to_tunnel;
t->use_tunneled_reply = inst->use_tunneled_reply;
#ifdef WITH_PROXY
t->proxy_tunneled_request_as_eap = inst->proxy_tunneled_request_as_eap;
#endif
t->virtual_server = inst->virtual_server;
t->soh = inst->soh;
t->soh_virtual_server = inst->soh_virtual_server;
t->session_resumption_state = PEAP_RESUMPTION_MAYBE;
return t;
}
static int eappeap_authenticate(void *arg, EAP_HANDLER *handler)
{
int rcode;
eaptls_status_t status;
rlm_eap_peap_t *inst = (rlm_eap_peap_t *) arg;
tls_session_t *tls_session = (tls_session_t *) handler->opaque;
peap_tunnel_t *peap = tls_session->opaque;
REQUEST *request = handler->request;
if (!tls_session->opaque) {
peap = tls_session->opaque = peap_alloc(inst);
tls_session->free_opaque = peap_free;
}
status = eaptls_process(handler);
RDEBUG2("eaptls_process returned %d\n", status);
switch (status) {
case EAPTLS_SUCCESS:
RDEBUG2("EAPTLS_SUCCESS");
peap->status = PEAP_STATUS_TUNNEL_ESTABLISHED;
break;
case EAPTLS_HANDLED:
RDEBUG2("EAPTLS_HANDLED");
return 1;
case EAPTLS_OK:
RDEBUG2("EAPTLS_OK");
break;
default:
RDEBUG2("EAPTLS_OTHERS");
return 0;
}
RDEBUG2("Session established. Decoding tunneled attributes.");
if (!tls_session->opaque) {
tls_session->opaque = peap_alloc(inst);
tls_session->free_opaque = peap_free;
}
rcode = eappeap_process(handler, tls_session);
switch (rcode) {
case RLM_MODULE_REJECT:
eaptls_fail(handler, 0);
return 0;
case RLM_MODULE_HANDLED:
eaptls_request(handler->eap_ds, tls_session);
return 1;
case RLM_MODULE_OK:
peap = tls_session->opaque;
if (peap->soh_reply_vps) {
RDEBUG2("Using saved attributes from the SoH reply");
debug_pair_list(peap->soh_reply_vps);
pairadd(&handler->request->reply->vps, peap->soh_reply_vps);
peap->soh_reply_vps = NULL;
}
if (peap->accept_vps) {
RDEBUG2("Using saved attributes from the original Access-Accept");
debug_pair_list(peap->accept_vps);
pairadd(&handler->request->reply->vps, peap->accept_vps);
peap->accept_vps = NULL;
}
return eaptls_success(handler, 0);
case RLM_MODULE_UPDATED:
#ifdef WITH_PROXY
rad_assert(handler->request->proxy != NULL);
#endif
return 1;
break;
default:
break;
}
eaptls_fail(handler, 0);
return 0;
}
EAP_TYPE rlm_eap_peap = {
"eap_peap",
eappeap_attach,
NULL,
NULL,
eappeap_authenticate,
eappeap_detach
};