#include <freeradius-devel/ident.h>
RCSID("$Id$")
#include <freeradius-devel/autoconf.h>
#include "eap_ttls.h"
typedef struct rlm_eap_ttls_t {
char *default_eap_type_name;
int default_eap_type;
int use_tunneled_reply;
int copy_request_to_tunnel;
int include_length;
char *virtual_server;
} rlm_eap_ttls_t;
static CONF_PARSER module_config[] = {
{ "default_eap_type", PW_TYPE_STRING_PTR,
offsetof(rlm_eap_ttls_t, default_eap_type_name), NULL, "md5" },
{ "copy_request_to_tunnel", PW_TYPE_BOOLEAN,
offsetof(rlm_eap_ttls_t, copy_request_to_tunnel), NULL, "no" },
{ "use_tunneled_reply", PW_TYPE_BOOLEAN,
offsetof(rlm_eap_ttls_t, use_tunneled_reply), NULL, "no" },
{ "virtual_server", PW_TYPE_STRING_PTR,
offsetof(rlm_eap_ttls_t, virtual_server), NULL, NULL },
{ "include_length", PW_TYPE_BOOLEAN,
offsetof(rlm_eap_ttls_t, include_length), NULL, "yes" },
{ NULL, -1, 0, NULL, NULL }
};
static int eapttls_detach(void *arg)
{
rlm_eap_ttls_t *inst = (rlm_eap_ttls_t *) arg;
free(inst);
return 0;
}
static int eapttls_attach(CONF_SECTION *cs, void **instance)
{
rlm_eap_ttls_t *inst;
inst = malloc(sizeof(*inst));
if (!inst) {
radlog(L_ERR, "rlm_eap_ttls: out of memory");
return -1;
}
memset(inst, 0, sizeof(*inst));
if (cf_section_parse(cs, inst, module_config) < 0) {
eapttls_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_ttls: Unknown EAP type %s",
inst->default_eap_type_name);
eapttls_detach(inst);
return -1;
}
*instance = inst;
return 0;
}
static void ttls_free(void *p)
{
ttls_tunnel_t *t = (ttls_tunnel_t *) p;
if (!t) return;
if (t->username) {
DEBUG2("rlm_eap_ttls: Freeing handler for user %s",
t->username->vp_strvalue);
}
pairfree(&t->username);
pairfree(&t->state);
pairfree(&t->accept_vps);
free(t);
}
static ttls_tunnel_t *ttls_alloc(rlm_eap_ttls_t *inst)
{
ttls_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;
t->virtual_server = inst->virtual_server;
return t;
}
static int eapttls_authenticate(void *arg, EAP_HANDLER *handler)
{
int rcode;
eaptls_status_t status;
rlm_eap_ttls_t *inst = (rlm_eap_ttls_t *) arg;
tls_session_t *tls_session = (tls_session_t *) handler->opaque;
ttls_tunnel_t *t = (ttls_tunnel_t *) tls_session->opaque;
REQUEST *request = handler->request;
RDEBUG2("Authenticate");
tls_session->length_flag = inst->include_length;
status = eaptls_process(handler);
RDEBUG2("eaptls_process returned %d\n", status);
switch (status) {
case EAPTLS_SUCCESS:
if (SSL_session_reused(tls_session->ssl)) {
RDEBUG("Skipping Phase2 due to session resumption");
goto do_keys;
}
if (t && t->authenticated) {
RDEBUG2("Using saved attributes from the original Access-Accept");
debug_pair_list(t->accept_vps);
pairadd(&handler->request->reply->vps,
t->accept_vps);
t->accept_vps = NULL;
do_keys:
return eaptls_success(handler, 0);
} else {
eaptls_request(handler->eap_ds, tls_session);
}
return 1;
case EAPTLS_HANDLED:
return 1;
case EAPTLS_OK:
break;
default:
return 0;
}
RDEBUG2("Session established. Proceeding to decode tunneled attributes.");
if (!tls_session->opaque) {
tls_session->opaque = ttls_alloc(inst);
tls_session->free_opaque = ttls_free;
}
rcode = eapttls_process(handler, tls_session);
switch (rcode) {
case PW_AUTHENTICATION_REJECT:
eaptls_fail(handler, 0);
return 0;
case PW_ACCESS_CHALLENGE:
eaptls_request(handler->eap_ds, tls_session);
return 1;
case PW_AUTHENTICATION_ACK:
return eaptls_success(handler, 0);
case PW_STATUS_CLIENT:
#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_ttls = {
"eap_ttls",
eapttls_attach,
NULL,
NULL,
eapttls_authenticate,
eapttls_detach
};