*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
*
* Copyright 2003 Alan DeKok <aland@freeradius.org>
+ * Copyright 2006 The FreeRADIUS server project
*/
/*
*
* LEAP Packet Format in EAP Type-Data
- * --- ------ ------ -- --- ---------
+ * --- ------ ------ -- --- ---------
* 0 1 2 3
* 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
* +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
* The LEAP type (0x11) is *not* included in the type data...
*/
+#include <freeradius-devel/ident.h>
+RCSID("$Id$")
+
#include <stdio.h>
#include <stdlib.h>
#include "eap.h"
*leap_packet_ptr = NULL;
}
-/*
+/*
* Extract the data from the LEAP packet.
- */
+ */
LEAP_PACKET *eapleap_extract(EAP_DS *eap_ds)
{
leap_packet_t *data;
* LEAP can have EAP-Response or EAP-Request (step 5)
* messages sent to it.
*/
- if (!eap_ds ||
- !eap_ds->response ||
+ if (!eap_ds ||
+ !eap_ds->response ||
((eap_ds->response->code != PW_EAP_RESPONSE) &&
(eap_ds->response->code != PW_EAP_REQUEST)) ||
eap_ds->response->type.type != PW_EAP_LEAP ||
/*
* The User-Name comes after the challenge.
+ *
+ * Length of the EAP-LEAP portion of the packet, minus
+ * 3 octets for data, minus the challenge size, is the
+ * length of the user name.
*/
- name_len = eap_ds->response->length - 3 - packet->count;
+ name_len = packet->length - 3 - packet->count;
if (name_len > 0) {
packet->name = malloc(name_len + 1);
if (!packet->name) {
return packet;
}
-/*
- * Verify the MS-CHAP response from the user.
+/*
+ * Get the NT-Password hash.
*/
-int eapleap_stage4(LEAP_PACKET *packet, VALUE_PAIR* password,
- leap_session_t *session)
+static int eapleap_ntpwdhash(unsigned char *ntpwdhash, VALUE_PAIR *password)
{
- int i;
- unsigned char unicode[512];
- unsigned char ntpwdhash[16];
- unsigned char response[24];
-
-
- /*
- * No password or previous packet. Die.
- */
- if ((password == NULL) || (session == NULL)) {
- return 0;
- }
+ if ((password->attribute == PW_USER_PASSWORD) ||
+ (password->attribute == PW_CLEARTEXT_PASSWORD)) {
+ size_t i;
+ unsigned char unicode[512];
- if (password->attribute == PW_PASSWORD) {
/*
* Convert the password to NT's weird Unicode format.
*/
* Yes, the *even* bytes have the values,
* and the *odd* bytes are zero.
*/
- unicode[(i << 1)] = password->strvalue[i];
+ unicode[(i << 1)] = password->vp_strvalue[i];
}
-
+
/*
* Get the NT Password hash.
*/
- md4_calc(ntpwdhash, unicode, password->length * 2);
+ fr_md4_calc(ntpwdhash, unicode, password->length * 2);
+
+ } else { /* MUST be NT-Password */
+ if (password->length == 32) {
+ password->length = fr_hex2bin(password->vp_strvalue,
+ password->vp_octets,
+ 16);
+ }
+ if (password->length != 16) {
+ radlog(L_ERR, "rlm_eap_leap: Bad NT-Password");
+ return 0;
+ }
- } else {
- memcpy(ntpwdhash, password->strvalue, 16);
+ memcpy(ntpwdhash, password->vp_strvalue, 16);
+ }
+ return 1;
+}
+
+
+/*
+ * Verify the MS-CHAP response from the user.
+ */
+int eapleap_stage4(LEAP_PACKET *packet, VALUE_PAIR* password,
+ leap_session_t *session)
+{
+ unsigned char ntpwdhash[16];
+ unsigned char response[24];
+
+
+ /*
+ * No password or previous packet. Die.
+ */
+ if ((password == NULL) || (session == NULL)) {
+ return 0;
+ }
+
+ if (!eapleap_ntpwdhash(ntpwdhash, password)) {
+ return 0;
}
/*
* Calculate and verify the CHAP challenge.
*/
- lrad_mschap(ntpwdhash, session->peer_challenge, response);
+ eapleap_mschap(ntpwdhash, session->peer_challenge, response);
if (memcmp(response, packet->challenge, 24) == 0) {
DEBUG2(" rlm_eap_leap: NtChallengeResponse from AP is valid");
memcpy(session->peer_response, response, sizeof(response));
return 0;
}
-/*
+/*
* Verify ourselves to the AP
*/
LEAP_PACKET *eapleap_stage6(LEAP_PACKET *packet, REQUEST *request,
- VALUE_PAIR *user_name, VALUE_PAIR* password,
+ VALUE_PAIR *user_name, VALUE_PAIR* password,
leap_session_t *session, VALUE_PAIR **reply_vps)
{
- int i;
- unsigned char unicode[512];
- unsigned char ntpwdhash[16];
+ size_t i;
+ unsigned char ntpwdhash[16], ntpwdhashhash[16];
+ unsigned char buffer[256];
LEAP_PACKET *reply;
- char *p;
+ unsigned char *p;
VALUE_PAIR *vp;
-
+
/*
* No password or previous packet. Die.
*/
return NULL;
}
- /*
- * Convert the password to NT's weird Unicode format.
- */
- memset(unicode, 0, sizeof(unicode));
- for (i = 0; i < password->length; i++) {
- /*
- * Yes, the *even* bytes have the values,
- * and the *odd* bytes are zero.
- */
- unicode[(i << 1)] = password->strvalue[i];
- }
-
reply = eapleap_alloc();
if (!reply) return NULL;
eapleap_free(&reply);
return NULL;
}
-
+
/*
* Copy the name over, and ensure it's NUL terminated.
*/
- memcpy(reply->name, user_name->strvalue, user_name->length);
+ memcpy(reply->name, user_name->vp_strvalue, user_name->length);
reply->name[user_name->length] = '\0';
reply->name_len = user_name->length;
/*
* MPPE hash = ntpwdhash(ntpwdhash(unicode(pw)))
*/
- md4_calc(ntpwdhash, unicode, password->length * 2);
- memcpy(unicode, ntpwdhash, 16);
- md4_calc(ntpwdhash, unicode, 16);
+ if (!eapleap_ntpwdhash(ntpwdhash, password)) {
+ eapleap_free(&reply);
+ return NULL;
+ }
+ fr_md4_calc(ntpwdhashhash, ntpwdhash, 16);
/*
* Calculate our response, to authenticate ourselves
* to the AP.
*/
- lrad_mschap(ntpwdhash, packet->challenge, reply->challenge);
+ eapleap_mschap(ntpwdhashhash, packet->challenge, reply->challenge);
/*
* Calculate the leap:session-key attribute
/*
* And calculate the MPPE session key.
*/
- p = unicode;
- memcpy(p, ntpwdhash, 16); /* MPPEHASH */
+ p = buffer;
+ memcpy(p, ntpwdhashhash, 16); /* MPPEHASH */
p += 16;
memcpy(p, packet->challenge, 8); /* APC */
p += 8;
memcpy(p, session->peer_challenge, 8); /* PC */
p += 8;
memcpy(p, session->peer_response, 24); /* PR */
- p += 24;
/*
* These 16 bytes are the session key to use.
*/
- librad_md5_calc(ntpwdhash, unicode, 16 + 8 + 24 + 8 + 24);
+ fr_md5_calc(ntpwdhash, buffer, 16 + 8 + 24 + 8 + 24);
- memcpy(vp->strvalue + vp->length, ntpwdhash, 16);
- memset(vp->strvalue + vp->length + 16, 0,
- sizeof(vp->strvalue) - (vp->length + 16));
+ memcpy(vp->vp_strvalue + vp->length, ntpwdhash, 16);
+ memset(vp->vp_strvalue + vp->length + 16, 0,
+ sizeof(vp->vp_strvalue) - (vp->length + 16));
i = 16;
- rad_tunnel_pwencode(vp->strvalue + vp->length, &i,
- request->secret, request->packet->vector);
+ rad_tunnel_pwencode(vp->vp_strvalue + vp->length, &i,
+ request->client->secret, request->packet->vector);
vp->length += i;
pairadd(reply_vps, vp);
* If an EAP LEAP request needs to be initiated then
* create such a packet.
*/
-LEAP_PACKET *eapleap_initiate(EAP_DS *eap_ds, VALUE_PAIR *user_name)
+LEAP_PACKET *eapleap_initiate(UNUSED EAP_DS *eap_ds, VALUE_PAIR *user_name)
{
int i;
LEAP_PACKET *reply;
* Fill the challenge with random bytes.
*/
for (i = 0; i < reply->count; i++) {
- reply->challenge[i] = lrad_rand();
+ reply->challenge[i] = fr_rand();
}
DEBUG2(" rlm_eap_leap: Issuing AP Challenge");
eapleap_free(&reply);
return NULL;
}
-
+
/*
* Copy the name over, and ensure it's NUL terminated.
*/
- memcpy(reply->name, user_name->strvalue, user_name->length);
+ memcpy(reply->name, user_name->vp_strvalue, user_name->length);
reply->name[user_name->length] = '\0';
reply->name_len = user_name->length;
return reply;
}
-/*
+/*
* compose the LEAP reply packet in the EAP reply typedata
*/
int eapleap_compose(EAP_DS *eap_ds, LEAP_PACKET *reply)
case PW_EAP_RESPONSE:
eap_ds->request->type.type = PW_EAP_LEAP;
eap_ds->request->type.length = reply->length;
-
+
eap_ds->request->type.data = malloc(reply->length);
if (eap_ds->request->type.data == NULL) {
radlog(L_ERR, "rlm_eap_leap: out of memory");