*
* 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"
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; */
+#ifdef WITH_TLS
+#include <freeradius-devel/tls.h>
+#endif
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 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");
fprintf(stderr, " -f file Read packets from file, not stdin.\n");
fprintf(stderr, " -r retries If timeout, retry sending the packet 'retries' times.\n");
fprintf(stderr, " -t timeout Wait 'timeout' seconds before retrying (may be a floating point number).\n");
+ fprintf(stderr, " -h Print usage help information.\n");
fprintf(stderr, " -i id Set request id to 'id'. Values may be 0..255\n");
fprintf(stderr, " -S file read secret from file, not command line.\n");
fprintf(stderr, " -q Do not print anything out.\n");
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;
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;
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 */
continue;
}
- *rep = rad_recv(req->sockfd);
+ *rep = rad_recv(req->sockfd, 0);
if (*rep != NULL) {
/*
* If we get a response from a machine
* which we did NOT send a request to,
* then complain.
*/
- if (((*rep)->src_ipaddr != req->dst_ipaddr) ||
+ if (((*rep)->src_ipaddr.af != req->dst_ipaddr.af) ||
+ (memcmp(&(*rep)->src_ipaddr.ipaddr,
+ &req->dst_ipaddr.ipaddr,
+ ((req->dst_ipaddr.af == AF_INET ? /* AF_INET6? */
+ sizeof(req->dst_ipaddr.ipaddr.ip4addr) : /* FIXME: AF_INET6 */
+ sizeof(req->dst_ipaddr.ipaddr.ip6addr)))) != 0) ||
((*rep)->src_port != req->dst_port)) {
- char src[64], dst[64];
+ char src[128], dst[128];
- ip_ntoa(src, (*rep)->src_ipaddr);
- ip_ntoa(dst, req->dst_ipaddr);
+ ip_ntoh(&(*rep)->src_ipaddr, src, sizeof(src));
+ ip_ntoh(&req->dst_ipaddr, dst, sizeof(dst));
fprintf(stderr, "radclient: ERROR: Sent request to host %s port %d, got response from host %s port %d\n!",
dst, req->dst_port,
src, (*rep)->src_port);
}
break;
} else { /* NULL: couldn't receive the packet */
- librad_perror("radclient:");
+ fr_perror("radclient:");
exit(1);
}
}
*
* 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++;
}
* 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)
/* 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;
}
- versions = (uint16_t *)vp->strvalue;
+ versions = (uint16_t *)vp->vp_strvalue;
/* 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;
}
*/
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;
}
* 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 ||
/* 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);
- versions = (uint16_t *)newvp->strvalue;
+ 0, PW_TYPE_OCTETS);
+ versions = (uint16_t *)newvp->vp_strvalue;
versions[0] = htons(selectedversion);
newvp->length = 2;
pairreplace(&(rep->vps), newvp);
* insert a nonce_mt that we make up.
*/
newvp = paircreate(ATTRIBUTE_EAP_SIM_BASE+PW_EAP_SIM_NONCE_MT,
- PW_TYPE_OCTETS);
- newvp->strvalue[0]=0;
- newvp->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->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! */
/*
* 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);
- idlen = strlen(vp->strvalue);
- pidlen = (uint16_t *)newvp->strvalue;
+ 0, PW_TYPE_OCTETS);
+ idlen = strlen(vp->vp_strvalue);
+ pidlen = (uint16_t *)newvp->vp_strvalue;
*pidlen = htons(idlen);
newvp->length = idlen + 2;
- memcpy(&newvp->strvalue[2], vp->strvalue, idlen);
+ memcpy(&newvp->vp_strvalue[2], vp->vp_strvalue, idlen);
pairreplace(&(rep->vps), newvp);
/* record it */
- memcpy(eapsim_mk.identity, vp->strvalue, idlen);
+ memcpy(eapsim_mk.identity, vp->vp_strvalue, idlen);
eapsim_mk.identitylen = idlen;
}
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;
}
*/
{
VALUE_PAIR *randcfgvp[3];
- unsigned char *randcfg[3];
+ uint8_t *randcfg[3];
- randcfg[0] = &randvp->strvalue[2];
- randcfg[1] = &randvp->strvalue[2+EAPSIM_RAND_SIZE];
- randcfg[2] = &randvp->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 ||
return 0;
}
- if(memcmp(randcfg[0], randcfgvp[0]->strvalue, EAPSIM_RAND_SIZE)!=0 ||
- memcmp(randcfg[1], randcfgvp[1]->strvalue, EAPSIM_RAND_SIZE)!=0 ||
- memcmp(randcfg[2], randcfgvp[2]->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");
}
j++;
- fprintf(stderr, "%02x", randcfgvp[rnum]->strvalue[i]);
+ fprintf(stderr, "%02x", randcfgvp[rnum]->vp_octets[i]);
}
fprintf(stderr, "\n");
}
* 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 ||
fprintf(stderr, "radeapclient: needs to have sres1, 2 and 3 set.\n");
return 0;
}
- memcpy(eapsim_mk.sres[0], sres1->strvalue, sizeof(eapsim_mk.sres[0]));
- memcpy(eapsim_mk.sres[1], sres2->strvalue, sizeof(eapsim_mk.sres[1]));
- memcpy(eapsim_mk.sres[2], sres3->strvalue, sizeof(eapsim_mk.sres[2]));
+ memcpy(eapsim_mk.sres[0], sres1->vp_strvalue, sizeof(eapsim_mk.sres[0]));
+ 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 ||
fprintf(stderr, "radeapclient: needs to have Kc1, 2 and 3 set.\n");
return 0;
}
- memcpy(eapsim_mk.Kc[0], Kc1->strvalue, sizeof(eapsim_mk.Kc[0]));
- memcpy(eapsim_mk.Kc[1], Kc2->strvalue, sizeof(eapsim_mk.Kc[1]));
- memcpy(eapsim_mk.Kc[2], Kc3->strvalue, sizeof(eapsim_mk.Kc[2]));
+ memcpy(eapsim_mk.Kc[0], Kc1->vp_strvalue, sizeof(eapsim_mk.Kc[0]));
+ memcpy(eapsim_mk.Kc[1], Kc2->vp_strvalue, sizeof(eapsim_mk.Kc[1]));
+ memcpy(eapsim_mk.Kc[2], Kc3->vp_strvalue, sizeof(eapsim_mk.Kc[2]));
/* all set, calculate keys */
eapsim_calculate_keys(&eapsim_mk);
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->strvalue+EAPSIM_SRES_SIZE*0, sres1->strvalue, EAPSIM_SRES_SIZE);
- memcpy(newvp->strvalue+EAPSIM_SRES_SIZE*1, sres2->strvalue, EAPSIM_SRES_SIZE);
- memcpy(newvp->strvalue+EAPSIM_SRES_SIZE*2, sres3->strvalue, EAPSIM_SRES_SIZE);
+ 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);
+ memcpy(newvp->vp_strvalue+EAPSIM_SRES_SIZE*2, sres3->vp_strvalue, EAPSIM_SRES_SIZE);
newvp->length = EAPSIM_SRES_SIZE*3;
pairreplace(&(rep->vps), newvp);
- newvp = paircreate(ATTRIBUTE_EAP_SIM_KEY, PW_TYPE_OCTETS);
- memcpy(newvp->strvalue, eapsim_mk.K_aut, EAPSIM_AUTH_SIZE);
+ 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);
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;
}
* 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
/* copy the radius state object in */
pairreplace(&(resp->vps), radstate);
- statevp->lvalue = newstate;
+ statevp->vp_integer = newstate;
return 1;
}
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->strvalue[0];
- value = &vp->strvalue[1];
- name = &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;
}
* buffer. We could also call rad_chap_encode, but it wants
* a CHAP-Challenge, which we don't want to bother with.
*/
- librad_MD5Init(&context);
- librad_MD5Update(&context, &identifier, 1);
- librad_MD5Update(&context, password, strlen(password));
- librad_MD5Update(&context, value, valuesize);
- librad_MD5Final(response, &context);
-
- vp = paircreate(ATTRIBUTE_EAP_BASE+PW_EAP_MD5, PW_TYPE_OCTETS);
- vp->strvalue[0]=16;
- memcpy(&vp->strvalue[1], response, 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;
pairreplace(&(rep->vps), vp);
/*
* Keep a copy of the the User-Password attribute.
*/
- if ((vp = pairfind(rep->vps, ATTRIBUTE_EAP_MD5_PASSWORD)) != NULL) {
- strNcpy(password, (char *)vp->strvalue, sizeof(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->strvalue, sizeof(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->strvalue, sizeof(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';
}
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
*
case PW_DIGEST_NONCE_COUNT:
case PW_DIGEST_USER_NAME:
/* overlapping! */
- memmove(&vp->strvalue[2], &vp->strvalue[0], vp->length);
- 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->strvalue[1] = vp->length;
+ vp->vp_octets[1] = vp->length;
vp->attribute = PW_DIGEST_ATTRIBUTES;
break;
}
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->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->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->strvalue, rep->id, vp);
+ rad_chap_encode(rep, vp->vp_octets, rep->id, vp);
vp->length = 17;
}
} /* there WAS a password */
/* 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) {
int id;
id = ((int)getpid() & 0xff);
- librad_debug = 0;
+ fr_debug_flag = 0;
radlog_dest = RADLOG_STDERR;
count = atoi(optarg);
break;
case 'd':
- radius_dir = optarg;
+ radius_dir = strdup(optarg);
break;
case 'f':
filename = optarg;
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;
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);
}
fclose(randinit);
}
}
- lrad_randinit(&randctx, 1);
+ fr_randinit(&randctx, 1);
#endif
req->id = id;
}
/*
- * Ensure that the configuration is initialized.
- */
- memset(&mainconfig, 0, sizeof(mainconfig));
-
- /*
* Resolve hostname.
*/
req->dst_port = port;
- req->dst_ipaddr = ip_getaddr(argv[1]);
- if (req->dst_ipaddr == INADDR_NONE) {
+ if (ip_hton(argv[1], AF_INET, &req->dst_ipaddr) < 0) {
fprintf(stderr, "radclient: Failed to find IP address for host %s\n", argv[1]);
exit(1);
}
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, 0);
+ vpkey = pairfind(req->vps, ATTRIBUTE_EAP_SIM_KEY, 0);
+ vpextra = pairfind(req->vps, ATTRIBUTE_EAP_SIM_EXTRA, 0);
+
+ 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
+