#include <freeradius-devel/ident.h>
RCSID("$Id$")
#include <stdio.h>
#include <stdlib.h>
#include "eap.h"
#include "eap_md5.h"
MD5_PACKET *eapmd5_alloc(void)
{
MD5_PACKET *rp;
if ((rp = malloc(sizeof(MD5_PACKET))) == NULL) {
radlog(L_ERR, "rlm_eap_md5: out of memory");
return NULL;
}
memset(rp, 0, sizeof(MD5_PACKET));
return rp;
}
void eapmd5_free(MD5_PACKET **md5_packet_ptr)
{
MD5_PACKET *md5_packet;
if (!md5_packet_ptr) return;
md5_packet = *md5_packet_ptr;
if (md5_packet == NULL) return;
if (md5_packet->value) free(md5_packet->value);
if (md5_packet->name) free(md5_packet->name);
free(md5_packet);
*md5_packet_ptr = NULL;
}
MD5_PACKET *eapmd5_extract(EAP_DS *eap_ds)
{
md5_packet_t *data;
MD5_PACKET *packet;
unsigned short name_len;
if (!eap_ds ||
!eap_ds->response ||
(eap_ds->response->code != PW_MD5_RESPONSE) ||
eap_ds->response->type.type != PW_EAP_MD5 ||
!eap_ds->response->type.data ||
(eap_ds->response->length <= MD5_HEADER_LEN) ||
(eap_ds->response->type.data[0] <= 0)) {
radlog(L_ERR, "rlm_eap_md5: corrupted data");
return NULL;
}
packet = eapmd5_alloc();
if (!packet) return NULL;
packet->code = eap_ds->response->code;
packet->id = eap_ds->response->id;
packet->length = eap_ds->response->length - (MD5_HEADER_LEN + 1);
data = (md5_packet_t *)eap_ds->response->type.data;
packet->value_size = data->value_size;
packet->value = malloc(packet->value_size);
if (packet->value == NULL) {
radlog(L_ERR, "rlm_eap_md5: out of memory");
eapmd5_free(&packet);
return NULL;
}
memcpy(packet->value, data->value_name, packet->value_size);
name_len = packet->length - (packet->value_size + 1);
if (name_len) {
packet->name = malloc(name_len + 1);
if (!packet->name) {
radlog(L_ERR, "rlm_eap_md5: out of memory");
eapmd5_free(&packet);
return NULL;
}
memcpy(packet->name, data->value_name + packet->value_size,
name_len);
packet->name[name_len] = 0;
}
return packet;
}
int eapmd5_verify(MD5_PACKET *packet, VALUE_PAIR* password,
uint8_t *challenge)
{
char *ptr;
char string[1 + MAX_STRING_LEN*2];
unsigned char output[MAX_STRING_LEN];
unsigned short len;
if (packet->value_size != 16) {
radlog(L_ERR, "rlm_eap_md5: Expected 16 bytes of response to challenge, got %d", packet->value_size);
return 0;
}
len = 0;
ptr = string;
*ptr++ = packet->id;
len++;
memcpy(ptr, password->vp_strvalue, password->length);
ptr += password->length;
len += password->length;
memcpy(ptr, challenge, MD5_CHALLENGE_LEN);
len += MD5_CHALLENGE_LEN;
fr_md5_calc((u_char *)output, (u_char *)string, len);
if (memcmp(output, packet->value, 16) != 0) {
return 0;
}
return 1;
}
int eapmd5_compose(EAP_DS *eap_ds, MD5_PACKET *reply)
{
uint8_t *ptr;
unsigned short name_len;
if (reply->code < 3) {
eap_ds->request->type.type = PW_EAP_MD5;
rad_assert(reply->length > 0);
eap_ds->request->type.data = malloc(reply->length);
if (eap_ds->request->type.data == NULL) {
eapmd5_free(&reply);
radlog(L_ERR, "rlm_eap_md5: out of memory");
return 0;
}
ptr = eap_ds->request->type.data;
*ptr++ = (uint8_t)(reply->value_size & 0xFF);
memcpy(ptr, reply->value, reply->value_size);
eap_ds->request->type.length = reply->value_size + 1;
name_len = reply->length - (reply->value_size + 1);
if (name_len && reply->name) {
ptr += reply->value_size;
memcpy(ptr, reply->name, name_len);
eap_ds->request->type.length += name_len;
}
} else {
eap_ds->request->type.length = 0;
}
eap_ds->request->code = reply->code;
eapmd5_free(&reply);
return 1;
}