Signed / unsigned fixes and function prototypes
[freeradius.git] / src / modules / rlm_eap / radeapclient.c
index 0e00ad2..9bcd20e 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 2000  The FreeRADIUS server project
+ * Copyright 2000,2006  The FreeRADIUS server project
  * Copyright 2000  Miquel van Smoorenburg <miquels@cistron.nl>
  * Copyright 2000  Alan DeKok <aland@ox.org>
  */
-static const char rcsid[] = "$Id$";
 
-#include "autoconf.h"
+#include <freeradius-devel/ident.h>
+RCSID("$Id$")
 
-#include <stdio.h>
-#include <stdlib.h>
+#include <freeradius-devel/libradius.h>
 
-#if HAVE_UNISTD_H
-#      include <unistd.h>
-#endif
-
-#include <string.h>
 #include <ctype.h>
-#include <netdb.h>
-#include <sys/socket.h>
-
-#if HAVE_NETINET_IN_H
-#      include <netinet/in.h>
-#endif
-
-#if HAVE_SYS_SELECT_H
-#      include <sys/select.h>
-#endif
 
 #if HAVE_GETOPT_H
 #      include <getopt.h>
 #endif
 
-#include "conf.h"
-#include "radpaths.h"
-#include "missing.h"
-#include "../include/md5.h"
+#include <freeradius-devel/conf.h>
+#include <freeradius-devel/radpaths.h>
+#include <freeradius-devel/md5.h>
 
 #include "eap_types.h"
 #include "eap_sim.h"
@@ -68,20 +51,29 @@ static int filedone = 0;
 static int totalapp = 0;
 static int totaldeny = 0;
 static char filesecret[256];
-const char *radius_dir = RADDBDIR;
+char *radius_dir = NULL;
 const char *progname = "radeapclient";
-/* lrad_randctx randctx; */
+/* fr_randctx randctx; */
 
 
 radlog_dest_t radlog_dest = RADLOG_STDERR;
 const char *radlog_dir = NULL;
 int debug_flag = 0;
-struct main_config_t mainconfig;
 char password[256];
 
 struct eapsim_keys eapsim_mk;
 
-static void usage(void)
+static void map_eap_types(RADIUS_PACKET *req);
+static void unmap_eap_types(RADIUS_PACKET *rep);
+static int map_eapsim_types(RADIUS_PACKET *r);
+static int unmap_eapsim_types(RADIUS_PACKET *r);
+
+void debug_pair_list(UNUSED VALUE_PAIR *vp)
+{
+       return;
+}
+
+static void NEVER_RETURNS usage(void)
 {
        fprintf(stderr, "Usage: radeapclient [options] server[:port] <command> [<secret>]\n");
 
@@ -116,6 +108,30 @@ int radlog(int lvl, const char *msg, ...)
        return r;
 }
 
+int log_debug(const char *msg, ...)
+{
+       va_list ap;
+       int r;
+
+       va_start(ap, msg);
+       r = vfprintf(stderr, msg, ap);
+       va_end(ap);
+       fputc('\n', stderr);
+
+       return r;
+}
+
+void radlog_request(UNUSED int lvl, UNUSED int priority,
+                   UNUSED REQUEST *request, const char *msg, ...)
+{
+       va_list ap;
+
+       va_start(ap, msg);
+       vfprintf(stderr, msg, ap);
+       va_end(ap);
+       fputc('\n', stderr);
+}
+
 static int getport(const char *name)
 {
        struct  servent         *svp;
@@ -128,6 +144,58 @@ static int getport(const char *name)
        return ntohs(svp->s_port);
 }
 
+#define R_RECV (0)
+#define R_SENT (1)
+static void debug_packet(RADIUS_PACKET *packet, int direction)
+{
+       VALUE_PAIR *vp;
+       char buffer[1024];
+       const char *received, *from;
+       const fr_ipaddr_t *ip;
+       int port;
+
+       if (!packet) return;
+
+       if (direction == 0) {
+               received = "Received";
+               from = "from";  /* what else? */
+               ip = &packet->src_ipaddr;
+               port = packet->src_port;
+
+       } else {
+               received = "Sending";
+               from = "to";    /* hah! */
+               ip = &packet->dst_ipaddr;
+               port = packet->dst_port;
+       }
+       
+       /*
+        *      Client-specific debugging re-prints the input
+        *      packet into the client log.
+        *
+        *      This really belongs in a utility library
+        */
+       if ((packet->code > 0) && (packet->code < FR_MAX_PACKET_CODE)) {
+               printf("%s %s packet %s host %s port %d, id=%d, length=%d\n",
+                      received, fr_packet_codes[packet->code], from,
+                      inet_ntop(ip->af, &ip->ipaddr, buffer, sizeof(buffer)),
+                      port, packet->id, (int) packet->data_len);
+       } else {
+               printf("%s packet %s host %s port %d code=%d, id=%d, length=%d\n",
+                      received, from,
+                      inet_ntop(ip->af, &ip->ipaddr, buffer, sizeof(buffer)),
+                      port,
+                      packet->code, packet->id, (int) packet->data_len);
+       }
+
+       for (vp = packet->vps; vp != NULL; vp = vp->next) {
+               vp_prints(buffer, sizeof(buffer), vp);
+               printf("\t%s\n", buffer);
+       }
+       fflush(stdout);
+}
+
+
 static int send_packet(RADIUS_PACKET *req, RADIUS_PACKET **rep)
 {
        int i;
@@ -136,6 +204,8 @@ static int send_packet(RADIUS_PACKET *req, RADIUS_PACKET **rep)
        for (i = 0; i < retries; i++) {
                fd_set          rdfdesc;
 
+               debug_packet(req, R_SENT);
+
                rad_send(req, NULL, secret);
 
                /* And wait for reply, timing out as necessary */
@@ -150,7 +220,7 @@ static int send_packet(RADIUS_PACKET *req, RADIUS_PACKET **rep)
                        continue;
                }
 
-               *rep = rad_recv(req->sockfd);
+               *rep = rad_recv(req->sockfd, 0);
                if (*rep != NULL) {
                        /*
                         *      If we get a response from a machine
@@ -175,7 +245,7 @@ static int send_packet(RADIUS_PACKET *req, RADIUS_PACKET **rep)
                        }
                        break;
                } else {        /* NULL: couldn't receive the packet */
-                       librad_perror("radclient:");
+                       fr_perror("radclient:");
                        exit(1);
                }
        }
