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