1 /*
2  *  RadiusClass -- An C++-Library for radius authentication
3  *					and accounting.
4  *
5  *  Copyright (C) 2005 EWE TEL GmbH/Ralf Luebben <ralfluebben@gmx.de>
6  *
7  *  This program is free software; you can redistribute it and/or modify
8  *  it under the terms of the GNU General Public License as published by
9  *  the Free Software Foundation; either version 2 of the License, or
10  *  any later version.
11  *
12  *  This program is distributed in the hope that it will be useful,
13  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
14  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15  *  GNU General Public License for more details.
16  *
17  *  You should have received a copy of the GNU General Public License
18  *  along with this program; if not, write to the Free Software
19  *  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
20  */
21 
22 #include "RadiusPacket.h"
23 #define NEED_LIBGCRYPT_VERSION "1.2.0"
24 GCRY_THREAD_OPTION_PTHREAD_IMPL;
25 
26 using namespace std;
27 
28 /** The destructur frees the dynamic allocated memory of the buffers,
29  * closes the socket and clears the attribute multimap.
30  */
31 
~RadiusPacket()32 RadiusPacket::~RadiusPacket()
33 {
34 
35 	if (this->sendbuffer)
36 	{
37 		delete [] (this->sendbuffer);
38 	}
39 	if (this->recvbuffer)
40 	{
41 		delete [] (this->recvbuffer);
42 	}
43 
44 
45 	if (this->sock)
46 	{
47 		close (this->sock);
48 	}
49 	this->attribs.clear();
50 
51 }
52 
53 /** The constructur sets the code and generate random numbers
54  * for the identifier. The socket and the buffer length are set to 0, the pointer
55  * to the buffers is set to NULL. The length is set to 20 Bytes, this is the length without
56  * attributes.
57  * @param code The code of the packet.
58  */
RadiusPacket(Octet code)59 RadiusPacket::RadiusPacket(Octet code)
60 {
61 	this->code=code;
62 	this->getRandom(RADIUS_PACKET_IDENTIFIER_LEN,&(this->identifier));
63 	memset(this->authenticator,0,16);
64 	memset(this->req_authenticator,0,16);
65 	this->length=sizeof(Octet)*(RADIUS_PACKET_AUTHENTICATOR_LEN+4);
66 	this->sendbuffer=NULL;
67 	this->sendbufferlen=0;
68 	this->recvbuffer=NULL;
69 	this->recvbufferlen=0;
70 	this->sock=0;
71 
72 }
73 
74 /** The constructur generates random numbers
75  * for the identifier. The socket, the code and the buffer length are set to 0, the pointer
76  * to the buffers is set to NULL. The length is set to 20 Bytes, this is the length without
77  * attributes.
78  */
RadiusPacket(void)79 RadiusPacket::RadiusPacket(void)
80 {
81 	this->code=0;
82 	this->getRandom(RADIUS_PACKET_IDENTIFIER_LEN,&(this->identifier));
83 	memset(this->authenticator,0,16);
84 	memset(this->req_authenticator,0,16);
85 	this->length=sizeof(Octet)*(RADIUS_PACKET_AUTHENTICATOR_LEN+4);
86 	this->sendbuffer=NULL;
87 	this->sendbufferlen=0;
88 	this->recvbuffer=NULL;
89 	this->recvbufferlen=0;
90 	this->sock=0;
91 
92 }
93 
94 
95 /** Create a dump of the radius packet
96  */
dumpRadiusPacket(void)97 void RadiusPacket::dumpRadiusPacket(void)
98 {
99 
100 
101 	fprintf(stdout,"\n-- RadiusPacket -----------------\n");
102 	fprintf(stdout,"\tcode\t\t:\t%d\n",this->code);
103 	fprintf(stdout,"\tidentifier\t:\t%d\n",this->identifier);
104 	fprintf(stdout,"\tlength\t\t:\t%d\n",this->length);
105 	fprintf(stdout,"---------------------------------\n");
106 	for (multimap<Octet, RadiusAttribute>::iterator it = attribs.begin(); it != attribs.end(); ++it)
107 	{
108 		it->second.dumpRadiusAttrib();
109 	}
110 
111 	fprintf(stdout,"---------------------------------\n");
112 
113 }
114 
115 
116 /**	Returns the number of attributes in the given radiusPacket.
117  * @return An integer with the number of the attributes.
118  */
getRadiusAttribNumber(void)119 int RadiusPacket::getRadiusAttribNumber(void)
120 {
121 	int i=0;
122 	for (multimap<Octet, RadiusAttribute>::iterator it = attribs.begin(); it != attribs.end(); it++)
123 	{
124 
125 		i++;
126 	}
127 	return i;
128 }
129 
130 
131 /**	Links a radiusAttrib structure to a radiusPacket.
132  * @param ra The radius attribute to add.
133  *	@return Returns 0 if everything is ok,
134  * NO_VALUE_IN_ATTRIBUTE if the attribut value length is 0.
135  * Return -1 if attribute value length is 0.
136  */
addRadiusAttribute(RadiusAttribute * ra)137 int RadiusPacket::addRadiusAttribute(RadiusAttribute *ra)
138 {
139 	if (ra->getLength()<1)
140 	{
141 		cerr << "No value in the Attribute!\n";
142 		return NO_VALUE_IN_ATTRIBUTE;
143 	}
144 
145 	//insert the attribute in the list
146 	attribs.insert(pair<Octet,RadiusAttribute>((Octet)ra->getType(), *ra));
147 
148 	//add the length of the attribute to the the packet length
149 	this->length=this->length+ra->getLength();
150 	return 0;
151 }
152 
153 
154 /**	Formats a radiusPacket structure into a buffer that can be sent to a radius server via UDP.
155  *	The destination buffer is put into sendbuffer while its length is put into sendbufferlen.
156  *  @param sharedsecret The sharedsecret in plaintext.
157  *	@return Returns 0 if everything is ok, ALLOC_ERROR in case of error.
158  */
shapeRadiusPacket(const char * sharedsecret)159 int RadiusPacket::shapeRadiusPacket(const char * sharedsecret)
160 {
161 	int				i,j;
162 	Octet *			value;
163 	char * 			hashedpassword ;
164 
165 	//fill the authenticator with random data
166 	this->getRandom(RADIUS_PACKET_AUTHENTICATOR_LEN,this->authenticator);
167 
168 	//free the buffer if it is not empty, for ex. if is send again
169 	if(this->sendbuffer!=NULL)
170 	{
171 		delete [] this->sendbuffer;
172 	}
173 	//allocate memory for the packet
174 	if(!(this->sendbuffer=new Octet [this->length]))
175 	{
176 		return (ALLOC_ERROR);
177 	}
178 
179 	this->sendbufferlen=0;
180 
181 	//add the code and increment the length
182 	sendbuffer[(this->sendbufferlen)++]=this->code;
183 
184 	//add the identifier and increment the length
185 	sendbuffer[(this->sendbufferlen)++]=this->identifier;
186 	int nlength=htonl(this->length);
187 	//add the two octets for the length and increment the length twice
188 	sendbuffer[(this->sendbufferlen)++]=((char*)&(nlength))[2];
189 	sendbuffer[(this->sendbufferlen)++]=((char*)&(nlength))[3];
190 
191 	//add the authenticator to the buffer
192 	for(i=0;i<RADIUS_PACKET_AUTHENTICATOR_LEN;i++)
193 		sendbuffer[(this->sendbufferlen)++]=this->authenticator[i];
194 
195 	//add the attributes to the buffer
196 	for (multimap<Octet, RadiusAttribute>::iterator it = attribs.begin(); it != attribs.end(); it++)
197 	{
198 		//if the attribute is a password, build the hashedpassword
199 		if (it->second.getType()==ATTRIB_User_Password)
200 		{
201 
202 			this->sendbuffer[(this->sendbufferlen)++]=it->second.getType();
203 			this->sendbuffer[(this->sendbufferlen)++]=it->second.getLength();
204 
205 			if (it->second.getLength()-2<=16)
206 			{
207 				hashedpassword=new char[16];
208 				it->second.makePasswordHash((char *)it->second.getValue(),hashedpassword,sharedsecret,this->getAuthenticator());
209 				for(j=0;j<16;j++)
210 					this->sendbuffer[(this->sendbufferlen)++]=(Octet)hashedpassword[j];
211 
212 			}
213 			else
214 			{
215 
216 
217 				hashedpassword = new char [it->second.getLength()-2];
218 				it->second.makePasswordHash((char *)it->second.getValue(), hashedpassword, sharedsecret, this->getAuthenticator());
219 
220 				for(j=0;j<(it->second.getLength()-2);j++)
221 				{
222 					this->sendbuffer[(this->sendbufferlen)++]=(Octet)hashedpassword[j];
223 
224 				}
225 
226 
227 			}
228 			delete [] hashedpassword;
229 
230 		}
231 		//normal attributes
232 		else
233 		{
234 			this->sendbuffer[(this->sendbufferlen)++]=it->second.getType();
235 			this->sendbuffer[(this->sendbufferlen)++]=it->second.getLength();
236 			value=it->second.getValue();
237 			for(j=0;j<(it->second.getLength()-2);j++)
238 				this->sendbuffer[(this->sendbufferlen)++]=value[j];
239 		}
240 	}
241 	return 0;
242 }
243 
244 
245 /**	Dumps a shaped RADIUS packet previously created with shapeRadiusPacket.
246  */
dumpShapedRadiusPacket(void)247 void	RadiusPacket::dumpShapedRadiusPacket(void)
248 {
249 	int		i,j,attr,attrLen;
250 
251 	if(this->sendbuffer)
252 	{
253 		i=0;
254 		fprintf(stdout,"-- sendbuffer --");
255 		fprintf(stdout,"-- shapedRadiusPacket - header --");
256 
257 		fprintf(stdout,"\n\tcode\t\t:\t%02x",(this->sendbuffer)[i++]);
258 		fprintf(stdout,"\n\tidentifier\t:\t%02x",(this->sendbuffer)[i++]);
259 		Octet length1=(this->recvbuffer)[i++];
260 		Octet length2=(this->recvbuffer)[i++];
261 		fprintf(stdout,"\n\tlength\t\t:\t%02x %02x",length1,length2);
262 		fprintf(stdout,"\n\tauthenticator\t:\t");
263 		for(j=0;j<RADIUS_PACKET_AUTHENTICATOR_LEN;j++)
264 			fprintf(stdout,"%02x ",(this->sendbuffer)[i++]);
265 
266 		attr=0;
267 		do
268 		{
269 			fprintf(stdout,"\n-- attribute %02x ------------",attr);
270 			fprintf(stdout,"\n\ttype\t\t:\t%02x",(this->sendbuffer[i++]));
271 			fprintf(stdout,"\n\tlength\t\t:\t%02x",attrLen=(this->sendbuffer)[i++]);
272 			fprintf(stdout,"\n\tvalue\t\t:\t");
273 			for(j=0;j<attrLen-2;j++)
274 				fprintf(stdout,"%02x ",(this->sendbuffer)[i++]);
275 		}
276 		while(i<(this->sendbufferlen));
277 
278 		fprintf(stdout,"\n---------------------------------\n");
279 	}
280 	if(this->recvbuffer)
281 	{
282 		i=0;
283 		fprintf(stdout,"-- recvbuffer --");
284 		fprintf(stdout,"-- shapedRadiusPacket - header --");
285 		fprintf(stdout,"\n\tcode\t\t:\t%02x",(this->recvbuffer)[i++]);
286 		fprintf(stdout,"\n\tidentifier\t:\t%02x",(this->recvbuffer)[i++]);
287 		Octet length1=(this->recvbuffer)[i++];
288 		Octet length2=(this->recvbuffer)[i++];
289 		fprintf(stdout,"\n\tlength\t\t:\t%02x %02x",length1,length2);
290 		fprintf(stdout,"\n\tauthenticator\t:\t");
291 		for(j=0;j<RADIUS_PACKET_AUTHENTICATOR_LEN;j++)
292 			fprintf(stdout,"%02x ",(this->recvbuffer)[i++]);
293 
294 		attr=0;
295 		do
296 		{
297 			fprintf(stdout,"\n-- attribute %02x ------------",attr);
298 			fprintf(stdout,"\n\ttype\t\t:\t%02x",(this->recvbuffer[i++]));
299 			fprintf(stdout,"\n\tlength\t\t:\t%02x",attrLen=(this->recvbuffer)[i++]);
300 			fprintf(stdout,"\n\tvalue\t\t:\t");
301 			for(j=0;j<attrLen-2;j++)
302 				fprintf(stdout,"%02x ",(this->recvbuffer)[i++]);
303 		}
304 		while(i<(this->recvbufferlen));
305 
306 		fprintf(stdout,"\n---------------------------------\n");
307 	}
308 
309 }
310 
311 
312 /**	Formats a UDP-received buffer radiusPacket structure
313  *	@return A error number. Returns 0 is everything is ok, NO_BUFFER_TO_UNSHAPE
314  * or ALLOC_ERROR or TO_BIG_ATTRIBUTE_LENGTH in case of error.
315  */
unShapeRadiusPacket(void)316 int RadiusPacket::unShapeRadiusPacket(void)
317 {
318 	RadiusAttribute		*ra;
319 	int					pos,i;
320 	char				*value;
321 
322 	//if the buffer is empty
323 	if(!this->recvbuffer||this->recvbufferlen<=0)
324 	{
325 		return NO_BUFFER_TO_UNSHAPE;
326 	}
327 
328 
329 	//	RADIUS packet header decoding
330 	this->code=this->recvbuffer[0];
331 	//cerr << getTime() << "\n\nCODE: %s\n\n", this->code);
332 
333 	this->identifier=this->recvbuffer[1];
334 	memcpy(this->authenticator,recvbuffer+4,RADIUS_PACKET_AUTHENTICATOR_LEN);
335 
336 
337 	//	RADIUS packet attributes decoding
338 	pos=20;
339 
340 	while(pos<this->recvbufferlen)
341 	{
342 		//for every turn create a new attribute
343 		if(!(ra=new RadiusAttribute))
344 		{
345 			return ALLOC_ERROR;
346 		}
347 
348 		ra->setType(recvbuffer[pos++]);
349 		ra->setLength(recvbuffer[pos++]);
350 
351 		//the maximum attribute size can be
352 		//RADIUS_MAX_PACKET_LEN-20, 20: bytes of the
353 		//packet header.
354 		if(ra->getLength()>(RADIUS_MAX_PACKET_LEN-20))
355 		{
356 			return TO_BIG_ATTRIBUTE_LENGTH;
357 		}
358 		else
359 		{
360 
361 			value=new char [ra->getLength()-2];
362 			for(i=0;i<(ra->getLength()-2);i++)
363 			{
364 				value[i]=recvbuffer[pos++];
365 			}
366 			ra->setRecvValue(value);
367 			this->addRadiusAttribute(ra);
368 			this->length+=ra->getLength();
369 			delete [] value;
370 
371 		}
372 		//free the attribute, it was inserted in the list
373 		delete ra;
374 	}
375 	//set the right length
376 	this->length=this->recvbufferlen;
377 
378 
379 	return 0;
380 }
381 
382 /**	The method sends the packet to a radius server.
383  * @param server A iterator to a server.
384  * @return Returns the number of bytes successfully sent,
385  * SOCKET_ERROR or UNKNOWN_HOST in case of error.
386  */
radiusSend(list<RadiusServer>::iterator server)387 int RadiusPacket::radiusSend(list<RadiusServer>::iterator server)
388 {
389 
390 	int					socket2Radius;
391     struct hostent		*h;
392     struct sockaddr_in	cliAddr,remoteServAddr;
393 
394     //the packet is shaped here, the authenticator gets
395     //a new random value and then the buffer must be shaped again
396     //the password field depends on the authenticator field
397 	if(this->shapeRadiusPacket(server->getSharedSecret().c_str())!=0)
398 	{
399 		return SHAPE_ERROR;
400 	}
401 
402 	//new Authenticator with hash over the
403 	//packet and the shared secret, if the packet is a ACCOUNTING_REQUEST
404 	if (this->code==ACCOUNTING_REQUEST)
405 	{
406 		this->calcacctdigest(server->getSharedSecret().c_str());
407 
408 	}
409 
410 	//save the authenticator field for packet authentication on receiving a packet
411 	memcpy(this->authenticator, this->req_authenticator, 16);
412 
413 	//	Get server IP address (no check if input is IP address or DNS name
414     if(!(h=gethostbyname(server->getName().c_str())))
415 	{
416 		return UNKNOWN_HOST;
417 	}
418 
419     remoteServAddr.sin_family=h->h_addrtype;
420     memcpy((char*)&(remoteServAddr.sin_addr.s_addr),h->h_addr_list[0],h->h_length);
421 
422     //set the port, they are differnt for accounting and authentication
423     if (this->code==ACCOUNTING_REQUEST)
424 	{
425     	remoteServAddr.sin_port=htons(server->getAcctPort());
426 	}
427 	else
428 	{
429 		remoteServAddr.sin_port=htons(server->getAuthPort());
430 	}
431 
432     //	Socket creation
433     if((socket2Radius = socket(AF_INET, SOCK_DGRAM, 0))<0)
434 	{
435 		cerr <<  "Cannot open socket: "<< strerror(errno) <<"\n";
436 		return SOCKET_ERROR;
437 	}
438 
439 	//	Bind any port
440     cliAddr.sin_family=AF_INET;
441     cliAddr.sin_addr.s_addr=htonl(INADDR_ANY);
442     cliAddr.sin_port=htons(0);
443 
444 	//Bind the socket port,
445     if(::bind(socket2Radius,(struct sockaddr*)&cliAddr,sizeof(struct sockaddr))<0)
446 	{
447 		cerr << "Cannot bind port: " << strerror(errno) << "\n";
448 		socket2Radius=-1;
449 		return BIND_ERROR;
450 	}
451 
452 	//safe the socket for receiving packets
453 	this->sock=socket2Radius;
454 	//sent the buffer
455 	return sendto(socket2Radius,this->sendbuffer,this->sendbufferlen,0,(struct sockaddr*)&remoteServAddr,sizeof(struct sockaddr));
456 }
457 
458 
459 /**	Receives a packet from a radius server, and copies it into recvbuffer.
460  * If there is no response the packet is send again if the server->retry
461  * is bigger than 0. 1 means the packet is send
462  * one more time. If a packet is received the received data is write to the recvbuffer
463  * and the length is written to recvbufferlen.
464  * The attributes are cleared if a packet is received.
465  * @param serverlist : A list of radius server.
466  * @return Returns 0 if everything is ok, else ALLOC_ERROR,  UNKNOWN_HOST, WRONG_AUTHENTICATOR_IN_RECV_PACKET or NO_RESPONSE in case of error.
467  */
radiusReceive(list<RadiusServer> * serverlist)468 int RadiusPacket::radiusReceive(list<RadiusServer> *serverlist)
469 {
470 
471 	list<RadiusServer>::iterator server;
472 
473 	int 			result, retries=1; //for the first try retries=1, because the first packet was send in radiusSend()
474 	socklen_t		len;
475 	struct hostent	*h;
476 	fd_set  		set;
477 	struct timeval 	tv;
478 	struct sockaddr_in	remoteServAddr;
479 	int i_server=serverlist->size(),i=0;
480 	server=serverlist->begin();
481 
482 	while (i<i_server)
483 	{
484 		//	Get server IP address (no check if input is IP address or DNS name
485 	    if(!(h=gethostbyname(server->getName().c_str())))
486 		{
487 			return UNKNOWN_HOST;
488 		}
489 
490 	    remoteServAddr.sin_family=h->h_addrtype;
491 
492 	    remoteServAddr.sin_port=htons(server->getAuthPort());
493 
494 
495 	    //retry the sending if there is no result
496 	    while (retries<=server->getRetry())
497 	    {
498 		    // wait for the specified time for a response
499 			tv.tv_sec = server->getWait();
500 		    tv.tv_usec = 0;
501 		    FD_ZERO(&set);				// clear out the set
502 		    FD_SET(this->sock, &set);	// wait only for the RADIUS UDP socket
503 			result = select(FD_SETSIZE, &set, NULL, NULL, &tv);
504 
505 
506 			if (result>0)
507 			{
508 
509 				//clear the attributes
510 				attribs.clear();
511 
512 
513 				//allocate enough space for the buffer (RFC says maximum 4096=RADIUS_MAX_PACKET_LEN Bytes)
514 				if(!(this->recvbuffer=new Octet[RADIUS_MAX_PACKET_LEN]))
515 				{
516 					return (ALLOC_ERROR);
517 				}
518 				//set the buffer to 0
519 				memset(this->recvbuffer,0,RADIUS_MAX_PACKET_LEN);
520 				len=sizeof(struct sockaddr_in);
521 				this->recvbufferlen=recvfrom(this->sock,this->recvbuffer,RADIUS_MAX_PACKET_LEN,0,(struct sockaddr*)&remoteServAddr,&len);
522 				close(this->sock);
523 				this->sock=0;
524 				//unshape the packet
525 				if(this->unShapeRadiusPacket()!=0)
526 				{
527 					return UNSHAPE_ERROR;
528 				}
529 
530 				if (this->authenticateReceivedPacket(server->getSharedSecret().c_str())!=0)
531 				{
532 
533 					return WRONG_AUTHENTICATOR_IN_RECV_PACKET;
534 				}
535 				return 0;
536 			}
537 			else
538 			{
539 				close(this->sock);
540 				this->sock=0;
541 				//retry only if the retries are less than
542 				//the server retries
543 				if(retries <= server->getRetry())
544 				{
545 					this->radiusSend(server);
546 				}
547 			}
548 			retries++;
549 	    }
550 
551 		server++;
552 		i++;
553 		//set the retries=0, for the new server
554 		retries=0;
555 	}
556 
557 	return NO_RESPONSE;
558 
559 }
560 
561 /** Sets the authenticator field if the packet is
562  * a accounting request. It is a MD5 hash over the whole packet
563  * (the authenticator field itself is set to 0) and the shared
564  * secret.
565  * The authenticator is updated in the field this->authenticator
566  * and in the serialized packet.
567  * @param secret The shared secret of the server in plaintext.
568  */
calcacctdigest(const char * secret)569 void RadiusPacket::calcacctdigest(const char *secret)
570 {
571 	//Octet		digest[MD5_DIGEST_LENGTH];
572 	gcry_md_hd_t	context;
573 
574 	//Zero out the auth_vector in the received packet.
575 	//Then append the shared secret to the received packet,
576 	//and calculate the MD5 sum. This must be the same
577 	//as the original MD5 sum (packet->vector).
578 
579 	memset((this->sendbuffer+4), 0, 16);
580 	//build the hash
581 	if (!gcry_control (GCRYCTL_ANY_INITIALIZATION_P))
582 	{ /* No other library has already initialized libgcrypt. */
583 
584 	  gcry_control(GCRYCTL_SET_THREAD_CBS,&gcry_threads_pthread);
585 
586 	  if (!gcry_check_version (NEED_LIBGCRYPT_VERSION) )
587 	    {
588 		cerr << "libgcrypt is too old (need " << NEED_LIBGCRYPT_VERSION << ", have " << gcry_check_version (NULL) << ")\n";
589 	    }
590 	    /* Disable secure memory.  */
591           gcry_control (GCRYCTL_DISABLE_SECMEM, 0);
592 	  gcry_control (GCRYCTL_INITIALIZATION_FINISHED);
593 	}
594 	gcry_md_open (&context, GCRY_MD_MD5, 0);
595 	gcry_md_write(context, this->sendbuffer, this->length);
596 	gcry_md_write(context, secret, strlen(secret));
597 	//copy the digest to the paket
598 	memcpy(this->sendbuffer+4, gcry_md_read(context, GCRY_MD_MD5), 16);
599 	memcpy(this->authenticator, this->sendbuffer+4, 16);
600 	gcry_md_close(context);
601 }
602 
603 
604 /** Returns a pointer to the authenticator field.
605  * @return A pointer to the authenticator field.
606  */
getAuthenticator(void)607 char * RadiusPacket::getAuthenticator(void)
608 {
609 		return ((char *)this->authenticator);
610 }
611 
612 /** The getter method of the packet code.
613  * @return The code as an integer.
614  */
getCode(void)615 int	RadiusPacket::getCode(void)
616 {
617 	return ((int)this->code);
618 }
619 
620 /** Generates real random data with the device "/dev/random".
621  * Windows doesn'h have this device!. The method generates
622  * random data with the length len and copies it to the
623  * field num. In the num field must be enough space!
624  * @param len  The length of the random data.
625  * @param num  A pointer to an array where the random data is written to.
626  */
getRandom(int len,Octet * num)627 void RadiusPacket::getRandom(int len, Octet *num)
628 {
629 
630   int fd = open("/dev/urandom",O_RDONLY);
631   if (fd >= 0)
632   {
633   	read(fd, num, len);
634   }
635 
636   close(fd);
637 }
638 
639 /**The method finds attributes with the given type in the packet and returns iterator pair.
640  * This can be looped for the attributes.
641  * @param type The attribute type to find.
642  * @return A pair of the datatype pair<multimap<Octet,RadiusAttribute>::iterator,multimap<Octet,RadiusAttribute>::iterator>
643  */
findAttributes(int type)644 pair<multimap<Octet,RadiusAttribute>::iterator,multimap<Octet,RadiusAttribute>::iterator> RadiusPacket::findAttributes(int type)
645 {
646 	pair<multimap<Octet,RadiusAttribute>::iterator,multimap<Octet,RadiusAttribute>::iterator> p;
647 	p=attribs.equal_range((Octet) type);
648 	return p;
649 }
650 
651 /**The method checks the authenticator field from a received packet,
652  * so the radius server is authenticated against the client.
653  * @param secret The shared secret.
654  * @return A an integer, 0 if the authenticator field is ok, else WRONG_AUTHENTICATOR_IN_RECV_PACKET.
655  */
656 
authenticateReceivedPacket(const char * secret)657 int	RadiusPacket::authenticateReceivedPacket(const char *secret)
658 {
659 	gcry_md_hd_t	context;
660 
661 	Octet * cpy_recvpacket;
662 	//make a copy of the received packet
663 	cpy_recvpacket=new Octet [this->recvbufferlen];
664 
665 	memcpy(cpy_recvpacket, this->recvbuffer, this->recvbufferlen);
666 
667 	//copy the authenticator of the sent packet to the received packet
668 	memcpy(cpy_recvpacket+4, this->sendbuffer+4, 16);
669 
670 	//bulid the hash of the copy
671 	//build the hash
672 	if (!gcry_control (GCRYCTL_ANY_INITIALIZATION_P))
673 	{ /* No other library has already initialized libgcrypt. */
674 
675 	  gcry_control(GCRYCTL_SET_THREAD_CBS,&gcry_threads_pthread);
676 
677 	  if (!gcry_check_version (NEED_LIBGCRYPT_VERSION) )
678 	    {
679 		cerr << "libgcrypt is too old (need " << NEED_LIBGCRYPT_VERSION << ", have " << gcry_check_version (NULL) << ")\n";
680 	    }
681 	    /* Disable secure memory.  */
682           gcry_control (GCRYCTL_DISABLE_SECMEM, 0);
683 	  gcry_control (GCRYCTL_INITIALIZATION_FINISHED);
684 	}
685 	gcry_md_open (&context, GCRY_MD_MD5, 0);
686 	gcry_md_write(context, cpy_recvpacket, this->recvbufferlen);
687 	gcry_md_write(context, secret, strlen(secret));
688 
689 	delete[] cpy_recvpacket;
690 
691 	//compare the received and the built authenticator
692 	if (memcmp(this->recvbuffer+4, gcry_md_read(context, GCRY_MD_MD5), 16)!=0)
693 	{
694 		gcry_md_close(context);
695 		return WRONG_AUTHENTICATOR_IN_RECV_PACKET;
696 	}
697 	else
698 	{
699 		gcry_md_close(context);
700 		return 0;
701 	}
702 
703 }
704 
705 
706