@@ -186,20 +256,29 @@ static int send_packet(RADIUS_PACKET *req, RADIUS_PACKET **rep)
                exit(1);
        }
 
+       /*
+        *      FIXME: Discard the packet & listen for another.
+        *
+        *      Hmm... we should really be using eapol_test, which does
+        *      a lot more than radeapclient.
+                */
+       if (rad_verify(*rep, req, secret) != 0) {
+               fr_perror("rad_verify");
+               exit(1);
+       }
+
        if (rad_decode(*rep, req, secret) != 0) {
-               librad_perror("rad_decode");
+               fr_perror("rad_decode");
                exit(1);
        }
 
        /* libradius debug already prints out the value pairs for us */
-       if (!librad_debug && do_output) {
-               printf("Received response ID %d, code %d, length = %d\n",
-                               (*rep)->id, (*rep)->code, (*rep)->data_len);
-               vp_printlist(stdout, (*rep)->vps);
+       if (!fr_debug_flag && do_output) {
+               debug_packet(*rep, R_RECV);
        }
        if((*rep)->code == PW_AUTHENTICATION_ACK) {
                totalapp++;
-       } else {
+       } else if ((*rep)->code == PW_AUTHENTICATION_REJECT) {
                totaldeny++;
        }
 
@@ -215,8 +294,8 @@ static void cleanresp(RADIUS_PACKET *resp)
         * maybe should just copy things we care about, or keep
         * a copy of the original input and start from there again?
         */
-       pairdelete(&resp->vps, PW_EAP_MESSAGE);
-       pairdelete(&resp->vps, ATTRIBUTE_EAP_BASE+PW_EAP_IDENTITY);
+       pairdelete(&resp->vps, PW_EAP_MESSAGE, 0);
+       pairdelete(&resp->vps, ATTRIBUTE_EAP_BASE+PW_EAP_IDENTITY, 0);
 
        last = &resp->vps;
        for(vp = *last; vp != NULL; vp = vpnext)
@@ -252,7 +331,7 @@ static int process_eap_start(RADIUS_PACKET *req,
        /* form new response clear of any EAP stuff */
        cleanresp(rep);
 
-       if((vp = pairfind(req->vps, ATTRIBUTE_EAP_SIM_BASE+PW_EAP_SIM_VERSION_LIST)) == NULL) {
+       if((vp = pairfind(req->vps, ATTRIBUTE_EAP_SIM_BASE+PW_EAP_SIM_VERSION_LIST, 0)) == NULL) {
                fprintf(stderr, "illegal start message has no VERSION_LIST\n");
                return 0;
        }
@@ -262,7 +341,7 @@ static int process_eap_start(RADIUS_PACKET *req,
        /* verify that the attribute length is big enough for a length field */
        if(vp->length < 4)
        {
-               fprintf(stderr, "start message has illegal VERSION_LIST. Too short: %d\n", vp->length);
+               fprintf(stderr, "start message has illegal VERSION_LIST. Too short: %u\n", (unsigned int) vp->length);
                return 0;
        }
 
@@ -272,7 +351,7 @@ static int process_eap_start(RADIUS_PACKET *req,
         */
        if((unsigned)vp->length <= (versioncount*2 + 2))
        {
-               fprintf(stderr, "start message is too short. Claimed %d versions does not fit in %d bytes\n", versioncount, vp->length);
+               fprintf(stderr, "start message is too short. Claimed %d versions does not fit in %u bytes\n", versioncount, (unsigned int) vp->length);
                return 0;
        }
 
@@ -311,9 +390,9 @@ static int process_eap_start(RADIUS_PACKET *req,
         * anyway we like, but it is illegal to have more than one
         * present.
         */
-       anyidreq_vp = pairfind(req->vps, ATTRIBUTE_EAP_SIM_BASE+PW_EAP_SIM_ANY_ID_REQ);
-       fullauthidreq_vp = pairfind(req->vps, ATTRIBUTE_EAP_SIM_BASE+PW_EAP_SIM_FULLAUTH_ID_REQ);
-       permanentidreq_vp = pairfind(req->vps, ATTRIBUTE_EAP_SIM_BASE+PW_EAP_SIM_PERMANENT_ID_REQ);
+       anyidreq_vp = pairfind(req->vps, ATTRIBUTE_EAP_SIM_BASE+PW_EAP_SIM_ANY_ID_REQ, 0);
+       fullauthidreq_vp = pairfind(req->vps, ATTRIBUTE_EAP_SIM_BASE+PW_EAP_SIM_FULLAUTH_ID_REQ, 0);
+       permanentidreq_vp = pairfind(req->vps, ATTRIBUTE_EAP_SIM_BASE+PW_EAP_SIM_PERMANENT_ID_REQ, 0);
 
        if(fullauthidreq_vp == NULL ||
           anyidreq_vp != NULL ||
@@ -328,13 +407,13 @@ static int process_eap_start(RADIUS_PACKET *req,
        /* okay, we have just any_id_req there, so fill in response */
 
        /* mark the subtype as being EAP-SIM/Response/Start */
-       newvp = paircreate(ATTRIBUTE_EAP_SIM_SUBTYPE, PW_TYPE_INTEGER);
-       newvp->lvalue = eapsim_start;
+       newvp = paircreate(ATTRIBUTE_EAP_SIM_SUBTYPE, 0, PW_TYPE_INTEGER);
+       newvp->vp_integer = eapsim_start;
        pairreplace(&(rep->vps), newvp);
 
        /* insert selected version into response. */
        newvp = paircreate(ATTRIBUTE_EAP_SIM_BASE+PW_EAP_SIM_SELECTED_VERSION,
-                          PW_TYPE_OCTETS);
+                          0, PW_TYPE_OCTETS);
        versions = (uint16_t *)newvp->vp_strvalue;
        versions[0] = htons(selectedversion);
        newvp->length = 2;
@@ -351,16 +430,16 @@ static int process_eap_start(RADIUS_PACKET *req,
                 * insert a nonce_mt that we make up.
                 */
                newvp = paircreate(ATTRIBUTE_EAP_SIM_BASE+PW_EAP_SIM_NONCE_MT,
-                                  PW_TYPE_OCTETS);
-               newvp->vp_strvalue[0]=0;
-               newvp->vp_strvalue[1]=0;
+                                  0, PW_TYPE_OCTETS);
+               newvp->vp_octets[0]=0;
+               newvp->vp_octets[1]=0;
                newvp->length = 18;  /* 16 bytes of nonce + padding */
 
-               nonce[0]=lrad_rand();
-               nonce[1]=lrad_rand();
-               nonce[2]=lrad_rand();
-               nonce[3]=lrad_rand();
-               memcpy(&newvp->vp_strvalue[2], nonce, 16);
+               nonce[0]=fr_rand();
+               nonce[1]=fr_rand();
+               nonce[2]=fr_rand();
+               nonce[3]=fr_rand();
+               memcpy(&newvp->vp_octets[2], nonce, 16);
                pairreplace(&(rep->vps), newvp);
 
                /* also keep a copy of the nonce! */
@@ -373,14 +452,14 @@ static int process_eap_start(RADIUS_PACKET *req,
                /*
                 * insert the identity here.
                 */
-               vp = pairfind(rep->vps, PW_USER_NAME);
+               vp = pairfind(rep->vps, PW_USER_NAME, 0);
                if(vp == NULL)
                {
                        fprintf(stderr, "eap-sim: We need to have a User-Name attribute!\n");
                        return 0;
                }
                newvp = paircreate(ATTRIBUTE_EAP_SIM_BASE+PW_EAP_SIM_IDENTITY,
-                                  PW_TYPE_OCTETS);
+                                  0, PW_TYPE_OCTETS);
                idlen = strlen(vp->vp_strvalue);
                pidlen = (uint16_t *)newvp->vp_strvalue;
                *pidlen = htons(idlen);
@@ -417,9 +496,9 @@ static int process_eap_challenge(RADIUS_PACKET *req,
        uint8_t calcmac[20];
 
        /* look for the AT_MAC and the challenge data */
-       mac   = pairfind(req->vps, ATTRIBUTE_EAP_SIM_BASE+PW_EAP_SIM_MAC);
-       randvp= pairfind(req->vps, ATTRIBUTE_EAP_SIM_BASE+PW_EAP_SIM_RAND);
-       if(mac == NULL || rand == NULL) {
+       mac   = pairfind(req->vps, ATTRIBUTE_EAP_SIM_BASE+PW_EAP_SIM_MAC, 0);
+       randvp= pairfind(req->vps, ATTRIBUTE_EAP_SIM_BASE+PW_EAP_SIM_RAND, 0);
+       if(mac == NULL || randvp == NULL) {
                fprintf(stderr, "radeapclient: challenge message needs to contain RAND and MAC\n");
                return 0;
        }
@@ -430,15 +509,15 @@ static int process_eap_challenge(RADIUS_PACKET *req,
         */
        {
          VALUE_PAIR *randcfgvp[3];
-         unsigned char *randcfg[3];
+         uint8_t *randcfg[3];
 
-         randcfg[0] = &randvp->vp_strvalue[2];
-         randcfg[1] = &randvp->vp_strvalue[2+EAPSIM_RAND_SIZE];
-         randcfg[2] = &randvp->vp_strvalue[2+EAPSIM_RAND_SIZE*2];
+         randcfg[0] = &randvp->vp_octets[2];
+         randcfg[1] = &randvp->vp_octets[2+EAPSIM_RAND_SIZE];
+         randcfg[2] = &randvp->vp_octets[2+EAPSIM_RAND_SIZE*2];
 
-         randcfgvp[0] = pairfind(rep->vps, ATTRIBUTE_EAP_SIM_RAND1);
-         randcfgvp[1] = pairfind(rep->vps, ATTRIBUTE_EAP_SIM_RAND2);
-         randcfgvp[2] = pairfind(rep->vps, ATTRIBUTE_EAP_SIM_RAND3);
+         randcfgvp[0] = pairfind(rep->vps, ATTRIBUTE_EAP_SIM_RAND1, 0);
+         randcfgvp[1] = pairfind(rep->vps, ATTRIBUTE_EAP_SIM_RAND2, 0);
+         randcfgvp[2] = pairfind(rep->vps, ATTRIBUTE_EAP_SIM_RAND3, 0);
 
          if(randcfgvp[0] == NULL ||
             randcfgvp[1] == NULL ||
@@ -447,9 +526,9 @@ static int process_eap_challenge(RADIUS_PACKET *req,
            return 0;
          }
 
-         if(memcmp(randcfg[0], randcfgvp[0]->vp_strvalue, EAPSIM_RAND_SIZE)!=0 ||
-            memcmp(randcfg[1], randcfgvp[1]->vp_strvalue, EAPSIM_RAND_SIZE)!=0 ||
-            memcmp(randcfg[2], randcfgvp[2]->vp_strvalue, EAPSIM_RAND_SIZE)!=0) {
+         if(memcmp(randcfg[0], randcfgvp[0]->vp_octets, EAPSIM_RAND_SIZE)!=0 ||
+            memcmp(randcfg[1], randcfgvp[1]->vp_octets, EAPSIM_RAND_SIZE)!=0 ||
+            memcmp(randcfg[2], randcfgvp[2]->vp_octets, EAPSIM_RAND_SIZE)!=0) {
            int rnum,i,j;
 
            fprintf(stderr, "radeapclient: one of rand 1,2,3 didn't match\n");
@@ -474,7 +553,7 @@ static int process_eap_challenge(RADIUS_PACKET *req,
                }
                j++;
 
-               fprintf(stderr, "%02x", randcfgvp[rnum]->vp_strvalue[i]);
+               fprintf(stderr, "%02x", randcfgvp[rnum]->vp_octets[i]);
              }
              fprintf(stderr, "\n");
            }
@@ -489,9 +568,9 @@ static int process_eap_challenge(RADIUS_PACKET *req,
         * Really, they should be calculated from the RAND!
         *
         */
-       sres1 = pairfind(rep->vps, ATTRIBUTE_EAP_SIM_SRES1);
-       sres2 = pairfind(rep->vps, ATTRIBUTE_EAP_SIM_SRES2);
-       sres3 = pairfind(rep->vps, ATTRIBUTE_EAP_SIM_SRES3);
+       sres1 = pairfind(rep->vps, ATTRIBUTE_EAP_SIM_SRES1, 0);
+       sres2 = pairfind(rep->vps, ATTRIBUTE_EAP_SIM_SRES2, 0);
+       sres3 = pairfind(rep->vps, ATTRIBUTE_EAP_SIM_SRES3, 0);
 
        if(sres1 == NULL ||
           sres2 == NULL ||
@@ -503,9 +582,9 @@ static int process_eap_challenge(RADIUS_PACKET *req,
        memcpy(eapsim_mk.sres[1], sres2->vp_strvalue, sizeof(eapsim_mk.sres[1]));
        memcpy(eapsim_mk.sres[2], sres3->vp_strvalue, sizeof(eapsim_mk.sres[2]));
 
-       Kc1 = pairfind(rep->vps, ATTRIBUTE_EAP_SIM_KC1);
-       Kc2 = pairfind(rep->vps, ATTRIBUTE_EAP_SIM_KC2);
-       Kc3 = pairfind(rep->vps, ATTRIBUTE_EAP_SIM_KC3);
+       Kc1 = pairfind(rep->vps, ATTRIBUTE_EAP_SIM_KC1, 0);
+       Kc2 = pairfind(rep->vps, ATTRIBUTE_EAP_SIM_KC2, 0);
+       Kc3 = pairfind(rep->vps, ATTRIBUTE_EAP_SIM_KC3, 0);
 
        if(Kc1 == NULL ||
           Kc2 == NULL ||
@@ -550,15 +629,15 @@ static int process_eap_challenge(RADIUS_PACKET *req,
        cleanresp(rep);
 
        /* mark the subtype as being EAP-SIM/Response/Start */
-       newvp = paircreate(ATTRIBUTE_EAP_SIM_SUBTYPE, PW_TYPE_INTEGER);
-       newvp->lvalue = eapsim_challenge;
+       newvp = paircreate(ATTRIBUTE_EAP_SIM_SUBTYPE, 0, PW_TYPE_INTEGER);
+       newvp->vp_integer = eapsim_challenge;
        pairreplace(&(rep->vps), newvp);
 
        /*
         * fill the SIM_MAC with a field that will in fact get appended
         * to the packet before the MAC is calculated
         */
-       newvp = paircreate(ATTRIBUTE_EAP_SIM_BASE+PW_EAP_SIM_MAC,
+       newvp = paircreate(ATTRIBUTE_EAP_SIM_BASE+PW_EAP_SIM_MAC, 0,
                           PW_TYPE_OCTETS);
        memcpy(newvp->vp_strvalue+EAPSIM_SRES_SIZE*0, sres1->vp_strvalue, EAPSIM_SRES_SIZE);
        memcpy(newvp->vp_strvalue+EAPSIM_SRES_SIZE*1, sres2->vp_strvalue, EAPSIM_SRES_SIZE);
@@ -566,7 +645,7 @@ static int process_eap_challenge(RADIUS_PACKET *req,
        newvp->length = EAPSIM_SRES_SIZE*3;
        pairreplace(&(rep->vps), newvp);
 
-       newvp = paircreate(ATTRIBUTE_EAP_SIM_KEY, PW_TYPE_OCTETS);
+       newvp = paircreate(ATTRIBUTE_EAP_SIM_KEY, 0, PW_TYPE_OCTETS);
        memcpy(newvp->vp_strvalue,    eapsim_mk.K_aut, EAPSIM_AUTH_SIZE);
        newvp->length = EAPSIM_AUTH_SIZE;
        pairreplace(&(rep->vps), newvp);
@@ -588,12 +667,12 @@ static int respond_eap_sim(RADIUS_PACKET *req,
        VALUE_PAIR *vp, *statevp, *radstate, *eapid;
        char statenamebuf[32], subtypenamebuf[32];
 
-       if ((radstate = paircopy2(req->vps, PW_STATE)) == NULL)
+       if ((radstate = paircopy2(req->vps, PW_STATE, 0)) == NULL)
        {
                return 0;
        }
 
-       if ((eapid = paircopy2(req->vps, ATTRIBUTE_EAP_ID)) == NULL)
+       if ((eapid = paircopy2(req->vps, ATTRIBUTE_EAP_ID, 0)) == NULL)
        {
                return 0;
        }
@@ -602,28 +681,25 @@ static int respond_eap_sim(RADIUS_PACKET *req,
         * outselves to be in EAP-SIM-Start state if there is none.
         */
 
-       if((statevp = pairfind(resp->vps, ATTRIBUTE_EAP_SIM_STATE)) == NULL)
+       if((statevp = pairfind(resp->vps, ATTRIBUTE_EAP_SIM_STATE, 0)) == NULL)
        {
                /* must be initial request */
-               statevp = paircreate(ATTRIBUTE_EAP_SIM_STATE, PW_TYPE_INTEGER);
-               statevp->lvalue = eapsim_client_init;
+               statevp = paircreate(ATTRIBUTE_EAP_SIM_STATE, 0, PW_TYPE_INTEGER);
+               statevp->vp_integer = eapsim_client_init;
                pairreplace(&(resp->vps), statevp);
        }
-       state = statevp->lvalue;
+       state = statevp->vp_integer;
 
        /*
         * map the attributes, and authenticate them.
         */
        unmap_eapsim_types(req);
 
-       printf("<+++ EAP-sim decoded packet:\n");
-       vp_printlist(stdout, req->vps);
-
-       if((vp = pairfind(req->vps, ATTRIBUTE_EAP_SIM_SUBTYPE)) == NULL)
+       if((vp = pairfind(req->vps, ATTRIBUTE_EAP_SIM_SUBTYPE, 0)) == NULL)
        {
                return 0;
        }
-       subtype = vp->lvalue;
+       subtype = vp->vp_integer;
 
        /*
         * look for the appropriate state, and process incoming message
@@ -683,7 +759,7 @@ static int respond_eap_sim(RADIUS_PACKET *req,
        /* copy the radius state object in */
        pairreplace(&(resp->vps), radstate);
 
-       statevp->lvalue = newstate;
+       statevp->vp_integer = newstate;
        return 1;
 }
 
@@ -691,45 +767,45 @@ static int respond_eap_md5(RADIUS_PACKET *req,
                           RADIUS_PACKET *rep)
 {
        VALUE_PAIR *vp, *id, *state;
-       int valuesize, namesize;
-       unsigned char identifier;
-       unsigned char *value;
-       unsigned char *name;
-       MD5_CTX context;
-       char    response[16];
+       size_t valuesize, namesize;
+       uint8_t identifier;
+       uint8_t *value;
+       uint8_t *name;
+       FR_MD5_CTX      context;
+       uint8_t    response[16];
 
        cleanresp(rep);
 
-       if ((state = paircopy2(req->vps, PW_STATE)) == NULL)
+       if ((state = paircopy2(req->vps, PW_STATE, 0)) == NULL)
        {
                fprintf(stderr, "radeapclient: no state attribute found\n");
                return 0;
        }
 
-       if ((id = paircopy2(req->vps, ATTRIBUTE_EAP_ID)) == NULL)
+       if ((id = paircopy2(req->vps, ATTRIBUTE_EAP_ID, 0)) == NULL)
        {
                fprintf(stderr, "radeapclient: no EAP-ID attribute found\n");
                return 0;
        }
-       identifier = id->lvalue;
+       identifier = id->vp_integer;
 
-       if ((vp = pairfind(req->vps, ATTRIBUTE_EAP_BASE+PW_EAP_MD5)) == NULL)
+       if ((vp = pairfind(req->vps, ATTRIBUTE_EAP_BASE+PW_EAP_MD5, 0)) == NULL)
        {
                fprintf(stderr, "radeapclient: no EAP-MD5 attribute found\n");
                return 0;
        }
 
        /* got the details of the MD5 challenge */
-       valuesize = vp->vp_strvalue[0];
-       value = &vp->vp_strvalue[1];
-       name  = &vp->vp_strvalue[valuesize+1];
+       valuesize = vp->vp_octets[0];
+       value = &vp->vp_octets[1];
+       name  = &vp->vp_octets[valuesize+1];
        namesize = vp->length - (valuesize + 1);
 
        /* sanitize items */
        if(valuesize > vp->length)
        {
-               fprintf(stderr, "radeapclient: md5 valuesize if too big (%d > %d)\n",
-                       valuesize, vp->length);
+               fprintf(stderr, "radeapclient: md5 valuesize if too big (%u > %u)\n",
+                       (unsigned int) valuesize, (unsigned int) vp->length);
                return 0;
        }
 
@@ -737,14 +813,14 @@ static int respond_eap_md5(RADIUS_PACKET *req,
         * buffer. We could also call rad_chap_encode, but it wants
         * a CHAP-Challenge, which we don't want to bother with.
         */
-       lrad_MD5Init(&context);
-       lrad_MD5Update(&context, &identifier, 1);
-       lrad_MD5Update(&context, password, strlen(password));
-       lrad_MD5Update(&context, value, valuesize);
-       lrad_MD5Final(response, &context);
-
-       vp = paircreate(ATTRIBUTE_EAP_BASE+PW_EAP_MD5, PW_TYPE_OCTETS);
-       vp->vp_strvalue[0]=16;
+       fr_MD5Init(&context);
+       fr_MD5Update(&context, &identifier, 1);
+       fr_MD5Update(&context, (uint8_t *) password, strlen(password));
+       fr_MD5Update(&context, value, valuesize);
+       fr_MD5Final(response, &context);
+
+       vp = paircreate(ATTRIBUTE_EAP_BASE+PW_EAP_MD5, 0, PW_TYPE_OCTETS);
+       vp->vp_octets[0]=16;
        memcpy(&vp->vp_strvalue[1], response, 16);
        vp->length = 17;
 
@@ -769,16 +845,16 @@ static int sendrecv_eap(RADIUS_PACKET *rep)
        /*
         *      Keep a copy of the the User-Password attribute.
         */
-       if ((vp = pairfind(rep->vps, ATTRIBUTE_EAP_MD5_PASSWORD)) != NULL) {
-               strNcpy(password, (char *)vp->vp_strvalue, sizeof(vp->vp_strvalue));
+       if ((vp = pairfind(rep->vps, PW_CLEARTEXT_PASSWORD, 0)) != NULL) {
+               strlcpy(password, (char *)vp->vp_strvalue, sizeof(vp->vp_strvalue));
 
-       } else  if ((vp = pairfind(rep->vps, PW_PASSWORD)) != NULL) {
-               strNcpy(password, (char *)vp->vp_strvalue, sizeof(vp->vp_strvalue));
+       } else  if ((vp = pairfind(rep->vps, PW_USER_PASSWORD, 0)) != NULL) {
+               strlcpy(password, (char *)vp->vp_strvalue, sizeof(vp->vp_strvalue));
                /*
                 *      Otherwise keep a copy of the CHAP-Password attribute.
                 */
-       } else if ((vp = pairfind(rep->vps, PW_CHAP_PASSWORD)) != NULL) {
-               strNcpy(password, (char *)vp->vp_strvalue, sizeof(vp->vp_strvalue));
+       } else if ((vp = pairfind(rep->vps, PW_CHAP_PASSWORD, 0)) != NULL) {
+               strlcpy(password, (char *)vp->vp_strvalue, sizeof(vp->vp_strvalue));
        } else {
                *password = '\0';
        }
@@ -786,9 +862,6 @@ static int sendrecv_eap(RADIUS_PACKET *rep)
  again:
        rep->id++;
 
-       printf("\n+++> About to send encoded packet:\n");
-       vp_printlist(stdout, rep->vps);
-
        /*
         * if there are EAP types, encode them into an EAP-Message
         *
@@ -814,10 +887,10 @@ static int sendrecv_eap(RADIUS_PACKET *rep)
                case PW_DIGEST_NONCE_COUNT:
                case PW_DIGEST_USER_NAME:
                        /* overlapping! */
-                       memmove(&vp->vp_strvalue[2], &vp->vp_strvalue[0], vp->length);
-                       vp->vp_strvalue[0] = vp->attribute - PW_DIGEST_REALM + 1;
+                       memmove(&vp->vp_strvalue[2], &vp->vp_octets[0], vp->length);
+                       vp->vp_octets[0] = vp->attribute - PW_DIGEST_REALM + 1;
                        vp->length += 2;
-                       vp->vp_strvalue[1] = vp->length;
+                       vp->vp_octets[1] = vp->length;
                        vp->attribute = PW_DIGEST_ATTRIBUTES;
                        break;
                }
@@ -833,19 +906,23 @@ static int sendrecv_eap(RADIUS_PACKET *rep)
                rep->data = NULL;
        }
 
-       librad_md5_calc(rep->vector, rep->vector,
+       fr_md5_calc(rep->vector, rep->vector,
                        sizeof(rep->vector));
 
        if (*password != '\0') {
-               if ((vp = pairfind(rep->vps, PW_PASSWORD)) != NULL) {
-                       strNcpy((char *)vp->vp_strvalue, password, strlen(password) + 1);
+               if ((vp = pairfind(rep->vps, PW_CLEARTEXT_PASSWORD, 0)) != NULL) {
+                       strlcpy((char *)vp->vp_strvalue, password, sizeof(vp->vp_strvalue));
+                       vp->length = strlen(password);
+
+               } else if ((vp = pairfind(rep->vps, PW_USER_PASSWORD, 0)) != NULL) {
+                       strlcpy((char *)vp->vp_strvalue, password, sizeof(vp->vp_strvalue));
                        vp->length = strlen(password);
 
-               } else if ((vp = pairfind(rep->vps, PW_CHAP_PASSWORD)) != NULL) {
-                       strNcpy((char *)vp->vp_strvalue, password, strlen(password) + 1);
+               } else if ((vp = pairfind(rep->vps, PW_CHAP_PASSWORD, 0)) != NULL) {
+                       strlcpy((char *)vp->vp_strvalue, password, sizeof(vp->vp_strvalue));
                        vp->length = strlen(password);
 
-                       rad_chap_encode(rep, (char *) vp->vp_strvalue, rep->id, vp);
+                       rad_chap_encode(rep, vp->vp_octets, rep->id, vp);
                        vp->length = 17;
                }
        } /* there WAS a password */
@@ -856,8 +933,7 @@ static int sendrecv_eap(RADIUS_PACKET *rep)
        /* okay got back the packet, go and decode the EAP-Message. */
        unmap_eap_types(req);
 
-       printf("<+++ EAP decoded packet:\n");
-       vp_printlist(stdout, req->vps);
+       debug_packet(req, R_RECV);
 
        /* now look for the code type. */
        for (vp = req->vps; vp != NULL; vp = vpnext) {
@@ -900,7 +976,7 @@ int main(int argc, char **argv)
        int id;
 
        id = ((int)getpid() & 0xff);
-       librad_debug = 0;
+       fr_debug_flag = 0;
 
        radlog_dest = RADLOG_STDERR;
 
@@ -913,7 +989,7 @@ int main(int argc, char **argv)
                        count = atoi(optarg);
                        break;
                case 'd':
-                       radius_dir = optarg;
+                       radius_dir = strdup(optarg);
                        break;
                case 'f':
                        filename = optarg;
@@ -923,11 +999,13 @@ int main(int argc, char **argv)
                        break;
                case 'x':
                        debug_flag++;
-                       librad_debug++;
+                       fr_debug_flag++;
                        break;
 
                case 'X':
-                 sha1_data_problems = 1;
+#if 0
+                 sha1_data_problems = 1; /* for debugging only */
+#endif
                  break;
 
 
@@ -999,13 +1077,15 @@ int main(int argc, char **argv)
                usage();
        }
 
+       if (!radius_dir) radius_dir = strdup(RADDBDIR);
+
        if (dict_init(radius_dir, RADIUS_DICTIONARY) < 0) {
-               librad_perror("radclient");
+               fr_perror("radclient");
                return 1;
        }
 
        if ((req = rad_alloc(1)) == NULL) {
-               librad_perror("radclient");
+               fr_perror("radclient");
                exit(1);
        }
 
@@ -1021,7 +1101,7 @@ int main(int argc, char **argv)
                        fclose(randinit);
                }
        }
-       lrad_randinit(&randctx, 1);
+       fr_randinit(&randctx, 1);
 #endif
 
        req->id = id;
@@ -1066,11 +1146,6 @@ int main(int argc, char **argv)
        }
 
        /*
-        *      Ensure that the configuration is initialized.
-        */
-       memset(&mainconfig, 0, sizeof(mainconfig));
-
-       /*
         *      Resolve hostname.
         */
        req->dst_port = port;
@@ -1119,9 +1194,316 @@ int main(int argc, char **argv)
                sendrecv_eap(req);
        }
 
+       free(radius_dir);
        if(do_summary) {
                printf("\n\t   Total approved auths:  %d\n", totalapp);
                printf("\t     Total denied auths:  %d\n", totaldeny);
        }
        return 0;
 }
+
+/*
+ * given a radius request with some attributes in the EAP range, build
+ * them all into a single EAP-Message body.
+ *
+ * Note that this function will build multiple EAP-Message bodies
+ * if there are multiple eligible EAP-types. This is incorrect, as the
+ * recipient will in fact concatenate them.
+ *
+ * XXX - we could break the loop once we process one type. Maybe this
+ *       just deserves an assert?
+ *
+ */
+static void map_eap_types(RADIUS_PACKET *req)
+{
+       VALUE_PAIR *vp, *vpnext;
+       int id, eapcode;
+       EAP_PACKET ep;
+       int eap_type;
+
+       vp = pairfind(req->vps, ATTRIBUTE_EAP_ID, 0);
+       if(vp == NULL) {
+               id = ((int)getpid() & 0xff);
+       } else {
+               id = vp->vp_integer;
+       }
+
+       vp = pairfind(req->vps, ATTRIBUTE_EAP_CODE, 0);
+       if(vp == NULL) {
+               eapcode = PW_EAP_REQUEST;
+       } else {
+               eapcode = vp->vp_integer;
+       }
+
+
+       for(vp = req->vps; vp != NULL; vp = vpnext) {
+               /* save it in case it changes! */
+               vpnext = vp->next;
+
+               if(vp->attribute >= ATTRIBUTE_EAP_BASE &&
+                  vp->attribute < ATTRIBUTE_EAP_BASE+256) {
+                       break;
+               }
+       }
+
+       if(vp == NULL) {
+               return;
+       }
+
+       eap_type = vp->attribute - ATTRIBUTE_EAP_BASE;
+
+       switch(eap_type) {
+       case PW_EAP_IDENTITY:
+       case PW_EAP_NOTIFICATION:
+       case PW_EAP_NAK:
+       case PW_EAP_MD5:
+       case PW_EAP_OTP:
+       case PW_EAP_GTC:
+       case PW_EAP_TLS:
+       case PW_EAP_LEAP:
+       case PW_EAP_TTLS:
+       case PW_EAP_PEAP:
+       default:
+               /*
+                * no known special handling, it is just encoded as an
+                * EAP-message with the given type.
+                */
+
+               /* nuke any existing EAP-Messages */
+               pairdelete(&req->vps, PW_EAP_MESSAGE, 0);
+
+               memset(&ep, 0, sizeof(ep));
+               ep.code = eapcode;
+               ep.id   = id;
+               ep.type.type = eap_type;
+               ep.type.length = vp->length;
+               ep.type.data = malloc(vp->length);
+               memcpy(ep.type.data,vp->vp_octets, vp->length);
+               eap_basic_compose(req, &ep);
+       }
+}
+
+/*
+ * given a radius request with an EAP-Message body, decode it specific
+ * attributes.
+ */
+static void unmap_eap_types(RADIUS_PACKET *rep)
+{
+       VALUE_PAIR *eap1;
+       eap_packet_t *e;
+       int len;
+       int type;
+
+       /* find eap message */
+       e = eap_vp2packet(rep->vps);
+
+       /* nothing to do! */
+       if(e == NULL) return;
+
+       /* create EAP-ID and EAP-CODE attributes to start */
+       eap1 = paircreate(ATTRIBUTE_EAP_ID, 0, PW_TYPE_INTEGER);
+       eap1->vp_integer = e->id;
+       pairadd(&(rep->vps), eap1);
+
+       eap1 = paircreate(ATTRIBUTE_EAP_CODE, 0, PW_TYPE_INTEGER);
+       eap1->vp_integer = e->code;
+       pairadd(&(rep->vps), eap1);
+
+       switch(e->code)
+       {
+       default:
+       case PW_EAP_SUCCESS:
+       case PW_EAP_FAILURE:
+               /* no data */
+               break;
+
+       case PW_EAP_REQUEST:
+       case PW_EAP_RESPONSE:
+               /* there is a type field, which we use to create
+                * a new attribute */
+
+               /* the length was decode already into the attribute
+                * length, and was checked already. Network byte
+                * order, just pull it out using math.
+                */
+               len = e->length[0]*256 + e->length[1];
+
+               /* verify the length is big enough to hold type */
+               if(len < 5)
+               {
+                       free(e);
+                       return;
+               }
+
+               type = e->data[0];
+
+               type += ATTRIBUTE_EAP_BASE;
+               len -= 5;
+
+               if(len > MAX_STRING_LEN) {
+                       len = MAX_STRING_LEN;
+               }
+
+               eap1 = paircreate(type, 0, PW_TYPE_OCTETS);
+               memcpy(eap1->vp_strvalue, &e->data[1], len);
+               eap1->length = len;
+               pairadd(&(rep->vps), eap1);
+               break;
+       }
+
+       free(e);
+       return;
+}
+
+static int map_eapsim_types(RADIUS_PACKET *r)
+{
+       EAP_PACKET ep;
+       int ret;
+
+       memset(&ep, 0, sizeof(ep));
+       ret = map_eapsim_basictypes(r, &ep);
+       if(ret != 1) {
+               return ret;
+       }
+       eap_basic_compose(r, &ep);
+
+       return 1;
+}
+
+static int unmap_eapsim_types(RADIUS_PACKET *r)
+{
+       VALUE_PAIR             *esvp;
+
+       esvp = pairfind(r->vps, ATTRIBUTE_EAP_BASE+PW_EAP_SIM, 0);
+       if (esvp == NULL) {
+               radlog(L_ERR, "eap: EAP-Sim attribute not found");
+               return 0;
+       }
+
+       return unmap_eapsim_basictypes(r, esvp->vp_octets, esvp->length);
+}
+
+#ifdef TEST_CASE
+
+#include <assert.h>
+
+const char *radius_dir = RADDBDIR;
+
+int radlog(int lvl, const char *msg, ...)
+{
+       va_list ap;
+       int r;
+
+       va_start(ap, msg);
+       r = vfprintf(stderr, msg, ap);
+       va_end(ap);
+       fputc('\n', stderr);
+
+       return r;
+}
+
+main(int argc, char *argv[])
+{
+       int filedone;
+       RADIUS_PACKET *req,*req2;
+       VALUE_PAIR *vp, *vpkey, *vpextra;
+       extern unsigned int sha1_data_problems;
+
+       req = NULL;
+       req2 = NULL;
+       filedone = 0;
+
+       if(argc>1) {
+         sha1_data_problems = 1;
+       }
+
+       if (dict_init(radius_dir, RADIUS_DICTIONARY) < 0) {
+               fr_perror("radclient");
+               return 1;
+       }
+
+       if ((req = rad_alloc(1)) == NULL) {
+               fr_perror("radclient");
+               exit(1);
+       }
+
+       if ((req2 = rad_alloc(1)) == NULL) {
+               fr_perror("radclient");
+               exit(1);
+       }
+
+       while(!filedone) {
+               if(req->vps) pairfree(&req->vps);
+               if(req2->vps) pairfree(&req2->vps);
+
+               if ((req->vps = readvp2(stdin, &filedone, "eapsimlib:")) == NULL) {
+                       break;
+               }
+
+               if (fr_debug_flag > 1) {
+                       printf("\nRead:\n");
+                       vp_printlist(stdout, req->vps);
+               }
+
+               map_eapsim_types(req);
+               map_eap_types(req);
+
+               if (fr_debug_flag > 1) {
+                       printf("Mapped to:\n");
+                       vp_printlist(stdout, req->vps);
+               }
+
+               /* find the EAP-Message, copy it to req2 */
+               vp = paircopy2(req->vps, PW_EAP_MESSAGE);
+
+               if(vp == NULL) continue;
+
+               pairadd(&req2->vps, vp);
+
+               /* only call unmap for sim types here */
+               unmap_eap_types(req2);
+               unmap_eapsim_types(req2);
+
+               if (fr_debug_flag > 1) {
+                       printf("Unmapped to:\n");
+                       vp_printlist(stdout, req2->vps);
+               }
+
+               vp = pairfind(req2->vps,
+                             ATTRIBUTE_EAP_SIM_BASE+PW_EAP_SIM_MAC);
+               vpkey   = pairfind(req->vps, ATTRIBUTE_EAP_SIM_KEY);
+               vpextra = pairfind(req->vps, ATTRIBUTE_EAP_SIM_EXTRA);
+
+               if(vp != NULL && vpkey != NULL && vpextra!=NULL) {
+                       uint8_t calcmac[16];
+
+                       /* find the EAP-Message, copy it to req2 */
+
+                       memset(calcmac, 0, sizeof(calcmac));
+                       printf("Confirming MAC...");
+                       if(eapsim_checkmac(req2->vps, vpkey->vp_strvalue,
+                                          vpextra->vp_strvalue, vpextra->length,
+                                          calcmac)) {
+                               printf("succeed\n");
+                       } else {
+                               int i, j;
+
+                               printf("calculated MAC (");
+                               for (i = 0; i < 20; i++) {
+                                       if(j==4) {
+                                               printf("_");
+                                               j=0;
+                                       }
+                                       j++;
+
+                                       printf("%02x", calcmac[i]);
+                               }
+                               printf(" did not match\n");
+                       }
+               }
+
+               fflush(stdout);
+       }
+}
+#endif
+