Fixes from clang / scan-build
[freeradius.git] / src / modules / rlm_eap / types / rlm_eap_leap / eap_leap.c
index bfd401c..edf46c0 100644 (file)
  *
  *   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
  *  +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
@@ -43,6 +44,9 @@
  *  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"
@@ -82,9 +86,9 @@ void eapleap_free(LEAP_PACKET **leap_packet_ptr)
        *leap_packet_ptr = NULL;
 }
 
-/* 
+/*
  *   Extract the data from the LEAP packet.
- */ 
+ */
 LEAP_PACKET *eapleap_extract(EAP_DS *eap_ds)
 {
        leap_packet_t   *data;
@@ -95,8 +99,8 @@ LEAP_PACKET *eapleap_extract(EAP_DS *eap_ds)
         *      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 ||
@@ -170,8 +174,12 @@ LEAP_PACKET *eapleap_extract(EAP_DS *eap_ds)
 
        /*
         *      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) {
@@ -188,26 +196,16 @@ LEAP_PACKET *eapleap_extract(EAP_DS *eap_ds)
        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.
                 */
@@ -217,22 +215,56 @@ int eapleap_stage4(LEAP_PACKET *packet, VALUE_PAIR* password,
                         *  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));
@@ -243,20 +275,20 @@ int eapleap_stage4(LEAP_PACKET *packet, VALUE_PAIR* password,
        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.
         */
@@ -264,18 +296,6 @@ LEAP_PACKET *eapleap_stage6(LEAP_PACKET *packet, REQUEST *request,
                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;
 
@@ -299,26 +319,28 @@ LEAP_PACKET *eapleap_stage6(LEAP_PACKET *packet, REQUEST *request,
                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
@@ -333,8 +355,8 @@ LEAP_PACKET *eapleap_stage6(LEAP_PACKET *packet, REQUEST *request,
        /*
         *      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;
@@ -343,20 +365,19 @@ LEAP_PACKET *eapleap_stage6(LEAP_PACKET *packet, REQUEST *request,
        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);
 
@@ -367,7 +388,7 @@ LEAP_PACKET *eapleap_stage6(LEAP_PACKET *packet, REQUEST *request,
  *     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;
@@ -393,7 +414,7 @@ LEAP_PACKET *eapleap_initiate(EAP_DS *eap_ds, VALUE_PAIR *user_name)
         *      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");
@@ -407,18 +428,18 @@ LEAP_PACKET *eapleap_initiate(EAP_DS *eap_ds, VALUE_PAIR *user_name)
                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)
@@ -433,7 +454,7 @@ 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");