#include <freeradius-devel/ident.h>
RCSID("$Id$")
#include <freeradius-devel/autoconf.h>
#include <stdio.h>
#include <stdlib.h>
#include "eap.h"
#include <freeradius-devel/rad_assert.h>
typedef struct rlm_eap_gtc_t {
const char *challenge;
const char *auth_type_name;
int auth_type;
} rlm_eap_gtc_t;
static CONF_PARSER module_config[] = {
{ "challenge", PW_TYPE_STRING_PTR,
offsetof(rlm_eap_gtc_t, challenge), NULL, "Password: " },
{ "auth_type", PW_TYPE_STRING_PTR,
offsetof(rlm_eap_gtc_t, auth_type_name), NULL, "PAP" },
{ NULL, -1, 0, NULL, NULL }
};
static int gtc_detach(void *arg)
{
rlm_eap_gtc_t *inst = (rlm_eap_gtc_t *) arg;
free(inst);
return 0;
}
static int gtc_attach(CONF_SECTION *cs, void **instance)
{
rlm_eap_gtc_t *inst;
DICT_VALUE *dval;
inst = malloc(sizeof(*inst));
if (!inst) {
radlog(L_ERR, "rlm_eap_gtc: out of memory");
return -1;
}
memset(inst, 0, sizeof(*inst));
if (cf_section_parse(cs, inst, module_config) < 0) {
gtc_detach(inst);
return -1;
}
dval = dict_valbyname(PW_AUTH_TYPE, inst->auth_type_name);
if (!dval) {
radlog(L_ERR, "rlm_eap_gtc: Unknown Auth-Type %s",
inst->auth_type_name);
gtc_detach(inst);
return -1;
}
inst->auth_type = dval->value;
*instance = inst;
return 0;
}
static int gtc_initiate(void *type_data, EAP_HANDLER *handler)
{
int length;
EAP_DS *eap_ds = handler->eap_ds;
rlm_eap_gtc_t *inst = (rlm_eap_gtc_t *) type_data;
length = strlen(inst->challenge);
eap_ds->request->code = PW_EAP_REQUEST;
eap_ds->request->type.data = malloc(length);
if (eap_ds->request->type.data == NULL) {
radlog(L_ERR, "rlm_eap_gtc: out of memory");
return 0;
}
memcpy(eap_ds->request->type.data, inst->challenge, length);
eap_ds->request->type.length = length;
handler->stage = AUTHENTICATE;
return 1;
}
static int gtc_authenticate(void *type_data, EAP_HANDLER *handler)
{
VALUE_PAIR *vp;
EAP_DS *eap_ds = handler->eap_ds;
rlm_eap_gtc_t *inst = (rlm_eap_gtc_t *) type_data;
rad_assert(handler->request != NULL);
rad_assert(handler->stage == AUTHENTICATE);
if (eap_ds->response->length <= 4) {
radlog(L_ERR, "rlm_eap_gtc: corrupted data");
eap_ds->request->code = PW_EAP_FAILURE;
return 0;
}
#if 0
if ((debug_flag > 2) && fr_log_fp) {
int i;
for (i = 0; i < eap_ds->response->length - 4; i++) {
if ((i & 0x0f) == 0) fprintf(fr_log_fp, "%d: ", i);
fprintf(fr_log_fp, "%02x ", eap_ds->response->type.data[i]);
if ((i & 0x0f) == 0x0f) fprintf(fr_log_fp, "\n");
}
}
#endif
if (inst->auth_type == PW_AUTHTYPE_LOCAL) {
vp = pairfind(handler->request->config_items, PW_CLEARTEXT_PASSWORD);
if (!vp) {
DEBUG2(" rlm_eap_gtc: ERROR: Cleartext-Password is required for authentication.");
eap_ds->request->code = PW_EAP_FAILURE;
return 0;
}
if (eap_ds->response->type.length != vp->length) {
DEBUG2(" rlm_eap_gtc: ERROR: Passwords are of different length. %d %d", eap_ds->response->type.length, vp->length);
eap_ds->request->code = PW_EAP_FAILURE;
return 0;
}
if (memcmp(eap_ds->response->type.data,
vp->vp_strvalue, vp->length) != 0) {
DEBUG2(" rlm_eap_gtc: ERROR: Passwords are different");
eap_ds->request->code = PW_EAP_FAILURE;
return 0;
}
} else if (eap_ds->response->type.length <= 128) {
int rcode;
pairdelete(&handler->request->packet->vps, PW_USER_PASSWORD);
vp = pairmake("User-Password", "", T_OP_EQ);
if (!vp) {
radlog(L_ERR, "rlm_eap_gtc: out of memory");
return 0;
}
vp->length = eap_ds->response->type.length;
memcpy(vp->vp_strvalue, eap_ds->response->type.data, vp->length);
vp->vp_strvalue[vp->length] = 0;
pairadd(&handler->request->packet->vps, vp);
handler->request->password = vp;
rcode = module_authenticate(inst->auth_type, handler->request);
if (rcode != RLM_MODULE_OK) {
eap_ds->request->code = PW_EAP_FAILURE;
return 0;
}
} else {
radlog(L_ERR, "rlm_eap_gtc: Response is too large to understand");
eap_ds->request->code = PW_EAP_FAILURE;
return 0;
}
DEBUG2(" rlm_eap_gtc: Everything is OK.");
eap_ds->request->code = PW_EAP_SUCCESS;
return 1;
}
EAP_TYPE rlm_eap_gtc = {
"eap_gtc",
gtc_attach,
gtc_initiate,
NULL,
gtc_authenticate,
gtc_detach
};