Files
m241Neelima/components/ip_net2-6.9/ipike/src/ipike_radius.c
T
2026-07-30 11:19:44 +05:30

1961 lines
57 KiB
C

/*
******************************************************************************
* SOURCE FILE
*
* Document no: @(#) $Name: VXWORKS_ITER40_2019102207 $ $RCSfile: ipike_radius.c,v $ $Revision: 1.37.10.4 $
* $Source: /home/interpeak/CVSRoot/ipike/src/ipike_radius.c,v $
* $Author: zan $ $Date: 2013-08-07 12:43:42 $
* $State: Exp $ $Locker: $
*
* INTERPEAK_COPYRIGHT_STRING
* Design and implementation by Kenneth Jonsson <kenneth@interpeak.se>
******************************************************************************
*/
/*
****************************************************************************
* 1 DESCRIPTION
****************************************************************************
*/
/*
****************************************************************************
* 2 CONFIGURATION
****************************************************************************
*/
#include "ipike_config.h"
/*
****************************************************************************
* 3 INCLUDE FILES
****************************************************************************
*/
#ifdef IPIKE_USE_RADIUS
#include "ipike_h.h"
#include "ipike_radius.h"
#include "ipike_sadb.h"
#include <ipcom_clib.h>
#include <ipcom_syslog.h>
#include <ipcom_syslog.h>
#include <openssl/md5.h>
/*
****************************************************************************
* 4 EXTERN PROTOTYPES
****************************************************************************
*/
/*
****************************************************************************
* 5 DEFINES
****************************************************************************
*/
#define IPIKE_EAP_MAX_BUF 1400u
#define IPIKE_EAP_HEADER_LEN 5u
#define IPIKE_RADIUS_VENDOR_ID_MICROSOFT 311
#define IPIKE_RADIUS_VENDOR_ATTR_MS_MPPE_SEND_KEY 16
#define IPIKE_RADIUS_VENDOR_ATTR_MS_MPPE_RECV_KEY 17
/* Cisco LEAP */
#define IPIKE_RADIUS_VENDOR_ID_CISCO 9
#define IPIKE_RADIUS_VENDOR_ATTR_CISCO_SESSION_KEY 1
#define IPIKE_RADIUS_CISCO_SESSION_KEY_LEN 34
/*
****************************************************************************
* 6 TYPES
****************************************************************************
*/
typedef struct Ipike_radius_list_elem_st
{
Ipike_radius_server* v;
char* ike_id;
} Ipike_radius_list_elem;
typedef struct Ipike_radius_list_key_st
{
Ip_fd fd;
const char* ike_id;
} Ipike_radius_list_key;
typedef struct Ipike_radius_unique_id_struct
{
Ip_u8 radius_id;
Ip_u8* unique_id;
Ip_u32 unique_id_len;
} Ipike_radius_unique_id;
/*
****************************************************************************
* 7 LOCAL PROTOTYPES
****************************************************************************
*/
/*
*===========================================================================
* ipike_radius_create_server
*===========================================================================
* Description:
* Parameters:
* Returns:
*/
IP_STATIC Ipike_radius_server*
ipike_radius_create_server(
union Ip_sockaddr_union* server_addr,
union Ip_sockaddr_union* local_addr,
const char* shared_secret);
/*
*===========================================================================
* ipike_radius_free_server
*===========================================================================
* Description:
* Parameters:
* Returns:
*/
IP_STATIC void
ipike_radius_free_server(Ipike_radius_server* ctx);
/*
*===========================================================================
* ipike_radius_hash_key
*===========================================================================
* Description:
* Parameters:
* Returns:
*/
IP_STATIC unsigned
ipike_radius_hash_key(Ipike_radius_list_key* key);
/*
*===========================================================================
* ipike_radius_hash_obj
*===========================================================================
* Description:
* Parameters:
* Returns:
*/
IP_STATIC unsigned
ipike_radius_hash_obj(Ipike_radius_list_elem* elem);
/*
*===========================================================================
* ipike_radius_hash_cmp
*===========================================================================
* Description:
* Parameters:
* Returns:
*/
IP_STATIC Ip_bool
ipike_radius_hash_cmp(Ipike_radius_list_elem* elem, Ipike_radius_list_key* key);
/*
*===========================================================================
* ipike_radius_hash_add
*===========================================================================
* Description:
* Parameters:
* Returns:
*/
IP_STATIC Ipike_error
ipike_radius_hash_add(Ipike_radius_server* server, const char* ike_id);
/*
*===========================================================================
* ipike_sadb_hash_free
*===========================================================================
* Description:
* Parameters:
* Returns:
*/
IP_STATIC void
ipike_radius_hash_free(Ipike_radius_list_elem* elem, void* unused);
/*
*===========================================================================
* ipike_radius_hash_get
*===========================================================================
* Description:
* Parameters:
* Returns:
*/
IP_STATIC Ipike_radius_server*
ipike_radius_hash_get(Ip_fd fd, const char* ike_id);
/*
*===========================================================================
* ipike_radius_get_server
*===========================================================================
* Description:
* Parameters:
* Returns:
*/
IP_STATIC Ipike_radius_server*
ipike_radius_get_server(
const char* ike_id,
union Ip_sockaddr_union* server_addr,
union Ip_sockaddr_union* local_addr,
const char* shared_secret);
/*
*===========================================================================
* ipike_radius_receive_buffer_size
*===========================================================================
* Description:
* Parameters:
* Returns:
*/
IP_STATIC Ip_u32
ipike_radius_receive_buffer_size();
/*
*===========================================================================
* ipike_radius_alloc_receive_buffer
*===========================================================================
* Description:
* Parameters:
* Returns:
*/
IP_STATIC Ipradius_header*
ipike_radius_alloc_receive_buffer();
/*
*===========================================================================
* ipike_radius_free_receive_buffer
*===========================================================================
* Description:
* Parameters:
* Returns:
*/
IP_STATIC void
ipike_radius_free_receive_buffer(Ipradius_header** msg);
/*
*===========================================================================
* ipeap_sim_radius_get_vendor_attr
*===========================================================================
* Description:
* Parameters:
* Returns:
*/
IP_STATIC Ip_u8*
ipike_radius_get_vendor_attr(
Ipradius_header* msg,
Ip_u32 vendor,
Ip_u8 subtype,
Ip_u32* len);
/*
*===========================================================================
* ipike_radius_decrypt_microsoft_key
*===========================================================================
* Description:
* Parameters:
* Returns:
*/
IP_STATIC Ip_u8*
ipike_radius_decrypt_microsoft_key(
const Ip_u8* enc,
Ip_u32 enc_len,
const Ip_u8* req_authenticator,
const Ip_u8* secret,
Ip_u32 secret_len,
Ip_u32* reslen);
/*
*===========================================================================
* ipike_radius_get_cisco_session_key
*===========================================================================
* Description:
* Parameters:
* Returns:
*/
IP_STATIC Ipike_error
ipike_radius_get_cisco_session_key(
Ipike_radius_ctx* ctx,
Ip_u8** key,
Ip_u32* key_len);
/*
*===========================================================================
* ipike_radius_get_microsoft_key
*===========================================================================
* Description:
* Parameters:
* Returns:
*/
IP_STATIC Ipike_error
ipike_radius_get_microsoft_keys(
Ipike_radius_ctx* ctx,
Ip_u8** akey_recv,
Ip_u8** akey_send,
Ip_u32* key_len);
/*
*===========================================================================
* ipike_radius_event_callback
*===========================================================================
* Description:
* Parameters:
* Returns:
*/
IP_STATIC Ip_err
ipike_radius_event_callback(
int event,
Ipradius_request* request,
Ipradius_header* request_packet,
Ipradius_header* response_packet,
Ipradius_server* server);
/*
*===========================================================================
* ipike_radius_msg_add_eap
*===========================================================================
* Description:
* Parameters:
* Returns:
*/
IP_STATIC Ipike_error
ipike_radius_msg_add_eap(Ipeap_pkt_hdr* hdr, Ipradius_header* msg);
/*
*===========================================================================
* ipike_radius_msg_extract_eap
*===========================================================================
* Description:
* Parameters:
* Returns:
*/
IP_STATIC Ipike_error
ipike_radius_msg_extract_eap(
Ipradius_header* msg,
Ipike_value* eap);
/*
*===========================================================================
* ipike_radius_msg_add_cookies
*===========================================================================
* Description:
* Parameters:
* Returns:
*/
IP_STATIC Ipike_error
ipike_radius_msg_add_unique_id(
Ip_u8* unique_id,
Ip_u32 unique_id_len,
Ipradius_header* msg);
/*
*===========================================================================
* ipike_radius_msg_extract_unique_id
*===========================================================================
* Description:
* Parameters:
* Returns:
*/
IP_STATIC Ipike_error
ipike_radius_msg_extract_unique_id(
Ipradius_header* msg,
Ip_u8* unique_id,
Ip_u32* unique_id_len);
/*
*===========================================================================
* ipike_radius_send_message
*===========================================================================
* Description:
* Parameters:
* Returns:
*/
IP_STATIC Ip_err
ipike_radius_send_message(Ipike_radius_ctx* ctx, Ipradius_header* msg);
/*
*===========================================================================
* ipike_radius_receive_message
*===========================================================================
* Description:
* Parameters:
* Returns:
*/
IP_STATIC Ip_err
ipike_radius_receive_message(Ip_fd fd, Ipradius_header* msg);
/*
****************************************************************************
* 8 DATA
****************************************************************************
*/
const Ip_u8 EAP_START[] =
{
0x01,0x00,0x00,0x05,0x01
};
const Ip_u32 EAP_START_LEN = 5;
/*
****************************************************************************
* 9 LOCAL FUNCTIONS
****************************************************************************
*/
/*
*===========================================================================
* ipike_radius_create_server
*===========================================================================
*/
IP_STATIC Ipike_radius_server*
ipike_radius_create_server(
union Ip_sockaddr_union* server_addr,
union Ip_sockaddr_union* local_addr,
const char* shared_secret)
{
Ipike_radius_server* ctx = IP_NULL;
if ((server_addr == IP_NULL) ||
(local_addr == IP_NULL) ||
(shared_secret == IP_NULL))
{
IPCOM_LOG0(DEBUG2, "ipike_radius_get_server: Bad radius configuration");
return IP_NULL;
}
if (!ipike.radius.initialized)
(void)ipike_radius_startup();
ctx = (Ipike_radius_server*)ipcom_calloc(1, sizeof(*ctx));
if (ctx != IP_NULL)
{
IPCOM_LOG1(DEBUG2, "ipike_radius_get_server: Radius server: '%s'", ipike_addr_to_str(server_addr));
IPCOM_LOG1(DEBUG2, "ipike_radius_get_server: Local address: '%s'", ipike_addr_to_str(local_addr));
(void)ipike_addr_copy(&ctx->server.server_addr, server_addr);
(void)ipike_addr_copy(&ctx->local_addr, local_addr);
if (ipike_addr_get_port(&ctx->server.server_addr) == 0)
(void)ipike_addr_set_port(&ctx->server.server_addr, 1812);
ctx->fd = IP_INVALID_SOCKET;
ctx->server.index = 0;
ctx->server.pollnum = 0;
ctx->server.pollsec = 3;
if (ipcom_strlen(shared_secret) < sizeof(ctx->server.shared_secret))
{
ipcom_strcpy((char*)ctx->server.shared_secret, shared_secret);
ctx->server.shared_secret_len = (Ip_u32) ipcom_strlen((char*)ctx->server.shared_secret);
ctx->server.conf[0] = (unsigned long)-1;
(void)ipradius_server_add(&ctx->server);
#ifdef IPCOM_USE_INET
if (ctx->local_addr.sa.sa_family == IP_AF_INET)
{
ctx->fd = ipcom_socket(IP_AF_INET, IP_SOCK_DGRAM, 0);
if (ctx->fd != IP_INVALID_SOCKET)
{
if (ipcom_bind(ctx->fd,
(struct Ip_sockaddr *)&ctx->local_addr,
sizeof(ctx->local_addr)) < 0)
{
ipcom_socketclose(ctx->fd);
ctx->fd = IP_INVALID_SOCKET;
}
}
}
#endif
#ifdef IPCOM_USE_INET6
if (ctx->local_addr.sa.sa_family == IP_AF_INET6)
{
ctx->fd = ipcom_socket(IP_AF_INET6, IP_SOCK_DGRAM, 0);
if (ctx->fd != IP_INVALID_SOCKET)
{
if (ipcom_bind(ctx->fd,
(struct Ip_sockaddr *)&ctx->local_addr,
sizeof(ctx->local_addr)) < 0)
{
ipcom_socketclose(ctx->fd);
ctx->fd = IP_INVALID_SOCKET;
}
}
}
#endif
}
if ((ctx->fd != IP_INVALID_SOCKET) &&
(ipike_dispatch_add_radius_socket(ctx->fd) != IPIKE_SUCCESS))
{
ipcom_socketclose(ctx->fd);
ctx->fd = IP_INVALID_SOCKET;
}
if (ctx->fd == IP_INVALID_SOCKET)
{
IPCOM_LOG0(ERR, "ipike_radius_create: failed to connect radius server");
ipcom_free(ctx);
ctx = IP_NULL;
}
}
return ctx;
}
/*
*===========================================================================
* ipike_radius_free_server
*===========================================================================
*/
IP_STATIC void
ipike_radius_free_server(Ipike_radius_server* ctx)
{
if (ctx != IP_NULL)
{
(void)ipradius_server_remove(&ctx->server);
if (ctx->fd != IP_INVALID_SOCKET)
{
ipike_dispatch_remove_radius_socket(ctx->fd);
ipcom_socketclose(ctx->fd);
}
ipcom_free(ctx);
}
return;
}
/*
*===========================================================================
* ipike_radius_hash_key
*===========================================================================
*/
IP_STATIC unsigned
ipike_radius_hash_key(Ipike_radius_list_key* key)
{
unsigned val = 0;
if (key->ike_id != IP_NULL)
val = ipcom_hash_update(key->ike_id, (int)ipcom_strlen(key->ike_id), 0);
else
val = ipcom_hash_update(&key->fd, sizeof(key->fd), val);
return val;
}
/*
*===========================================================================
* ipike_radius_hash_obj
*===========================================================================
*/
IP_STATIC unsigned
ipike_radius_hash_obj(Ipike_radius_list_elem* elem)
{
Ipike_radius_list_key key;
key.fd = elem->v->fd;
key.ike_id = elem->ike_id;
return ipike_radius_hash_key(&key);
}
/*
*===========================================================================
* ipike_radius_hash_cmp
*===========================================================================
*/
IP_STATIC Ip_bool
ipike_radius_hash_cmp(
Ipike_radius_list_elem* elem,
Ipike_radius_list_key* key)
{
if (key->ike_id != IP_NULL)
{
if ((elem->ike_id != IP_NULL) &&
(!ipcom_strcmp(elem->ike_id, key->ike_id)))
return IP_TRUE;
}
else
{
if (key->fd == elem->v->fd)
return IP_TRUE;
}
return IP_FALSE;
}
/*
*===========================================================================
* ipike_radius_hash_add
*===========================================================================
*/
IP_STATIC Ipike_error
ipike_radius_hash_add(Ipike_radius_server* server, const char* ike_id)
{
Ipike_radius_list_elem* elem;
/* Create for serach by both ike_id and fd */
elem = ipcom_malloc(sizeof(*elem));
if (elem == IP_NULL)
{
IP_PANIC();
return IPIKE_OUT_OF_MEMORY;
}
elem->v = server;
elem->ike_id = ipcom_strdup(ike_id);
if (ipcom_hash_add(ipike.radius.hash_table, elem) != IPCOM_SUCCESS)
{
ipcom_free(elem);
return IPIKE_FAILED;
}
elem = ipcom_malloc(sizeof(*elem));
if (elem == IP_NULL)
{
IP_PANIC();
return IPIKE_OUT_OF_MEMORY;
}
elem->v = server;
elem->ike_id = IP_NULL;
if (ipcom_hash_add(ipike.radius.hash_table, elem) != IPCOM_SUCCESS)
{
ipcom_free(elem);
return IPIKE_FAILED;
}
return IPIKE_SUCCESS;
}
/*
*===========================================================================
* ipike_sadb_hash_free
*===========================================================================
*/
IP_STATIC void
ipike_radius_hash_free(Ipike_radius_list_elem* elem, void* unused)
{
(void) unused;
/* Always added twice, so only delete server when ike_id present */
if (elem->ike_id != IP_NULL)
{
ipike_radius_free_server(elem->v);
ipcom_free(elem->ike_id);
}
ipcom_free(elem);
return;
}
/*
*===========================================================================
* ipike_radius_hash_get
*===========================================================================
*/
IP_STATIC Ipike_radius_server*
ipike_radius_hash_get(Ip_fd fd, const char* ike_id)
{
Ipike_radius_list_key key;
Ipike_radius_list_elem* elem;
if (ipike.radius.hash_table != IP_NULL)
{
key.fd = fd;
key.ike_id = ike_id;
elem = (Ipike_radius_list_elem*)ipcom_hash_get(ipike.radius.hash_table, &key);
if (elem != IP_NULL)
return elem->v;
}
return IP_NULL;
}
/*
*===========================================================================
* ipike_radius_hash_unique_id_key
*===========================================================================
*/
IP_STATIC unsigned
ipike_radius_hash_unique_id_key(Ip_u8* key)
{
return ipcom_hash_update((void*)key, 1, 0);
}
/*
*===========================================================================
* ipike_radius_hash_unique_id_obj
*===========================================================================
* Description:
* Parameters:
* Returns:
*/
IP_STATIC unsigned
ipike_radius_hash_unique_id_obj(Ipike_radius_unique_id* elem)
{
return ipike_radius_hash_unique_id_key(&elem->radius_id);
}
/*
*===========================================================================
* ipike_radius_hash_unique_id_cmp
*===========================================================================
*/
IP_STATIC Ip_bool
ipike_radius_hash_unique_id_cmp(Ip_u8* key, Ipike_radius_unique_id* elem)
{
if (*key != elem->radius_id)
return IP_FALSE;
return IP_TRUE;
}
/*
*===========================================================================
* ipike_radius_hash_unique_id_get
*===========================================================================
*/
IP_STATIC Ip_bool
ipike_radius_hash_unique_id_get(Ip_u8 rad_id, Ip_u8* id, Ip_u32* id_len)
{
Ipike_radius_unique_id* elem;
if (ipike.radius.unique_id_table != IP_NULL)
{
elem = (Ipike_radius_unique_id*)ipcom_hash_get(ipike.radius.unique_id_table, &rad_id);
if (elem == IP_NULL)
{
return IP_FALSE;
}
else
{
if (IP_NULL != id)
{
if (*id_len < elem->unique_id_len)
return IP_FALSE;
*id_len = elem->unique_id_len;
ipcom_memcpy(id, elem->unique_id, *id_len);
}
return IP_TRUE;
}
}
return IP_FALSE;
}
/*
*===========================================================================
* ipike_radius_hash_unique_id_free
*===========================================================================
*/
IP_STATIC void
ipike_radius_hash_unique_id_free(Ipike_radius_unique_id* elem, void* unused)
{
(void) unused;
if (IP_NULL != elem)
{
if (IP_NULL != elem->unique_id)
ipcom_free(elem->unique_id);
ipcom_free(elem);
}
return;
}
/*
*===========================================================================
* ipike_radius_hash_unique_id_remove
*===========================================================================
*/
IP_STATIC void
ipike_radius_hash_unique_id_remove(Ip_u8 rad_id)
{
Ipike_radius_unique_id* elem = IP_NULL;
elem = (Ipike_radius_unique_id*)ipcom_hash_get(ipike.radius.unique_id_table, &rad_id);
if (elem != IP_NULL)
{
(void)ipcom_hash_remove(ipike.radius.unique_id_table, (void*)elem);
ipike_radius_hash_unique_id_free(elem, IP_NULL);
}
return;
}
/*
*===========================================================================
* ipike_radius_hash_unique_id_add
*===========================================================================
*/
IP_STATIC Ip_bool
ipike_radius_hash_unique_id_add(Ip_u8 rad_id, Ip_u8* id, Ip_u32 id_len)
{
Ip_bool success = IP_FALSE;
Ipike_radius_unique_id* elem = IP_NULL;
if (ipike_radius_hash_unique_id_get(rad_id, IP_NULL, IP_NULL))
{
IPCOM_LOG1(DEBUG, "ipike_radius_hash_unique_id_add: id %u already used, will be removed", rad_id);
ipike_radius_hash_unique_id_remove(rad_id);
}
elem = ipcom_malloc(sizeof(*elem));
if (IP_NULL != elem)
{
elem->unique_id = ipcom_malloc(id_len);
if (IP_NULL != elem->unique_id)
{
elem->radius_id = rad_id;
ipcom_memcpy(elem->unique_id, id, id_len);
elem->unique_id_len = id_len;
if (ipcom_hash_add(ipike.radius.unique_id_table, elem) == IPCOM_SUCCESS)
success = IP_TRUE;
}
if (!success)
ipike_radius_hash_unique_id_free(elem, IP_NULL);
}
return success;
}
/*
*===========================================================================
* ipike_radius_get_server
*===========================================================================
*/
IP_STATIC Ipike_radius_server*
ipike_radius_get_server(
const char* ike_id,
union Ip_sockaddr_union* server_addr,
union Ip_sockaddr_union* local_addr,
const char* shared_secret)
{
Ipike_radius_server* server;
/* Try to get radius server by ike_id and create at failure */
server = ipike_radius_hash_get(0, ike_id);
if (server == IP_NULL)
{
server = ipike_radius_create_server(server_addr, local_addr, shared_secret);
if (server != IP_NULL)
{
if (ipike_radius_hash_add(server, ike_id) != IPIKE_SUCCESS)
{
ipike_radius_free_server(server);
server = IP_NULL;
}
}
}
return server;
}
/*
*===========================================================================
* ipike_radius_receive_buffer_size
*===========================================================================
*/
IP_STATIC Ip_u32
ipike_radius_receive_buffer_size()
{
return (Ip_u32)(IPIKE_EAP_MAX_BUF);
}
/*
*===========================================================================
* ipike_radius_alloc_receive_buffer
*===========================================================================
*/
IP_STATIC Ipradius_header*
ipike_radius_alloc_receive_buffer()
{
return (Ipradius_header*)ipcom_calloc(1, ipike_radius_receive_buffer_size());
}
/*
*===========================================================================
* ipike_radius_free_receive_buffer
*===========================================================================
*/
IP_STATIC void
ipike_radius_free_receive_buffer(Ipradius_header** msg)
{
if ((msg != IP_NULL) && (*msg != IP_NULL))
{
ipcom_free(*msg);
*msg = IP_NULL;
}
return;
}
/*
*===========================================================================
* ipeap_sim_radius_get_vendor_attr
*===========================================================================
*/
IP_STATIC Ip_u8*
ipike_radius_get_vendor_attr(
Ipradius_header* msg,
Ip_u32 vendor,
Ip_u8 subtype,
Ip_u32* len)
{
Ip_u8* attr = IP_NULL;
Ip_u8* data = IP_NULL;
while ((attr = ipradius_attr_get_next(msg, attr)) != IP_NULL)
{
if ((attr[0] == IPRADIUS_ATTR_Vendor_Specific) &&
(attr[1] > 7) &&
(attr[2] == ((vendor >> 24) & 0xff)) &&
(attr[3] == ((vendor >> 16) & 0xff)) &&
(attr[4] == ((vendor >> 8) & 0xff)) &&
(attr[5] == ((vendor) & 0xff)) &&
(attr[6] == subtype))
{
*len = (Ip_u32) (attr[7] - 2);
data = &attr[8];
break;
}
}
return data;
}
/*
*===========================================================================
* ipike_radius_decrypt_microsoft_key
*===========================================================================
*/
IP_STATIC Ip_u8*
ipike_radius_decrypt_microsoft_key(
const Ip_u8* enc,
Ip_u32 enc_len,
const Ip_u8* req_authenticator,
const Ip_u8* secret,
Ip_u32 secret_len,
Ip_u32* reslen)
{
const Ip_u8* salt = IP_NULL;
Ip_u8* plain = IP_NULL;
Ip_bool first = IP_TRUE;
Ip_size_t left = 0;
const Ip_u8* pos = IP_NULL;
Ip_u8* p = IP_NULL;
MD5_CTX ctx = {0};
Ip_u8 digest[16] = {0};
Ip_u32 i = 0;
Ip_u8* res = IP_NULL;
/* For detail information read RFC 2548 */
/* First two bytes is salt value */
salt = enc;
pos = enc + 2;
left = enc_len - 2;
/* Should be multiple of 16 bytes */
if ((left % 16) != 0)
return IP_NULL;
plain = ipcom_malloc(left);
if (plain == IP_NULL)
return IP_NULL;
p = plain;
while (left > 0)
{
MD5_Init(&ctx);
MD5_Update(&ctx, secret, secret_len);
/* round 0: MD5(Secret | Authenticator | Salt)
* round >0: MD5(Secret | <encrypted data>(round - 1)) */
if (first)
{
MD5_Update(&ctx, req_authenticator, 16);
MD5_Update(&ctx, salt, 2);
first = IP_FALSE;
}
else
{
MD5_Update(&ctx, pos - sizeof(digest), sizeof(digest));
}
MD5_Final(digest, &ctx);
/* xor with digest to decrypt */
for (i = 0; i < sizeof(digest); i++)
p[i] = (Ip_u8)(pos[i] ^ digest[i]);
p += sizeof(digest);
pos += sizeof(digest);
left -= sizeof(digest);
}
if (plain[0] >= (enc_len - 2))
{
ipcom_free(plain);
return IP_NULL;
}
res = ipcom_malloc(plain[0]);
if (res == IP_NULL)
{
ipcom_free(plain);
return IP_NULL;
}
ipcom_memcpy(res, plain + 1, plain[0]);
if (reslen != IP_NULL)
*reslen = plain[0];
ipcom_free(plain);
return res;
}
/*
*===========================================================================
* ipike_radius_get_microsoft_key
*===========================================================================
*/
IP_STATIC Ipike_error
ipike_radius_get_cisco_session_key(
Ipike_radius_ctx* ctx,
Ip_u8** key,
Ip_u32* key_len)
{
Ip_u8 *enc_key = IP_NULL;
Ip_u32 enc_key_len = 0;
Ipike_error err = IPCOM_ERR_FAILED;
ip_assert(key);
/* Try to get cisco session key */
enc_key = ipike_radius_get_vendor_attr( ctx->last_msg,
IPIKE_RADIUS_VENDOR_ID_CISCO,
IPIKE_RADIUS_VENDOR_ATTR_CISCO_SESSION_KEY,
&enc_key_len);
/* Got session key? */
if ( enc_key )
{
const char *enc_key_prefix = "leap:session-key=";
Ip_u32 enc_key_prefix_len = (Ip_u32) strlen(enc_key_prefix);
/* Make sure we have correct prefix */
if ( enc_key_prefix_len > enc_key_len ||
ipcom_strncmp(enc_key_prefix, (const char *)enc_key, enc_key_prefix_len) != 0 )
{
IPCOM_LOG1(ERR,
"ipike_radius_get_cisco_session_key() :: expected '%s' as key prefix",
enc_key_prefix);
return IPCOM_ERR_FAILED;
}
/* Validate session key length */
if ( enc_key_len - enc_key_prefix_len != IPIKE_RADIUS_CISCO_SESSION_KEY_LEN )
{
IPCOM_LOG1(ERR,
"ipike_radius_get_cisco_session_key() :: bad key length '%u'",
enc_key_len - enc_key_prefix_len);
}
/* Using the same algorithm as mschap */
*key = ipike_radius_decrypt_microsoft_key(enc_key + enc_key_prefix_len,
enc_key_len - enc_key_prefix_len,
ctx->last_msg->auth,
ctx->server->server.shared_secret,
ctx->server->server.shared_secret_len,
key_len);
/* Decrypt Successful?*/
if ( *key )
{
(void)ipike_print_memory(IPCOM_LOG_DEBUG2,
"ipike_radius_get_cisco_session_key() ::"\
" Cisco EAP session key:\n",
*key, *key_len);
err = IPIKE_SUCCESS;
}
else
{
IPCOM_LOG0(ERR,
"ipike_radius_get_cisco_session_key() ::"\
" failed to decrypt cisco session key");
}
}
return err;
}
/*
*===========================================================================
* ipike_radius_get_microsoft_key
*===========================================================================
*/
IP_STATIC Ipike_error
ipike_radius_get_microsoft_keys(
Ipike_radius_ctx* ctx,
Ip_u8** akey_recv,
Ip_u8** akey_send,
Ip_u32* key_len)
{
Ip_err err = IPCOM_ERR_FAILED;
Ip_u8* key_send = IP_NULL;
Ip_u32 key_send_len = 0;
Ip_u8* key_recv = IP_NULL;
Ip_u32 key_recv_len = 0;
*akey_recv = IP_NULL;
*akey_send = IP_NULL;
*key_len = 0;
/* key_recv and key_send will be pointers to existing buffers */
key_recv = ipike_radius_get_vendor_attr(
ctx->last_msg,
IPIKE_RADIUS_VENDOR_ID_MICROSOFT,
IPIKE_RADIUS_VENDOR_ATTR_MS_MPPE_RECV_KEY,
&key_recv_len);
key_send = ipike_radius_get_vendor_attr(
ctx->last_msg,
IPIKE_RADIUS_VENDOR_ID_MICROSOFT,
IPIKE_RADIUS_VENDOR_ATTR_MS_MPPE_SEND_KEY,
&key_send_len);
if ((key_recv != IP_NULL) && (key_send != IP_NULL))
{
/* key_recv and key_send will be allocated */
key_recv = ipike_radius_decrypt_microsoft_key(
key_recv,
key_recv_len,
ctx->last_msg->auth,
ctx->server->server.shared_secret,
ctx->server->server.shared_secret_len,
&key_recv_len);
key_send = ipike_radius_decrypt_microsoft_key(
key_send,
key_send_len,
ctx->last_msg->auth,
ctx->server->server.shared_secret,
ctx->server->server.shared_secret_len,
&key_send_len);
if ((key_send == IP_NULL) ||
(key_recv == IP_NULL) ||
(key_recv_len != key_send_len))
{
ipcom_free(key_recv);
ipcom_free(key_send);
}
else
{
*akey_recv = key_recv;
*akey_send = key_send;
*key_len = key_recv_len;
err = IPIKE_SUCCESS;
}
}
return err;
}
/*
*===========================================================================
* ipike_radius_event_callback
*===========================================================================
*/
IP_STATIC Ip_err
ipike_radius_event_callback(
int event,
Ipradius_request* request,
Ipradius_header* request_packet,
Ipradius_header* response_packet,
Ipradius_server* server)
{
(void)request;
(void)request_packet;
(void)response_packet;
(void)server;
switch(event)
{
case IPRADIUS_EVENT_ACCESS_ACCEPT:
break;
case IPRADIUS_EVENT_ACCESS_REJECT:
break;
case IPRADIUS_EVENT_ACCESS_CHALLENGE:
break;
case IPRADIUS_EVENT_ACCESS_TIMEOUT:
break;
case IPRADIUS_EVENT_ACCESS_CANCELLED:
break;
case IPRADIUS_EVENT_ACCOUNTING_RESPONSE:
break;
case IPRADIUS_EVENT_ACCOUNTING_REQUEST:
break;
case IPRADIUS_EVENT_ACCOUNTING_TIMEOUT:
break;
case IPRADIUS_EVENT_ACCOUNTING_CANCELLED:
break;
default:
IP_PANIC();
break;
}
return IPCOM_SUCCESS;
}
/*
*===========================================================================
* ipike_radius_msg_add_eap
*===========================================================================
*/
IP_STATIC Ipike_error
ipike_radius_msg_add_eap(Ipeap_pkt_hdr* hdr, Ipradius_header* msg)
{
Ip_u8* data = IP_NULL;
Ip_size_t len = 0;
Ip_size_t n = 0;
data = (Ip_u8*)hdr;
len = ip_htons(hdr->len);
while (len > 0)
{
/* Maximum 255 bytes for each attribute, so split to multiple */
if (len > 253)
n = 253;
else
n = len;
if (ipradius_attr_add_array(msg,
IPRADIUS_ATTR_EAP_Message,
data,
(Ip_u8)n))
return IPIKE_FAILED;
data += n;
len -= n;
}
return IPIKE_SUCCESS;
}
/*
*===========================================================================
* ipike_radius_msg_extract_eap
*===========================================================================
*/
IP_STATIC Ipike_error
ipike_radius_msg_extract_eap(
Ipradius_header* msg,
Ipike_value* eap)
{
Ip_u8* attr = IP_NULL;
ipcom_free(eap->value);
eap->value = IP_NULL;
eap->len = 0;
while ((attr = ipradius_attr_get_next(msg, attr)) != IP_NULL)
{
if (attr[0] == IPRADIUS_ATTR_EAP_Message)
{
eap->value = ipcom_realloc(eap->value, eap->len + attr[1]);
if (eap->value != IP_NULL)
{
ipcom_memcpy(eap->value + eap->len,
&attr[2],
(Ip_size_t) (attr[1]-2));
eap->len += (Ip_size_t) attr[1] - 2;
}
}
}
return (eap->value != IP_NULL) ? IPIKE_SUCCESS : IPIKE_FAILED;
}
/*
*===========================================================================
* ipike_radius_msg_add_cookies
*===========================================================================
*/
IP_STATIC Ipike_error
ipike_radius_msg_add_unique_id(
Ip_u8* unique_id,
Ip_u32 unique_id_len,
Ipradius_header* msg)
{
char* state;
state = ipcom_malloc(2*unique_id_len+1);
if (state == IP_NULL)
return IPIKE_FAILED;
ipike_bin2hex(unique_id, unique_id_len, state);
if (ipradius_attr_add_array(msg,
IPRADIUS_ATTR_Proxy_State,
(Ip_u8*)state,
(Ip_u8)ipcom_strlen(state)) != IPCOM_SUCCESS)
{
ipcom_free(state);
return IPIKE_FAILED;
}
ipcom_free(state);
return IPIKE_SUCCESS;
}
/*
*===========================================================================
* ipike_radius_msg_extract_unique_id
*===========================================================================
*/
IP_STATIC Ipike_error
ipike_radius_msg_extract_unique_id(
Ipradius_header* msg,
Ip_u8* unique_id,
Ip_u32* unique_id_len)
{
Ip_u8* attr = IP_NULL;
Ip_u8* p = IP_NULL;
Ip_size_t n = 0;
while ((attr = ipradius_attr_get_next(msg, attr)) != IP_NULL)
{
if (attr[0] == IPRADIUS_ATTR_Proxy_State)
{
if (attr[1] > ((2 * (*unique_id_len)) + 2))
return IPIKE_FAILED;
n = (Ip_size_t) (attr[1] - 2);
p = ipike_hex2bin((char*)&attr[2], &n);
if (p != IP_NULL)
{
*unique_id_len = (Ip_u32) n;
ipcom_memcpy(unique_id, p, n);
ipcom_free(p);
}
break;
}
}
return ((p != IP_NULL) ? IPIKE_SUCCESS : IPIKE_FAILED);
}
/*
*===========================================================================
* ipike_radius_send_message
*===========================================================================
*/
IP_STATIC Ip_err
ipike_radius_send_message(Ipike_radius_ctx* ctx, Ipradius_header* msg)
{
Ipradius_request request = {0};
Ip_u8 errattr = 0;
request.unique = ctx->server->id;
request.pwd_type = IPRADIUS_No_Password;
/* Set RADIUS socket descriptor and event callback. */
#ifdef IPCOM_USE_INET
if (ctx->server->local_addr.sa.sa_family == IP_AF_INET)
request.fd = ctx->server->fd;
else
request.fd = IP_INVALID_SOCKET;
#endif
#ifdef IPCOM_USE_INET6
if (ctx->server->local_addr.sa.sa_family == IP_AF_INET6)
request.fd6 = ctx->server->fd;
else
request.fd6 = IP_INVALID_SOCKET;
#endif
request.event_callback = ipike_radius_event_callback;
request.num_servers = 1;
ipcom_memcpy(&request.serv_list[0].server_addr,
&ctx->server->server.server_addr,
sizeof(union Ip_sockaddr_union));
request.serv_list[0].server_type = ctx->server->server.server_type;
request.serv_list[0].pollnum = ctx->server->server.pollnum;
request.serv_list[0].pollsec = ctx->server->server.pollsec;
return ipradius_access_request(msg, &request, &errattr);
}
/*
*===========================================================================
* ipike_radius_receive_message
*===========================================================================
*/
IP_STATIC Ip_err
ipike_radius_receive_message(
Ip_fd fd,
Ipradius_header* msg)
{
Ip_s32 maxfd;
Ip_s32 num;
Ip_fd_set read_set;
struct Ip_timeval tmo;
Ip_err retval;
Ip_ssize_t length;
Ip_socklen_t addr_len;
union Ip_sockaddr_union addr;
Ip_u32 count = 0;
again:
IP_FD_ZERO(&read_set);
IP_FD_SET(fd, &read_set);
maxfd = (Ip_s32)fd;
tmo.tv_usec = 0;
tmo.tv_sec = 3;
num = ipcom_socketselect(maxfd + 1, &read_set, IP_NULL, IP_NULL, &tmo);
if (num < 0)
{
IPCOM_LOG0(ERR, "ipike_radius_receive_message - out of memory");
return IPIKE_FAILED;
}
else if (num == 0)
{
IPCOM_LOG0(ERR, "ipike_radius_receive_message - no server reply");
return IPIKE_FAILED;
}
/* Got a packet waiting... */
else if (num == 1)
{
ipcom_memset(&addr, 0, sizeof(addr));
addr_len = sizeof(addr);
/* Read the packet. */
length = ipcom_recvfrom(fd,
msg,
ipike_radius_receive_buffer_size(),
0,
&addr.sa,
&addr_len);
if (length <= 0)
{
IPCOM_LOG1(ERR, "ipike_radius_receive_message - recv failed (%d)", ipcom_errno);
if (count++ < 10)
goto again;
return IPIKE_FAILED;
}
if (ip_ntohs(msg->length)>length || ip_ntohs(msg->length)<=0)
{
IPCOM_LOG0(ERR, "ipike_radius_receive_message - invalid packet");
return IPIKE_FAILED;
}
/* Pass packet to RADIUS for input parsing. */
/* Ipradius_header is followed by data payload, accessing data seems over access */
/* coverity[tainted_data] */
retval = ipradius_read(msg, (Ip_size_t) length, &addr.sa);
if (retval != IPCOM_SUCCESS)
{
IPCOM_LOG0(ERR, "ipike_radius_receive_message - input parsing failed");
if (count++ < 10)
goto again;
return IPIKE_FAILED;
}
/* Valid packet, return. */
return 0;
}
IP_PANIC();
IPCOM_LOG1(ERR, "ipike_radius_receive_message - internal error, num = %d", num);
return IPIKE_FAILED;
}
/*
****************************************************************************
* 10 PUBLIC FUNCTIONS
****************************************************************************
*/
/*
*===========================================================================
* ipike_radius_create
*===========================================================================
*/
IP_GLOBAL Ipike_radius_ctx*
ipike_radius_create(
const char* ike_id,
union Ip_sockaddr_union* server_addr,
union Ip_sockaddr_union* local_addr,
const char* shared_secret)
{
Ipike_radius_ctx* ctx = IP_NULL;
ctx = (Ipike_radius_ctx*)ipcom_calloc(1, sizeof(*ctx));
if (ctx != IP_NULL)
{
ctx->server = ipike_radius_get_server(ike_id,
server_addr,
local_addr,
shared_secret);
if (ctx->server == IP_NULL)
{
ipcom_free(ctx);
ctx = IP_NULL;
}
}
return ctx;
}
/*
*===========================================================================
* ipike_radius_free
*===========================================================================
*/
IP_GLOBAL void
ipike_radius_free(Ipike_radius_ctx* ctx)
{
if (ctx != IP_NULL)
{
if (ctx->last_msg != IP_NULL)
ipike_radius_free_receive_buffer(&ctx->last_msg);
ipcom_free(ctx);
}
return;
}
/*
*===========================================================================
* ipike_radius_send
*===========================================================================
*/
IP_GLOBAL Ipike_error
ipike_radius_send(
Ipike_radius_ctx* ctx,
Ip_u8* unique_id,
Ip_u32 unique_id_len,
Ipeap_pkt* pkt)
{
Ip_err err = IPIKE_FAILED;
Ipeap_pkt_hdr* hdr = IP_NULL;
Ipradius_header* msg = IP_NULL;
Ip_u8* data = IP_NULL;
Ip_u8 len = 0;
msg = ipradius_access_request_pkt_malloc();
if (msg == IP_NULL)
{
IP_PANIC();
return IPIKE_OUT_OF_MEMORY;
}
msg->id = ++ctx->server->id;
msg->code = IPRADIUS_CODE_Access_Request;
hdr = (Ipeap_pkt_hdr*)&pkt->data[pkt->start];
data = (Ip_u8*)hdr + sizeof(*hdr);
if (ctx->identity[0] != 0)
if (ipradius_attr_add_array(msg,
IPRADIUS_ATTR_User_Name,
(Ip_u8*)ctx->identity,
(Ip_u8)ipcom_strlen(ctx->identity)))
goto cleanup;
/* Add unique id so we will find the correct exchange at response */
if (ipike_radius_msg_add_unique_id(unique_id,
unique_id_len,
msg) != IPIKE_SUCCESS)
goto cleanup;
/* Copy state from last response */
if (ctx->last_msg != IP_NULL)
if ((data = ipradius_attr_get_array(ctx->last_msg,
IPRADIUS_ATTR_State,
&len)) != IP_NULL)
if (ipradius_attr_add_array(msg,
IPRADIUS_ATTR_State,
data,
(Ip_u8)(len-2)))
goto cleanup;
if (ipike_radius_msg_add_eap(hdr, msg))
goto cleanup;
if (ipike_radius_send_message(ctx, msg))
goto cleanup;
/* Store unique id, so we may handle if state isn't returned */
(void)ipike_radius_hash_unique_id_add(msg->id, unique_id, unique_id_len);
msg = IP_NULL;
err = IPCOM_SUCCESS;
cleanup:
if (msg != IP_NULL)
(void)ipradius_access_request_pkt_free(msg);
return err;
}
/*
*===========================================================================
* ipike_radius_receive
*===========================================================================
*/
IP_GLOBAL Ipike_error
ipike_radius_receive(
Ip_fd fd,
Ipike_value* eap,
Ip_u8* unique_id,
Ip_u32* unique_id_len,
Ipradius_header** last_msg)
{
Ipike_error err = IPIKE_FAILED;
Ipradius_header* msg = IP_NULL;
Ipike_radius_server* ctx = IP_NULL;
if ((ctx = ipike_radius_hash_get(fd, IP_NULL)) == IP_NULL)
{
IPCOM_LOG0(ERR, "ipike_radius_receive - unknown radius server");
goto cleanup;
}
msg = ipike_radius_alloc_receive_buffer();
if (msg==IP_NULL)
{
IPCOM_LOG0(ERR, "ipike_radius_receive - mem alloc failed");
goto cleanup;
}
/* Ipradius_header is followed by data payload, accessing data seems over access */
/* coverity[tainted_data] */
if (ipike_radius_receive_message(fd, msg))
{
IPCOM_LOG0(ERR, "ipike_radius_receive - receive failed");
goto cleanup;
}
if (msg->code != IPRADIUS_CODE_Access_Accept &&
msg->code != IPRADIUS_CODE_Access_Reject &&
msg->code != IPRADIUS_CODE_Access_Challenge)
{
IPCOM_LOG0(ERR, "ipike_radius_receive - unknown message");
goto cleanup;
}
IPCOM_LOG0(DEBUG2, "ipike_radius_receive - message received");
/* Ipradius_header is followed by data payload, accessing data seems over access */
/* coverity[tainted_data] */
if (ipradius_attr_verify_message_auth(msg,
ctx->server.shared_secret,
ctx->server.shared_secret_len))
{
IPCOM_LOG0(ERR, "ipike_radius_receive - failed to verify message authenticator");
goto cleanup;
}
/* Ipradius_header is followed by data payload, accessing data seems over access */
/* coverity[tainted_data] */
if (ipike_radius_msg_extract_eap(msg, eap) != IPIKE_SUCCESS)
{
IPCOM_LOG0(ERR, "ipike_radius_receive - failed to extract eap message");
goto cleanup;
}
if (ipike_radius_msg_extract_unique_id(msg,
unique_id,
unique_id_len) != IPIKE_SUCCESS)
{
if (!ipike_radius_hash_unique_id_get(msg->id, unique_id, unique_id_len))
{
IPCOM_LOG0(ERR, "ipike_radius_receive - failed to extract cookies");
goto cleanup;
}
}
err = IPIKE_SUCCESS;
*last_msg = msg;
msg = IP_NULL;
cleanup:
if (msg != IP_NULL)
ipike_radius_free_receive_buffer(&msg);
return err;
}
/*
*===========================================================================
* ipike_radius_process_pkt
*===========================================================================
*/
IP_GLOBAL Ipike_error
ipike_radius_process_pkt(
Ipike_radius_ctx* ctx,
Ip_u8* unique_id,
Ip_u32 unique_id_len,
Ipeap_pkt* pkt_in,
Ipeap_pkt* pkt_out)
{
Ipike_error err = IPEAP_FAILURE;
Ipeap_pkt_hdr* hdr = IP_NULL;
Ip_u8* data = IP_NULL;
Ip_u32 len = 0;
if ((pkt_in->end - pkt_in->start) == 0)
{
if (pkt_out->max_len >= (int)EAP_START_LEN)
{
pkt_out->end = pkt_out->start + (int)EAP_START_LEN;
ipcom_memcpy(pkt_out->data+ pkt_out->start, EAP_START, EAP_START_LEN);
err = IPEAP_PENDING_SEND_OUT_PKT;
}
}
else
{
/* Get identity from packet */
hdr = (Ipeap_pkt_hdr*)&pkt_in->data[pkt_in->start];
data = (Ip_u8*)hdr + IPIKE_EAP_HEADER_LEN;
if ((hdr->code == IPEAP_PKT_RESPONSE) &&
(ip_htons(hdr->len) > IPIKE_EAP_HEADER_LEN) &&
(hdr->type == IPEAP_TYPE_IDENTITY))
{
len = ip_htons(hdr->len) - IPIKE_EAP_HEADER_LEN;
if (len < sizeof(ctx->identity))
{
ipcom_memcpy(ctx->identity, data, len);
ctx->identity[len] = 0;
IPCOM_LOG1(DEBUG2, "Identity: '%s'", ctx->identity);
}
}
/* Send to radius server */
if (ipike_radius_send(ctx,
unique_id,
unique_id_len,
pkt_in) != IPCOM_SUCCESS)
{
IPCOM_LOG0(ERR, "ipike_radius_process_pkt: Failed to send to radius server");
}
else
{
err = IPCOM_SUCCESS;
}
}
return err;
}
/*
*===========================================================================
* ipike_radius_process_dispatcher_event
*===========================================================================
*/
IP_GLOBAL void
ipike_radius_process_dispatcher_event(Ip_fd fd)
{
Ip_u8 unique_id[74] = {0};
Ip_u32 unique_id_len = sizeof(unique_id);
Ipike_isakmp_exchange* ie = IP_NULL;
Ipike_value eap = {0};
Ipradius_header* msg = IP_NULL;
if (ipike_radius_receive(
fd,
&eap,
unique_id,
&unique_id_len,
&msg) != IPIKE_SUCCESS)
{
IPCOM_LOG0(ERR, "ipike_radius_process_dispatcher_event: Failed to get radius message");
ipike_dispatch_remove_radius_socket(fd);
}
else if ((ie = ipike_isakmp_get_exchange_from_unique_id(
unique_id,
unique_id_len)) == IP_NULL)
{
ipike_radius_free_receive_buffer(&msg);
IPCOM_LOG0(ERR, "ipike_radius_process_dispatcher_event: Failed to get exchange");
}
else
{
/* Set last radius buffer, so it may be used later */
ipike_radius_free_receive_buffer(&ie->ike_sa->v2.radius_ctx->last_msg);
ie->ike_sa->v2.radius_ctx->last_msg = msg;
/* Set EAP message */
ipcom_free(ie->ike_sa->v2.eap.value);
ie->ike_sa->v2.eap.value = eap.value;
ie->ike_sa->v2.eap.len = eap.len;
/* Continue processing of exchange */
ipike_isakmp_process_message_continue(ie);
}
return;
}
/*
*===========================================================================
* ipike_radius_extract_key
*===========================================================================
*/
IP_GLOBAL void
ipike_radius_extract_key(Ipike_radius_ctx* ctx, Ip_u8* key, Ip_u32* key_size)
{
Ip_u8* key_recv = IP_NULL;
Ip_u8* key_send = IP_NULL;
Ip_u32 key_len = 0;
Ip_u32 max_len = 0;
Ip_u32 len = 0;
max_len = *key_size;
*key_size = 0;
if (ipike_radius_get_microsoft_keys(ctx,
&key_recv,
&key_send,
&key_len) == IPIKE_SUCCESS)
{
/* Append recv key */
if ((key_len + *key_size) > max_len)
len = max_len - *key_size;
else
len = key_len;
ipcom_memcpy(key + *key_size, key_recv, len);
*key_size += len;
/* Append send key */
if ((key_len + *key_size) > max_len)
len = max_len - *key_size;
else
len = key_len;
ipcom_memcpy(key + *key_size, key_send, len);
*key_size += len;
/* free allocated keys */
ipcom_free(key_recv);
ipcom_free(key_send);
key_recv = IP_NULL;
key_send = IP_NULL;
}
/* Try to get cisco session key (LEAP) */
else if ( ipike_radius_get_cisco_session_key(ctx, &key_recv, &key_len) == IPIKE_SUCCESS )
{
if ( key_len > max_len )
key_len = max_len;
/* Copy key */
ipcom_memcpy(key, key_recv, key_len);
*key_size = key_len;
/* Free allocated bytes */
ipcom_free(key_recv);
key_recv = IP_NULL;
}
return;
}
/*
*===========================================================================
* ipike_radius_startup
*===========================================================================
*/
IP_GLOBAL Ipike_error
ipike_radius_startup(void)
{
Ipradius_open conf;
if (ipike.radius.initialized)
ipike_radius_shutdown();
ipike.radius.initialized = IP_TRUE;
/* Initialize hash table */
ipike.radius.hash_table = ipcom_hash_new(
(Ipcom_hash_obj_func) ipike_radius_hash_obj,
(Ipcom_hash_key_func) ipike_radius_hash_key,
(Ipcom_hash_cmp_func) ipike_radius_hash_cmp);
if (ipike.radius.hash_table == IP_NULL)
{
IP_PANIC();
return IPIKE_OUT_OF_MEMORY;
}
/* Initialize hash table */
ipike.radius.unique_id_table = ipcom_hash_new(
(Ipcom_hash_obj_func) ipike_radius_hash_unique_id_obj,
(Ipcom_hash_key_func) ipike_radius_hash_unique_id_key,
(Ipcom_hash_cmp_func) ipike_radius_hash_unique_id_cmp);
if (ipike.radius.unique_id_table == IP_NULL)
{
IP_PANIC();
return IPIKE_OUT_OF_MEMORY;
}
/* Open IPRADIUS */
ipcom_strcpy(conf.ipradius_NAS_Identifier,"Interpeak IKE");
conf.ipradius_NAS_Identifier_size = (Ip_u32) ipcom_strlen(conf.ipradius_NAS_Identifier);
conf.access_request_attribute_size = IPIKE_EAP_MAX_BUF;
conf.accounting_request_attribute_size = IPRADIUS_accounting_request_attribute_size;
conf.conf[0] = IP_TAG_END;
if (ipradius_open(&conf) != IPCOM_SUCCESS)
{
/* Ignore failure, since no closing */
IPCOM_LOG0(DEBUG2, "ipike_radius_startup: Failed to open radius (ignored)");
}
return IPIKE_SUCCESS;
}
/*
*===========================================================================
* ipike_radius_shutdown
*===========================================================================
*/
IP_GLOBAL void
ipike_radius_shutdown(void)
{
if (!ipike.radius.initialized)
return;
/* Close hash table */
if (ipike.radius.hash_table != IP_NULL)
{
ipcom_hash_for_each(ipike.radius.hash_table,
(void(*)(void *, void *)) ipike_radius_hash_free, IP_NULL);
ipcom_hash_delete(ipike.radius.hash_table);
ipike.radius.hash_table = IP_NULL;
}
if (ipike.radius.unique_id_table != IP_NULL)
{
ipcom_hash_for_each(ipike.radius.unique_id_table,
(void(*)(void *, void *)) ipike_radius_hash_unique_id_free, IP_NULL);
ipcom_hash_delete(ipike.radius.unique_id_table);
ipike.radius.unique_id_table = IP_NULL;
}
ipike.radius.initialized = IP_FALSE;
return;
}
#else
int ipike_radius_empty_file = 0;
#endif /* IPIKE_USE_RADIUS */
/*
****************************************************************************
* END OF FILE
****************************************************************************
*/