⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 radeapclient.c

📁 RADIUS认证协议
💻 C
📖 第 1 页 / 共 2 页
字号:
/* * radeapclient.c	EAP specific radius packet debug tool. * * Version:	$Id: radeapclient.c,v 1.7 2004/02/26 19:04:29 aland Exp $ * *   This program is free software; you can redistribute it and/or modify *   it under the terms of the GNU General Public License as published by *   the Free Software Foundation; either version 2 of the License, or *   (at your option) any later version. * *   This program is distributed in the hope that it will be useful, *   but WITHOUT ANY WARRANTY; without even the implied warranty of *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the *   GNU General Public License for more details. * *   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 * * Copyright 2000  The FreeRADIUS server project * Copyright 2000  Miquel van Smoorenburg <miquels@cistron.nl> * Copyright 2000  Alan DeKok <aland@ox.org> */static const char rcsid[] = "$Id: radeapclient.c,v 1.7 2004/02/26 19:04:29 aland Exp $";#include "autoconf.h"#include "libradius.h"#include <stdio.h>#include <stdlib.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 "eap_types.h"#include "eap_sim.h"extern int sha1_data_problems;static int retries = 10;static float timeout = 3;static const char *secret = NULL;static int do_output = 1;static int do_summary = 0;static int filedone = 0;static int totalapp = 0;static int totaldeny = 0;static char filesecret[256];const char *radius_dir = RADDBDIR;const char *progname = "radeapclient";/* lrad_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){	fprintf(stderr, "Usage: radeapclient [options] server[:port] <command> [<secret>]\n");	fprintf(stderr, "  <command>    One of auth, acct, status, or disconnect.\n");	fprintf(stderr, "  -c count    Send each packet 'count' times.\n");	fprintf(stderr, "  -d raddb    Set dictionary directory.\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, "  -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");	fprintf(stderr, "  -s          Print out summary information of auth results.\n");	fprintf(stderr, "  -v          Show program version information.\n");	fprintf(stderr, "  -x          Debugging mode.\n");	exit(1);}int radlog(int lvl, const char *msg, ...){	va_list ap;	int r;	r = lvl; /* shut up compiler */	va_start(ap, msg);	r = vfprintf(stderr, msg, ap);	va_end(ap);	fputc('\n', stderr);	return r;}static int getport(const char *name){	struct	servent		*svp;	svp = getservbyname (name, "udp");	if (!svp) {		return 0;	}	return ntohs(svp->s_port);}static int send_packet(RADIUS_PACKET *req, RADIUS_PACKET **rep){	int i;	struct timeval	tv;	for (i = 0; i < retries; i++) {		fd_set		rdfdesc;		rad_send(req, NULL, secret);		/* And wait for reply, timing out as necessary */		FD_ZERO(&rdfdesc);		FD_SET(req->sockfd, &rdfdesc);		tv.tv_sec = (int)timeout;		tv.tv_usec = 1000000 * (timeout - (int) timeout);		/* Something's wrong if we don't get exactly one fd. */		if (select(req->sockfd + 1, &rdfdesc, NULL, NULL, &tv) != 1) {			continue;		}		*rep = rad_recv(req->sockfd);		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) ||			    ((*rep)->src_port != req->dst_port)) {				char src[64], dst[64];				ip_ntoa(src, (*rep)->src_ipaddr);				ip_ntoa(dst, req->dst_ipaddr);				fprintf(stderr, "radclient: ERROR: Sent request to host %s:%d, got response from host %s:%d\n!",					dst, req->dst_port,					src, (*rep)->src_port);				exit(1);			}			break;		} else {	/* NULL: couldn't receive the packet */			librad_perror("radclient:");			exit(1);		}	}	/* No response or no data read (?) */	if (i == retries) {		fprintf(stderr, "radclient: no response from server\n");		exit(1);	}	if (rad_decode(*rep, req, secret) != 0) {		librad_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((*rep)->code == PW_AUTHENTICATION_ACK) {		totalapp++;	} else {		totaldeny++;	}	return 0;}static void cleanresp(RADIUS_PACKET *resp){	VALUE_PAIR *vpnext, *vp, **last;	/*	 * 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);	last = &resp->vps;	for(vp = *last; vp != NULL; vp = vpnext)	{		vpnext = vp->next;		if((vp->attribute > ATTRIBUTE_EAP_BASE &&		    vp->attribute <= ATTRIBUTE_EAP_BASE+256) ||		   (vp->attribute > ATTRIBUTE_EAP_SIM_BASE &&		    vp->attribute <= ATTRIBUTE_EAP_SIM_BASE+256))		{			*last = vpnext;			pairbasicfree(vp);		} else {			last = &vp->next;		}	}}/* * we got an EAP-Request/Sim/Start message in a legal state. * * pick a supported version, put it into the reply, and insert a nonce. */static int process_eap_start(RADIUS_PACKET *req,			     RADIUS_PACKET *rep){	VALUE_PAIR *vp, *newvp;	VALUE_PAIR *anyidreq_vp, *fullauthidreq_vp, *permanentidreq_vp;	uint16_t *versions, selectedversion;	unsigned int i,versioncount;	/* 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) {		fprintf(stderr, "illegal start message has no VERSION_LIST\n");		return 0;	}	versions = (uint16_t *)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);		return 0;	}	versioncount = ntohs(versions[0])/2;	/* verify that the attribute length is big enough for the given number	 * of versions present.	 */	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);		return 0;	}	/*	 * record the versionlist for the MK calculation.	 */	eapsim_mk.versionlistlen = versioncount*2;	memcpy(eapsim_mk.versionlist, (unsigned char *)(versions+1),	       eapsim_mk.versionlistlen);	/* walk the version list, and pick the one we support, which	 * at present, is 1, EAP_SIM_VERSION.	 */	selectedversion=0;	for(i=0; i < versioncount; i++)	{		if(ntohs(versions[i+1]) == EAP_SIM_VERSION)		{			selectedversion=EAP_SIM_VERSION;			break;		}	}	if(selectedversion == 0)	{		fprintf(stderr, "eap-sim start message. No compatible version found. We need %d\n", EAP_SIM_VERSION);		for(i=0; i < versioncount; i++)		{			fprintf(stderr, "\tfound version %d\n",				ntohs(versions[i+1]));		}	}	/*	 * now make sure that we have only FULLAUTH_ID_REQ.	 * I think that it actually might not matter - we can answer in	 * 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);	if(fullauthidreq_vp == NULL ||	   anyidreq_vp != NULL ||	   permanentidreq_vp != NULL) {		fprintf(stderr, "start message has %sanyidreq, %sfullauthid and %spermanentid. Illegal combination.\n",			(anyidreq_vp != NULL ? "a " : "no "),			(fullauthidreq_vp != NULL ? "a " : "no "),			(permanentidreq_vp != NULL ? "a " : "no "));		return 0;	}	/* 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;	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;	versions[0] = htons(selectedversion);	newvp->length = 2;	pairreplace(&(rep->vps), newvp);	/* record the selected version */	memcpy(eapsim_mk.versionselect, (unsigned char *)versions, 2);	vp = newvp = NULL;	{		uint32_t nonce[4];		/*		 * 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;		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);		pairreplace(&(rep->vps), newvp);		/* also keep a copy of the nonce! */		memcpy(eapsim_mk.nonce_mt, nonce, 16);	}	{		uint16_t *pidlen, idlen;		/*		 * insert the identity here.		 */		vp = pairfind(rep->vps, PW_USER_NAME);		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;		*pidlen = htons(idlen);		newvp->length = idlen + 2;		memcpy(&newvp->strvalue[2], vp->strvalue, idlen);		pairreplace(&(rep->vps), newvp);		/* record it */		memcpy(eapsim_mk.identity, vp->strvalue, idlen);		eapsim_mk.identitylen = idlen;	}	return 1;}/* * we got an EAP-Request/Sim/Challenge message in a legal state. * * use the RAND challenge to produce the SRES result, and then * use that to generate a new MAC. * * for the moment, we ignore the RANDs, then just plug in the SRES * values. * */static int process_eap_challenge(RADIUS_PACKET *req,				 RADIUS_PACKET *rep){	VALUE_PAIR *newvp;	VALUE_PAIR *mac, *randvp;	VALUE_PAIR *sres1,*sres2,*sres3;	VALUE_PAIR *Kc1, *Kc2, *Kc3;	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) {		fprintf(stderr, "radeapclient: challenge message needs to contain RAND and MAC\n");		return 0;	}	/*	 * compare RAND with randX, to verify this is the right response	 * to this challenge.	 */	{	  VALUE_PAIR *randcfgvp[3];	  unsigned char *randcfg[3];	  randcfg[0] = &randvp->strvalue[2];	  randcfg[1] = &randvp->strvalue[2+EAPSIM_RAND_SIZE];	  randcfg[2] = &randvp->strvalue[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);	  if(randcfgvp[0] == NULL ||	     randcfgvp[1] == NULL ||	     randcfgvp[2] == NULL) {	    fprintf(stderr, "radeapclient: needs to have rand1, 2 and 3 set.\n");	    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) {	    int rnum,i,j;	    fprintf(stderr, "radeapclient: one of rand 1,2,3 didn't match\n");	    for(rnum = 0; rnum < 3; rnum++) {	      fprintf(stderr, "received   rand %d: ", rnum);	      j=0;	      for (i = 0; i < EAPSIM_RAND_SIZE; i++) {		if(j==4) {		  printf("_");		  j=0;		}		j++;		fprintf(stderr, "%02x", randcfg[rnum][i]);	      }	      fprintf(stderr, "\nconfigured rand %d: ", rnum);	      j=0;	      for (i = 0; i < EAPSIM_RAND_SIZE; i++) {		if(j==4) {		  printf("_");		  j=0;		}		j++;		fprintf(stderr, "%02x", randcfgvp[rnum]->strvalue[i]);	      }	      fprintf(stderr, "\n");	    }	    return 0;	  }	}	/*	 * now dig up the sres values from the response packet,	 * which were put there when we read things in.	 *	 * 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);	if(sres1 == NULL ||	   sres2 == NULL ||	   sres3 == 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]));	Kc1 = pairfind(rep->vps, ATTRIBUTE_EAP_SIM_KC1);	Kc2 = pairfind(rep->vps, ATTRIBUTE_EAP_SIM_KC2);	Kc3 = pairfind(rep->vps, ATTRIBUTE_EAP_SIM_KC3);	if(Kc1 == NULL ||	   Kc2 == NULL ||	   Kc3 == 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]));	/* all set, calculate keys */	eapsim_calculate_keys(&eapsim_mk);	if(debug_flag) {	  eapsim_dump_mk(&eapsim_mk);	}	/* verify the MAC, now that we have all the keys. */	if(eapsim_checkmac(req->vps, eapsim_mk.K_aut,			   eapsim_mk.nonce_mt, sizeof(eapsim_mk.nonce_mt),			   calcmac)) {		printf("MAC check succeed\n");	} else {		int i, j;		j=0;		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");		return 0;	}	/* form new response clear of any EAP stuff */	cleanresp(rep);	/* mark the subtype as being EAP-SIM/Response/Start */	newvp = paircreate(ATTRIBUTE_EAP_SIM_SUBTYPE, PW_TYPE_INTEGER);	newvp->lvalue = 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,			   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);	newvp->length = EAPSIM_SRES_SIZE*3;	pairreplace(&(rep->vps), newvp);

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -