X-Git-Url: http://www.project-moonshot.org/gitweb/?a=blobdiff_plain;f=src%2Fmodules%2Frlm_eap%2Fradeapclient.c;h=9bcd20e5a80b6415c60eaa0f72a5b15db6f04814;hb=bca85674a83f94b9cfae0ebdc129bbaf645c8f7d;hp=0e00ad2048126bd99e9a3b9abff7a9ff25bce742;hpb=a181002e0e879ea9d5b187497a2fd4d772ad34bb;p=freeradius.git diff --git a/src/modules/rlm_eap/radeapclient.c b/src/modules/rlm_eap/radeapclient.c index 0e00ad2..9bcd20e 100644 --- a/src/modules/rlm_eap/radeapclient.c +++ b/src/modules/rlm_eap/radeapclient.c @@ -15,44 +15,27 @@ * * 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 * Copyright 2000 Alan DeKok */ -static const char rcsid[] = "$Id$"; -#include "autoconf.h" +#include +RCSID("$Id$") -#include -#include +#include -#if HAVE_UNISTD_H -# include -#endif - -#include #include -#include -#include - -#if HAVE_NETINET_IN_H -# include -#endif - -#if HAVE_SYS_SELECT_H -# include -#endif #if HAVE_GETOPT_H # include #endif -#include "conf.h" -#include "radpaths.h" -#include "missing.h" -#include "../include/md5.h" +#include +#include +#include #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] []\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 + +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 +