1018 lines
42 KiB
C
1018 lines
42 KiB
C
|
|
/*
|
|
******************************************************************************
|
|
* INTERPEAK SOURCE FILE
|
|
*
|
|
* Document no: @(#) $Name: VXWORKS_ITER40_2019102207 $ $RCSfile: ipmipha_aaa_radius.c,v $ $Revision: 1.6.10.1 $
|
|
* $Source: /home/interpeak/CVSRoot/ipmipha/config/ipmipha_aaa_radius.c,v $
|
|
* $Author: jsheng $
|
|
* $State: Exp $ $Locker: $
|
|
*
|
|
* INTERPEAK_COPYRIGHT_STRING
|
|
* Design and implementation by Joel Hortelius <joel.hortelis@interpeak.se>
|
|
******************************************************************************
|
|
*/
|
|
|
|
|
|
/*
|
|
****************************************************************************
|
|
* 1 DESCRIPTION
|
|
****************************************************************************
|
|
*/
|
|
|
|
/*
|
|
****************************************************************************
|
|
* 2 CONFIGURATION
|
|
****************************************************************************
|
|
*/
|
|
|
|
#include "ipmipha_config.h"
|
|
|
|
#ifdef IPMIPHA_RADIUS_ENABLE
|
|
|
|
/*
|
|
****************************************************************************
|
|
* 3 INCLUDE FILES
|
|
****************************************************************************
|
|
*/
|
|
|
|
#define IPCOM_USE_CLIB_PROTO
|
|
#include <ipcom_clib.h>
|
|
#include <ipcom_err.h>
|
|
#include <ipcom_hash.h>
|
|
#include <ipcom_inet.h>
|
|
#include <ipcom_ipd.h>
|
|
#include <ipcom_list.h>
|
|
#include <ipcom_os.h>
|
|
#include <ipcom_sock.h>
|
|
#include <ipcom_sock2.h>
|
|
#include <ipcom_syslog.h>
|
|
#include <ipcom_sysvar.h>
|
|
|
|
#include <ipmip.h>
|
|
#include <private/ipmip_buffer.h>
|
|
|
|
#include <ipmip4.h>
|
|
#include <private/ipmip4_context.h>
|
|
#include <private/ipmip4_if.h>
|
|
#include <private/ipmip4_auth.h>
|
|
#include <private/ipmip4_sysext.h>
|
|
#include <private/ipmip4_util.h>
|
|
#include <private/ipmip4_radius.h>
|
|
#include <private/ipmip4_pktbuf.h>
|
|
|
|
#include "ipmipha_h.h"
|
|
#include "ipmipha_if.h"
|
|
#include "ipmipha_node.h"
|
|
#include "ipmipha_pktbuf.h"
|
|
|
|
|
|
#if defined(IPMCRYPTO)
|
|
#include <ip/openssl/sha.h>
|
|
#else
|
|
#include <openssl/sha.h>
|
|
#endif
|
|
|
|
/*
|
|
****************************************************************************
|
|
* 4 DEFINES
|
|
****************************************************************************
|
|
*/
|
|
|
|
#define IPMIPHA_AAA_RADIUS "AAA-RADIUS"
|
|
|
|
/*
|
|
****************************************************************************
|
|
* 5 TYPES
|
|
****************************************************************************
|
|
*/
|
|
|
|
typedef struct Ipmipha_aaa_radius_config_ifp
|
|
{
|
|
struct Ipmip4_radius_context *radius;
|
|
|
|
/* Should the MN-AAA authentication extension be verified? */
|
|
Ip_bool access;
|
|
/* MUST the MN-AAA extension be available? */
|
|
Ip_bool access_require;
|
|
Ip_u32 access_timeout;
|
|
/* Enable or disable accounting */
|
|
Ip_bool accounting;
|
|
} Ipmipha_aaa_radius_config_ifp_t;
|
|
|
|
typedef struct Ipmipha_aaa_radius_pktbuf_data
|
|
{
|
|
Ip_bool keyrep;
|
|
char *tunnel_pwd;
|
|
char *shared_key;
|
|
Ip_u32 spi_mh_num;
|
|
Ip_u32 spi_aaa_num;
|
|
Ip_u8 nonce[16];
|
|
} Ipmipha_aaa_radius_pktbuf_data_t;
|
|
/*
|
|
****************************************************************************
|
|
* 6 EXTERN PROTOTYPES
|
|
****************************************************************************
|
|
*/
|
|
|
|
/*
|
|
****************************************************************************
|
|
* 7 LOCAL PROTOTYPES
|
|
****************************************************************************
|
|
*/
|
|
|
|
/*
|
|
****************************************************************************
|
|
* 8 DATA
|
|
****************************************************************************
|
|
*/
|
|
static Ipmipha_extension_t ipmipha_aaa_radius_srv;
|
|
|
|
/*
|
|
****************************************************************************
|
|
* 9 STATIC FUNCTIONS
|
|
****************************************************************************
|
|
*/
|
|
|
|
IP_STATIC void
|
|
ipmipha_aaa_radius_pktaux_free(struct Ipmipha_data *data,
|
|
struct Ipmip_proc *proc,
|
|
struct Ipmipha_pktbuf *pbuf,
|
|
Ipmipha_aaa_radius_pktbuf_data_t *aaa)
|
|
{
|
|
IPMIP_UNUSED_PARAMETER(data);
|
|
IPMIP_UNUSED_PARAMETER(proc);
|
|
IPMIP_UNUSED_PARAMETER(pbuf);
|
|
|
|
if (aaa->tunnel_pwd)
|
|
ipcom_free(aaa->tunnel_pwd);
|
|
if (aaa->shared_key)
|
|
ipcom_free(aaa->shared_key);
|
|
}
|
|
|
|
|
|
IP_STATIC void
|
|
ipmipha_aaa_radius_acct_process(int event,
|
|
Ipmipha_data_t *data,
|
|
Ipmip_proc_t *proc,
|
|
struct Ipmip4_radius_context *radius,
|
|
void *unused,
|
|
Ipmipha_node_t *node,
|
|
Ipmip4_radius_packet_t *request,
|
|
Ipmip4_radius_packet_t *reply)
|
|
{
|
|
IPMIP_UNUSED_PARAMETER(reply);
|
|
IPMIP_UNUSED_PARAMETER(unused);
|
|
if (event == IPMIP4_RADIUS_ACCOUNTING_STOP)
|
|
{
|
|
Ip_u32 val;
|
|
|
|
/**** THE PBUF VARIABLE IS NOT VALID HERE; ONLY USE NODE */
|
|
|
|
/* Add username */
|
|
if (node->nai_mobile != IP_NULL)
|
|
{
|
|
ipmip4_radius_attr_add(&data->ipmip4,
|
|
proc,
|
|
radius,
|
|
request,
|
|
IPMIP4_RADIUS_ATTR_User_Name,
|
|
(Ip_u8*)IPMIP4_MSGEXT_SHDR_EXT_DATA(node->nai_mobile),
|
|
(Ip_u8)IPMIP4_MSGEXT_SHDR_EXT_SIZE(node->nai_mobile));
|
|
}
|
|
|
|
/* Add the FRAMED IP ADDRESS */
|
|
if (node->haNodeHomeAddress.prefix != 0)
|
|
{
|
|
ipmip4_radius_attr_add(&data->ipmip4,
|
|
proc,
|
|
radius,
|
|
request,
|
|
IPMIP4_RADIUS_ATTR_Framed_IP_Address,
|
|
(Ip_u8*)&node->haNodeHomeAddress.prefix,
|
|
(Ip_u8)sizeof(node->haNodeHomeAddress.prefix));
|
|
}
|
|
|
|
/* Add the NAS IP address */
|
|
ipmip4_radius_attr_add(&data->ipmip4,
|
|
proc,
|
|
radius,
|
|
request,
|
|
IPMIP4_RADIUS_ATTR_NAS_IP_Address,
|
|
(Ip_u8*)&node->ifp->iff.ifaddr,
|
|
(Ip_u8)sizeof(node->ifp->iff.ifaddr));
|
|
|
|
val = IP_U64_GETLO(node->haNodeRcvOctets);
|
|
val = ip_htonl(val);
|
|
ipmip4_radius_attr_add(&data->ipmip4,
|
|
proc,
|
|
radius,
|
|
request,
|
|
IPMIP4_RADIUS_ACCT_Input_Octets,
|
|
(Ip_u8*)&val,
|
|
(Ip_u8)sizeof(val));
|
|
|
|
val = IP_U64_GETHI(node->haNodeRcvOctets);
|
|
val = ip_htonl(val);
|
|
ipmip4_radius_attr_add(&data->ipmip4,
|
|
proc,
|
|
radius,
|
|
request,
|
|
IPMIP4_RADIUS_ACCT_Input_Gigawords,
|
|
(Ip_u8*)&val,
|
|
(Ip_u8)sizeof(val));
|
|
|
|
val = IP_U64_GETLO(node->haNodeRcvPkts);
|
|
val = ip_htonl(val);
|
|
ipmip4_radius_attr_add(&data->ipmip4,
|
|
proc,
|
|
radius,
|
|
request,
|
|
IPMIP4_RADIUS_ACCT_Input_Packets,
|
|
(Ip_u8*)&val,
|
|
(Ip_u8)sizeof(val));
|
|
|
|
val = IP_U64_GETLO(node->haNodeSndOctets);
|
|
val = ip_htonl(val);
|
|
ipmip4_radius_attr_add(&data->ipmip4,
|
|
proc,
|
|
radius,
|
|
request,
|
|
IPMIP4_RADIUS_ACCT_Output_Octets,
|
|
(Ip_u8*)&val,
|
|
(Ip_u8)sizeof(val));
|
|
|
|
val = IP_U64_GETHI(node->haNodeSndOctets);
|
|
val = ip_htonl(val);
|
|
ipmip4_radius_attr_add(&data->ipmip4,
|
|
proc,
|
|
radius,
|
|
request,
|
|
IPMIP4_RADIUS_ACCT_Output_Gigawords,
|
|
(Ip_u8*)&val,
|
|
(Ip_u8)sizeof(val));
|
|
|
|
val = IP_U64_GETLO(node->haNodeSndPkts);
|
|
val = ip_htonl(val);
|
|
ipmip4_radius_attr_add(&data->ipmip4,
|
|
proc,
|
|
radius,
|
|
request,
|
|
IPMIP4_RADIUS_ACCT_Output_Packets,
|
|
(Ip_u8*)&val,
|
|
(Ip_u8)sizeof(val));
|
|
|
|
val = (Ip_u32)(ipmip_util_time() - node->haNodeCreationTime);
|
|
val = ip_htonl(val);
|
|
ipmip4_radius_attr_add(&data->ipmip4,
|
|
proc,
|
|
radius,
|
|
request,
|
|
IPMIP4_RADIUS_ACCT_Session_Time,
|
|
(Ip_u8*)&val,
|
|
(Ip_u8)sizeof(val));
|
|
}
|
|
else if (event == IPMIP4_RADIUS_ACCOUNTING_START)
|
|
{
|
|
/* Add username */
|
|
if (node->nai_mobile != IP_NULL)
|
|
{
|
|
ipmip4_radius_attr_add(&data->ipmip4,
|
|
proc,
|
|
radius,
|
|
request,
|
|
IPMIP4_RADIUS_ATTR_User_Name,
|
|
(Ip_u8*)IPMIP4_MSGEXT_SHDR_EXT_DATA(node->nai_mobile),
|
|
(Ip_u8)IPMIP4_MSGEXT_SHDR_EXT_SIZE(node->nai_mobile));
|
|
}
|
|
|
|
/* Add the FRAMED IP ADDRESS */
|
|
if (node->haNodeHomeAddress.prefix != 0)
|
|
{
|
|
ipmip4_radius_attr_add(&data->ipmip4,
|
|
proc,
|
|
radius,
|
|
request,
|
|
IPMIP4_RADIUS_ATTR_Framed_IP_Address,
|
|
(Ip_u8*)&node->haNodeHomeAddress.prefix,
|
|
(Ip_u8)sizeof(node->haNodeHomeAddress.prefix));
|
|
}
|
|
|
|
/* Add the NAS IP address */
|
|
ipmip4_radius_attr_add(&data->ipmip4,
|
|
proc,
|
|
radius,
|
|
request,
|
|
IPMIP4_RADIUS_ATTR_NAS_IP_Address,
|
|
(Ip_u8*)&node->ifp->iff.ifaddr,
|
|
(Ip_u8)sizeof(node->ifp->iff.ifaddr));
|
|
}
|
|
else if (event == IPMIP4_RADIUS_ACCOUNTING_START_RESPONSE)
|
|
{
|
|
IPMIP4_EVENT_IF(DEBUG2, proc,
|
|
ipmip_log_event_add(&data->ipmip4.ipmip,
|
|
proc,
|
|
"Node %s RADIUS Accounting started",
|
|
ipmipha_node_describe(proc, node, IP_NULL)));
|
|
|
|
/* Is it our start? */
|
|
node->haNodeAccounting = 1;
|
|
ipmip_timer_execute(&data->ipmip4.ipmip, &node->service);
|
|
}
|
|
else if (event == IPMIP4_RADIUS_ACCOUNTING_STOP_RESPONSE)
|
|
{
|
|
IPMIP4_EVENT_IF(DEBUG2, proc,
|
|
ipmip_log_event_add(&data->ipmip4.ipmip,
|
|
proc,
|
|
"Node %s RADIUS Accounting stopped",
|
|
ipmipha_node_describe(proc, node, IP_NULL)));
|
|
|
|
/* Is it our start? */
|
|
ipmip_timer_execute(&data->ipmip4.ipmip, &node->service);
|
|
}
|
|
else
|
|
{
|
|
IPMIP4_EVENT_IF(DEBUG2, proc,
|
|
ipmip_log_event_add(&data->ipmip4.ipmip,
|
|
proc,
|
|
"Node %s RADIUS Accounting failed",
|
|
ipmipha_node_describe(proc, node, IP_NULL)));
|
|
|
|
/* SOME KIND OF ERROR */
|
|
ipmip_timer_execute(&data->ipmip4.ipmip, &node->service);
|
|
}
|
|
}
|
|
|
|
|
|
IP_STATIC void
|
|
ipmipha_aaa_radius_auth_process(int result,
|
|
Ipmipha_data_t *data,
|
|
Ipmip_proc_t *proc,
|
|
struct Ipmip4_radius_context *radius,
|
|
Ipmipha_pktbuf_t *pbuf,
|
|
Ipmipha_node_t *node,
|
|
Ipmip4_radius_packet_t *request,
|
|
Ipmip4_radius_packet_t *reply)
|
|
{
|
|
if (result == IPMIP4_RADIUS_ACCESS_REQUEST_SUCCESS)
|
|
{
|
|
Ip_u8 *attr = IP_NULL;
|
|
Ipmipha_aaa_radius_pktbuf_data_t *aaa = ipmip_pktbuf_pktaux_data_get(&data->ipmip4.ipmip, &pbuf->ipmip4.ipmip, ipmipha_aaa_radius_srv.pktaux.pktbuf_data_index, IP_TRUE);
|
|
if(IP_NULL == aaa)
|
|
return;
|
|
|
|
/**/
|
|
IPMIP4_EVENT_IF(INFO, proc,
|
|
ipmip_log_event_add(&data->ipmip4.ipmip,
|
|
proc,
|
|
"Node %s RADIUS authorization accepted",
|
|
ipmipha_node_describe(proc, node, IP_NULL)));
|
|
|
|
/* Allocate the NAI */
|
|
if (node->nai_aaah == IP_NULL)
|
|
node->nai_aaah = ipmip4_radius_aaah(&data->ipmip4, proc, radius);
|
|
|
|
/* Go through the attributes */
|
|
while ((attr = ipmip4_radius_attr_next(&data->ipmip4, proc, radius, reply, attr)) != IP_NULL)
|
|
{
|
|
/**/
|
|
switch (IPMIP4_RADIUS_ATTR_TYPE(attr))
|
|
{
|
|
case IPMIP4_RADIUS_ATTR_Framed_IP_Address:
|
|
pbuf->pktinfo.haBindingResolvedHomeAddress = IP_GET_32ON8(IPMIP4_RADIUS_ATTR_DATA(attr, 0));
|
|
#if 0
|
|
IPCOM_LOG3(DEBUG2, "Extension: %d/%d (Framed IP Address) IP=%s", attr[0], attr[1], ipmip_ntop_inet(proc, pbuf->pktinfo.haBindingResolvedHomeAddress));
|
|
#endif
|
|
break;
|
|
case IPMIP4_RADIUS_ATTR_Tunnel_Password:
|
|
{
|
|
Ipmip_buffer_t buf;
|
|
const char *key;
|
|
/* Jump past the TAG field, go for the SALT */
|
|
if ((key = ipmip4_radius_decrypt_tunnel_password(&data->ipmip4,proc,radius,request,IPMIP4_RADIUS_ATTR_DATA(attr, 1),IPMIP4_RADIUS_ATTR_LEN(attr) - 1, &buf)))
|
|
{
|
|
#if 0
|
|
IPCOM_LOG2(DEBUG2, "Extension: %d/%d (Tunnel Password) Password=<>",
|
|
IPMIP4_RADIUS_ATTR_TYPE(attr),
|
|
IPMIP4_RADIUS_ATTR_LEN(attr));
|
|
#endif
|
|
aaa->tunnel_pwd = ipcom_strdup(key);
|
|
ipmip_buffer_release(&buf);
|
|
}
|
|
}
|
|
break;
|
|
case IPMIP4_RADIUS_ATTR_Vendor_Specific:
|
|
{
|
|
Ip_u32 vendor = IPMIP4_RADIUS_ATTR_VSA_VENDOR(attr);
|
|
switch (vendor)
|
|
{
|
|
case IPMIP4_RADIUS_VENDOR_3GGP2:
|
|
switch (IPMIP4_RADIUS_ATTR_VSA_TYPE(attr))
|
|
{
|
|
case IPMIP4_RADIUS_VENDOR_3GPP2_Home_Agent_IP_Address:
|
|
pbuf->pktinfo.haBindingResolvedHomeAgentAddress = IP_GET_32ON8(IPMIP4_RADIUS_ATTR_VSA_DATA(attr));
|
|
#if 0
|
|
IPCOM_LOG3(DEBUG2, "Extension: %d/%d (VSA) Vendor = 3GPP2, HA=%s",
|
|
IPMIP4_RADIUS_ATTR_TYPE(attr),
|
|
IPMIP4_RADIUS_ATTR_LEN(attr),
|
|
ipmip_ntop_inet(proc, pbuf->pktinfo.haBindingResolvedHomeAgentAddress));
|
|
#endif
|
|
break;
|
|
case IPMIP4_RADIUS_VENDOR_3GPP2_MN_HA_SPI:
|
|
#if 0
|
|
IPCOM_LOG3(DEBUG2, "Extension: %d/%d (VSA) Vendor = 3GPP2, HA SPI=%d",
|
|
IPMIP4_RADIUS_ATTR_TYPE(attr),
|
|
IPMIP4_RADIUS_ATTR_LEN(attr),
|
|
IP_GET_NTOHL(IPMIP4_RADIUS_ATTR_VSA_DATA(attr)));
|
|
#endif
|
|
break;
|
|
case IPMIP4_RADIUS_VENDOR_3GPP2_MN_HA_SHARED_KEY:
|
|
{
|
|
Ipmip_buffer_t buf;
|
|
const char *key;
|
|
if ((key = ipmip4_radius_decrypt_tunnel_password(&data->ipmip4,proc,radius,request,IPMIP4_RADIUS_ATTR_VSA_DATA(attr),IPMIP4_RADIUS_ATTR_VSA_LEN(attr), &buf)))
|
|
{
|
|
#if 0
|
|
IPCOM_LOG2(DEBUG2, "Extension: %d/%d (VSA) Vendor = 3GPP2, Secret=<>",
|
|
IPMIP4_RADIUS_ATTR_TYPE(attr),
|
|
IPMIP4_RADIUS_ATTR_LEN(attr));
|
|
#endif
|
|
aaa->shared_key = ipcom_strdup(key);
|
|
ipmip_buffer_release(&buf);
|
|
}
|
|
}
|
|
break;
|
|
default:
|
|
#if 0
|
|
IPCOM_LOG4(DEBUG2, "Extension: %d/%d (VSA) Vendor = 3GPP2, Info=%d/%d",
|
|
IPMIP4_RADIUS_ATTR_TYPE(attr),
|
|
IPMIP4_RADIUS_ATTR_LEN(attr),
|
|
IPMIP4_RADIUS_ATTR_VSA_TYPE(attr),
|
|
IPMIP4_RADIUS_ATTR_VSA_LEN(attr));
|
|
#endif
|
|
break;
|
|
}
|
|
break;
|
|
case IPMIP4_RADIUS_VENDOR_CISCO:
|
|
#if 0
|
|
IPCOM_LOG4(DEBUG2, "Extension: %d/%d (VSA) Vendor = CISCO, Info=%d/%d",
|
|
IPMIP4_RADIUS_ATTR_TYPE(attr),
|
|
IPMIP4_RADIUS_ATTR_LEN(attr),
|
|
IPMIP4_RADIUS_ATTR_VSA_TYPE(attr),
|
|
IPMIP4_RADIUS_ATTR_VSA_LEN(attr));
|
|
#endif
|
|
break;
|
|
default:
|
|
#if 0
|
|
IPCOM_LOG5(DEBUG2, "Extension: %d/%d (VSA) Vendor = %u, Info=%d/%d",
|
|
IPMIP4_RADIUS_ATTR_TYPE(attr),
|
|
IPMIP4_RADIUS_ATTR_LEN(attr),
|
|
vendor,
|
|
IPMIP4_RADIUS_ATTR_VSA_TYPE(attr),
|
|
IPMIP4_RADIUS_ATTR_VSA_LEN(attr));
|
|
#endif
|
|
break;
|
|
}
|
|
break;
|
|
}
|
|
default:
|
|
#if 0
|
|
IPCOM_LOG2(DEBUG2, "Extension: %d/%d",
|
|
IPMIP4_RADIUS_ATTR_TYPE(attr),
|
|
IPMIP4_RADIUS_ATTR_LEN(attr));
|
|
#endif
|
|
break;
|
|
}
|
|
}
|
|
|
|
/* Time to process some AAA related functionalities */
|
|
if (pbuf->ipmip4.ext.mobile.mn_ha_keyreq != IP_NULL)
|
|
{
|
|
/* Do we have a tunnel password? */
|
|
if (aaa->tunnel_pwd != IP_NULL)
|
|
{
|
|
Ipmip4_ext_gen_auth_t *auth = (Ipmip4_ext_gen_auth_t *)pbuf->ipmip4.ext.mobile.mn_aaa;
|
|
Ipmip4_ext_keyreq_t *keyreq = (Ipmip4_ext_keyreq_t *)pbuf->ipmip4.ext.mobile.mn_ha_keyreq;
|
|
void *ident;
|
|
Ip_u32 i;
|
|
|
|
aaa->spi_aaa_num = IP_GET_NTOHL(&auth->spi[0]);
|
|
aaa->spi_mh_num = IP_GET_NTOHL(&keyreq->spi);
|
|
|
|
aaa->keyrep = IP_TRUE;
|
|
|
|
for (i = 0; i < 16; i++)
|
|
aaa->nonce[i] = ipcom_random() & 0xff;
|
|
|
|
/**/
|
|
if (pbuf->ipmip4.ext.mobile.nai_mobile)
|
|
{
|
|
ident = IPMIP4_MSGEXT_SHDR_EXT_DATA(pbuf->ipmip4.ext.mobile.nai_mobile);
|
|
i = IPMIP4_MSGEXT_SHDR_EXT_SIZE(pbuf->ipmip4.ext.mobile.nai_mobile);
|
|
}
|
|
else
|
|
{
|
|
ident = (void *)&pbuf->pktinfo.haBindingHomeAddress;
|
|
i = sizeof(pbuf->pktinfo.haBindingHomeAddress);
|
|
}
|
|
|
|
if (node->haBindingHomeSA)
|
|
ipmip4_auth_spi_free(node->haBindingHomeSA);
|
|
|
|
/* Claim the security association */
|
|
node->haBindingHomeSA = ipmip4_auth_spi_generate(&data->ipmip4,
|
|
proc,
|
|
aaa->spi_mh_num,
|
|
IPMIP4_AUTH_ALG_HMAC_SHA,
|
|
aaa->tunnel_pwd,
|
|
ipcom_strlen(aaa->tunnel_pwd),
|
|
aaa->nonce,
|
|
16,
|
|
ident,
|
|
i);
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
ipmip_pktbuf_error(&pbuf->ipmip4.ipmip,
|
|
0,
|
|
"AAA RADIUS authentication request failed");
|
|
}
|
|
|
|
/* Are we satisfied? */
|
|
if (pbuf->ipmip4.ipmip.message == IP_NULL)
|
|
pbuf->haBindingAAAVerified = IP_TRUE;
|
|
ipmip_timer_execute(&data->ipmip4.ipmip, &node->service);
|
|
}
|
|
|
|
/*
|
|
*===========================================================================
|
|
* ipmipha_radius_request
|
|
*===========================================================================
|
|
* Description: Create the basic parts of a radius access-request
|
|
* Parameters:
|
|
* Returns:
|
|
*
|
|
*/
|
|
IP_STATIC Ipmip4_radius_packet_t *
|
|
ipmipha_aaa_radius_request(Ipmipha_data_t *data,
|
|
Ipmip_proc_t *proc,
|
|
Ipmipha_aaa_radius_config_ifp_t *ifp_config,
|
|
Ipmipha_pktbuf_t *pbuf)
|
|
{
|
|
Ipmip4_radius_packet_t *msg = ipmip4_radius_access_request_init(&data->ipmip4, proc, ifp_config->radius);
|
|
|
|
if (msg == IP_NULL)
|
|
{
|
|
ipmip_pktbuf_error(&pbuf->ipmip4.ipmip,
|
|
0,
|
|
"HA failed to allocate required memory for RADIUS negotiation");
|
|
return IP_NULL;
|
|
}
|
|
|
|
/* Add username */
|
|
if (pbuf->ipmip4.ext.mobile.nai_mobile != IP_NULL)
|
|
{
|
|
ipmip4_radius_attr_add(&data->ipmip4,
|
|
proc,
|
|
ifp_config->radius,
|
|
msg,
|
|
IPMIP4_RADIUS_ATTR_User_Name,
|
|
(Ip_u8*)IPMIP4_MSGEXT_SHDR_EXT_DATA(pbuf->ipmip4.ext.mobile.nai_mobile),
|
|
(Ip_u8)IPMIP4_MSGEXT_SHDR_EXT_SIZE(pbuf->ipmip4.ext.mobile.nai_mobile));
|
|
}
|
|
|
|
if (pbuf->pktinfo.haBindingHomeAddress != 0)
|
|
{
|
|
ipmip4_radius_attr_add(&data->ipmip4,
|
|
proc,
|
|
ifp_config->radius,
|
|
msg,
|
|
IPMIP4_RADIUS_ATTR_Framed_IP_Address,
|
|
(Ip_u8*)&pbuf->pktinfo.haBindingHomeAddress,
|
|
(Ip_u8)sizeof(pbuf->pktinfo.haBindingHomeAddress));
|
|
}
|
|
|
|
/* Add the 3GPP2 Home Agent extension */
|
|
if (pbuf->pktinfo.haBindingHomeAgentAddress)
|
|
{
|
|
/* There's an explicit address requested */
|
|
ipmip4_radius_attr_vendor_add(&data->ipmip4,
|
|
proc,
|
|
ifp_config->radius,
|
|
msg,
|
|
IPMIP4_RADIUS_VENDOR_3GGP2,
|
|
IPMIP4_RADIUS_VENDOR_3GPP2_Home_Agent_IP_Address,
|
|
&pbuf->pktinfo.haBindingHomeAgentAddress,
|
|
4);
|
|
}
|
|
else
|
|
{
|
|
/* Add our address */
|
|
ipmip4_radius_attr_vendor_add(&data->ipmip4,
|
|
proc,
|
|
ifp_config->radius,
|
|
msg,
|
|
IPMIP4_RADIUS_VENDOR_3GGP2,
|
|
IPMIP4_RADIUS_VENDOR_3GPP2_Home_Agent_IP_Address,
|
|
&pbuf->iff.pub->ifaddr,
|
|
4);
|
|
}
|
|
|
|
/* Request a Shared Secret */
|
|
if (pbuf->ipmip4.ext.mobile.mobile_home != IP_NULL)
|
|
{
|
|
/**/
|
|
Ipmip4_ext_auth_t *mh = (Ipmip4_ext_auth_t *) pbuf->ipmip4.ext.mobile.mobile_home;
|
|
|
|
/* Add our address */
|
|
ipmip4_radius_attr_vendor_add(&data->ipmip4,
|
|
proc,
|
|
ifp_config->radius,
|
|
msg,
|
|
IPMIP4_RADIUS_VENDOR_3GGP2,
|
|
IPMIP4_RADIUS_VENDOR_3GPP2_MN_HA_SPI,
|
|
&mh->spi,
|
|
4);
|
|
}
|
|
|
|
{
|
|
Ip_u32 msgid[2];
|
|
|
|
IP_SET_32ON8(&msgid[0], pbuf->pktinfo.haBindingRegIDHigh);
|
|
IP_SET_32ON8(&msgid[1], pbuf->pktinfo.haBindingRegIDLow);
|
|
|
|
/* Add our address */
|
|
ipmip4_radius_attr_vendor_add(&data->ipmip4,
|
|
proc,
|
|
ifp_config->radius,
|
|
msg,
|
|
IPMIP4_RADIUS_VENDOR_3GGP2,
|
|
IPMIP4_RADIUS_VENDOR_3GPP2_MN_MIP4_Mesg_Id,
|
|
&msgid[0],
|
|
8);
|
|
}
|
|
/**/
|
|
ipmip4_radius_attr_add(&data->ipmip4,
|
|
proc,
|
|
ifp_config->radius,
|
|
msg,
|
|
IPMIP4_RADIUS_ATTR_NAS_IP_Address,
|
|
(Ip_u8*)&pbuf->iff.pub->ifaddr,
|
|
(Ip_u8)sizeof(pbuf->iff.pub->ifaddr));
|
|
return msg;
|
|
}
|
|
|
|
|
|
IP_STATIC void
|
|
ipmipha_aaa_radius_pkt_rep_mobile_home(struct Ipmipha_data *ctx,
|
|
struct Ipmip_proc *proc,
|
|
void *global_config,
|
|
Ipmipha_aaa_radius_config_ifp_t *ifp_config,
|
|
void *node_config,
|
|
struct Ipmipha_node *node,
|
|
struct Ipmipha_pktbuf *req_pbuf,
|
|
struct Ipmipha_pktbuf *pbuf)
|
|
{
|
|
Ipmipha_aaa_radius_pktbuf_data_t *aaa = ipmip_pktbuf_pktaux_data_get(&ctx->ipmip4.ipmip, &req_pbuf->ipmip4.ipmip, ipmipha_aaa_radius_srv.pktaux.pktbuf_data_index, IP_FALSE);
|
|
|
|
IPMIP_UNUSED_PARAMETER(ctx);
|
|
IPMIP_UNUSED_PARAMETER(global_config);
|
|
IPMIP_UNUSED_PARAMETER(ifp_config);
|
|
IPMIP_UNUSED_PARAMETER(node_config);
|
|
IPMIP_UNUSED_PARAMETER(node);
|
|
|
|
if (aaa != IP_NULL && aaa->keyrep)
|
|
{
|
|
Ipmip4_ext_keyrep_ha_t *keyrep = (Ipmip4_ext_keyrep_ha_t *)proc->ntop.ntop_pbuf;
|
|
|
|
ipcom_memset(keyrep, 0, sizeof(*keyrep));
|
|
|
|
/**/
|
|
keyrep->type = IPMIP4_EXT_TYPE_MN_HA_KEYGEN_REP;
|
|
keyrep->subtype = IPMIP4_KEYGEN_SUBTYPE_1;
|
|
|
|
IP_SET_HTONL(&keyrep->lifetime, 0xffffffff);
|
|
IP_SET_HTONS(&keyrep->alg_id, IPMIP4_AUTH_ALG_HMAC_SHA);
|
|
IP_SET_HTONS(&keyrep->replay, 2);
|
|
IP_SET_HTONS(&keyrep->length, (IPMIP4_EXT_KEYREP_HA_LENGTH + 16 - IPMIP4_MSGEXT_LHDR_HDR_SIZE));
|
|
IP_SET_HTONL(&keyrep->aaa_spi, aaa->spi_aaa_num);
|
|
IP_SET_HTONL(&keyrep->spi, aaa->spi_mh_num);
|
|
|
|
ipcom_memcpy(&keyrep->nonce[0], &aaa->nonce[0], 16);
|
|
|
|
/* Append */
|
|
ipmip4_msgext_buffer_append_lhdr(&pbuf->ipmip4.ipmip.packet, (void *)proc->ntop.ntop_pbuf);
|
|
}
|
|
}
|
|
|
|
/**/
|
|
IP_STATIC int
|
|
ipmipha_aaa_radius_provide(struct Ipmipha_data *ctx,
|
|
struct Ipmip_proc *proc,
|
|
int action,
|
|
void *global_config,
|
|
Ipmipha_aaa_radius_config_ifp_t *ifp_config,
|
|
void *node_config,
|
|
struct Ipmipha_node *node)
|
|
{
|
|
|
|
IPMIP_UNUSED_PARAMETER(global_config);
|
|
IPMIP_UNUSED_PARAMETER(node_config);
|
|
|
|
if (action == IPMIP_CALLBACK_ENABLE)
|
|
{
|
|
if (ifp_config->accounting)
|
|
{
|
|
/* Must terminate the accounting session */
|
|
if (!ipmip4_radius_accounting_start(&ctx->ipmip4,
|
|
proc,
|
|
ifp_config->radius,
|
|
(Ipmip4_radius_func_t)ipmipha_aaa_radius_acct_process,
|
|
node->haNodeIdentity,
|
|
IP_NULL,
|
|
node))
|
|
{
|
|
IPMIP4_EVENT_IF(ERR, proc,
|
|
ipmip_log_event_add(&ctx->ipmip4.ipmip,
|
|
proc,
|
|
"HA not able to communicate with RADIUS server (ACCT)"));
|
|
return IPMIP_CALLBACK_RET_FAILED;
|
|
}
|
|
|
|
/* Pending; wait for accounting start */
|
|
return IPMIP_CALLBACK_RET_PENDING;
|
|
}
|
|
}
|
|
else if (action == IPMIP_CALLBACK_DISABLE)
|
|
{
|
|
if (node->haNodeAccounting)
|
|
{
|
|
if (ifp_config->radius != IP_NULL)
|
|
{
|
|
/* Must terminate the accounting session */
|
|
if (!ipmip4_radius_accounting_stop(&ctx->ipmip4,
|
|
proc,
|
|
ifp_config->radius,
|
|
node->haNodeIdentity))
|
|
return IPMIP_CALLBACK_RET_FAILED;
|
|
|
|
return IPMIP_CALLBACK_RET_PENDING;
|
|
}
|
|
}
|
|
|
|
}
|
|
|
|
/* Don't delay */
|
|
return IPMIP_CALLBACK_RET_SUCCESS;
|
|
}
|
|
|
|
|
|
IP_STATIC Ip_bool
|
|
ipmipha_aaa_radius_setup(struct Ipmipha_data *ctx,
|
|
struct Ipmip_proc *proc,
|
|
int action,
|
|
void *global_config,
|
|
Ipmipha_aaa_radius_config_ifp_t *ifp_config,
|
|
void *node_config,
|
|
struct Ipmipha_node *node,
|
|
Ipmip_cli_message_t *request)
|
|
{
|
|
IPMIP_UNUSED_PARAMETER(ctx);
|
|
IPMIP_UNUSED_PARAMETER(proc);
|
|
IPMIP_UNUSED_PARAMETER(global_config);
|
|
IPMIP_UNUSED_PARAMETER(node_config);
|
|
IPMIP_UNUSED_PARAMETER(node);
|
|
IPMIP_UNUSED_PARAMETER(request);
|
|
|
|
if (action == IPMIP_CALLBACK_CONFIG_READ)
|
|
{
|
|
return ifp_config->radius != IP_NULL;
|
|
}
|
|
else if (action == IPMIP_CALLBACK_CONFIG_FREE)
|
|
{
|
|
/* No dyncamically allocated values */
|
|
}
|
|
else if (action == IPMIP_CALLBACK_CONFIG_DUMP)
|
|
{
|
|
}
|
|
|
|
return IP_FALSE;
|
|
}
|
|
|
|
|
|
IP_STATIC void
|
|
ipmipha_aaa_radius_config_ifp(struct Ipmipha_data *ctx,
|
|
struct Ipmip_proc *proc,
|
|
int action,
|
|
struct Ipmipha_iff *ifp,
|
|
void *gcfg,
|
|
Ipmipha_aaa_radius_config_ifp_t *cfg,
|
|
Ipmip_cli_message_t *request)
|
|
{
|
|
IPMIP_UNUSED_PARAMETER(ctx);
|
|
IPMIP_UNUSED_PARAMETER(proc);
|
|
IPMIP_UNUSED_PARAMETER(gcfg);
|
|
IPMIP_UNUSED_PARAMETER(request);
|
|
|
|
if (action == IPMIP_CALLBACK_CONFIG_READ)
|
|
{
|
|
if (ipmip_sysvar_bool(ipmip_sysvar_bool(IP_FALSE, "ipmipha.aaa.radius.enable"), "ipmipha.if.%s.aaa.radius.enable", ifp->iff.ipmip.ifname))
|
|
{
|
|
cfg->radius = ipmip4_radius_context_create(&ctx->ipmip4, proc, "ipmipha.aaa.radius", "ipmipha.if.%s.aaa.radius", ifp->iff.ipmip.ifname);
|
|
cfg->access = ipmip_sysvar_bool(ipmip_sysvar_bool(IP_FALSE, "ipmipha.aaa.radius.access"), "ipmipha.if.%s.aaa.radius.access", ifp->iff.ipmip.ifname);
|
|
cfg->access_require = ipmip_sysvar_bool(ipmip_sysvar_bool(IP_FALSE, "ipmipha.aaa.radius.access.required"), "ipmipha.if.%s.aaa.radius.access.required", ifp->iff.ipmip.ifname);
|
|
cfg->access_timeout = ipmip_sysvar_ulong(ipmip_sysvar_ulong(0, "ipmipha.aaa.radius.access.time_interval"), "ipmipha.if.%s.aaa.radius.access.time_interval", ifp->iff.ipmip.ifname);
|
|
cfg->accounting = ipmip_sysvar_bool(ipmip_sysvar_bool(IP_FALSE, "ipmipha.aaa.radius.accounting"), "ipmipha.if.%s.aaa.radius.accounting", ifp->iff.ipmip.ifname);
|
|
}
|
|
}
|
|
else if (action == IPMIP_CALLBACK_CONFIG_FREE)
|
|
{
|
|
if (cfg->radius)
|
|
ipmip4_radius_context_destroy(&ctx->ipmip4, proc, cfg->radius);
|
|
cfg->radius = IP_NULL;
|
|
}
|
|
else if (action == IPMIP_CALLBACK_CONFIG_DUMP)
|
|
{
|
|
if (cfg->radius)
|
|
{
|
|
ipmip_cli_config_printf(&request->message,
|
|
"ipmipha.if.%s.aaa.radius.enable=enabled",
|
|
ifp->iff.ipmip.ifname);
|
|
ipmip_cli_config_printf(&request->message,
|
|
"ipmipha.if.%s.aaa.radius.access=%s",
|
|
ifp->iff.ipmip.ifname, cfg->access? "enabled" : "disabled");
|
|
ipmip_cli_config_printf(&request->message,
|
|
"ipmipha.if.%s.aaa.radius.access.required=%s",
|
|
ifp->iff.ipmip.ifname, cfg->access_require? "enabled" : "disabled");
|
|
ipmip_cli_config_printf(&request->message,
|
|
"ipmipha.if.%s.aaa.radius.access.time_interval=%d",
|
|
ifp->iff.ipmip.ifname, cfg->access_timeout);
|
|
ipmip_cli_config_printf(&request->message,
|
|
"ipmipha.if.%s.aaa.radius.accounting=%s",
|
|
ifp->iff.ipmip.ifname, cfg->accounting? "enabled" : "disabled");
|
|
ipmip4_radius_context_dump(&ctx->ipmip4, proc, cfg->radius, request, "ipmipha.if.%s.aaa.radius", ifp->iff.ipmip.ifname);
|
|
}
|
|
else
|
|
{
|
|
ipmip_cli_config_printf(&request->message,
|
|
"ipmipha.if.%s.aaa.radius.enable=disabled",
|
|
ifp->iff.ipmip.ifname);
|
|
}
|
|
}
|
|
}
|
|
|
|
/*
|
|
*===========================================================================
|
|
* ipmipha_radius_auth
|
|
*===========================================================================
|
|
* Description: Resolve a mobile-AAA extension using RADIUS
|
|
* Parameters: ctx - Context
|
|
* proc - Current process
|
|
* setup - Setup structure
|
|
* ifcfg - Setup structure for current interface.
|
|
* pbuf - The container.
|
|
* lock - Timer lock
|
|
* func - Timer function callback
|
|
* Returns: IP_TRUE if pending, IP_FALSE otherwise
|
|
*/
|
|
IP_STATIC Ip_bool
|
|
ipmipha_aaa_radius_pkt_req_verify(struct Ipmipha_data *ctx,
|
|
struct Ipmip_proc *proc,
|
|
void *global_config,
|
|
Ipmipha_aaa_radius_config_ifp_t *ifp_config,
|
|
void *node_config,
|
|
struct Ipmipha_node *node,
|
|
struct Ipmipha_pktbuf *pbuf)
|
|
{
|
|
/* Do whatever processing is required */
|
|
/* Do we need to verify anything? */
|
|
Ipmip4_radius_packet_t *msg = IP_NULL;
|
|
int auth_type;
|
|
|
|
IPMIP_UNUSED_PARAMETER(global_config);
|
|
IPMIP_UNUSED_PARAMETER(node_config);
|
|
|
|
if (ifp_config->access)
|
|
{
|
|
if (pbuf->ipmip4.ext.mobile.mn_aaa != IP_NULL)
|
|
{
|
|
Ipmip4_ext_gen_auth_t *auth = (Ipmip4_ext_gen_auth_t *)pbuf->ipmip4.ext.mobile.mn_aaa;
|
|
Ip_u32 spi = IP_GET_NTOHL(&auth->spi[0]);
|
|
Ip_time_t now = ipmip_util_time();
|
|
|
|
pbuf->pktinfo.haBindingSPIMobileAAA = spi;
|
|
|
|
if ((unsigned)(now - pbuf->node->haNodeAAAVerificationTime) < ifp_config->access_timeout)
|
|
{
|
|
/* Verify keygen; if we have keygen in play, the keygen must match */
|
|
if (pbuf->ipmip4.ext.mobile.mn_ha_keyreq == IP_NULL)
|
|
{
|
|
/* If not keygen; there has to be security association's that correspond to the overall security policy */
|
|
if (pbuf->pktinfo.haBindingForeignHomeSAPolicyOK != 0 && pbuf->pktinfo.haBindingMobileHomeSAPolicyOK != 0)
|
|
return IP_FALSE;
|
|
}
|
|
}
|
|
|
|
/* Is it a CHAP authentication attempt? */
|
|
if (spi == IPMIP4_AUTH_SPI_CHAP_SPI)
|
|
{
|
|
/* Create the request */
|
|
if ((msg = ipmipha_aaa_radius_request(ctx, proc, ifp_config, pbuf)) == IP_NULL)
|
|
return IP_FALSE;
|
|
auth_type = IPMIP4_RADIUS_AUTH_CHAP;
|
|
}
|
|
else
|
|
{
|
|
/* Now what? */
|
|
ipmip_pktbuf_error(&pbuf->ipmip4.ipmip,
|
|
0,
|
|
"HA not able to deal with MN-AAA SPI which doesn't use CHAP");
|
|
return IP_FALSE;
|
|
}
|
|
}
|
|
else if (ifp_config->access_require)
|
|
{
|
|
/**/
|
|
/* Required MN-AAA; but it wasn't there */
|
|
ipmip_pktbuf_error(&pbuf->ipmip4.ipmip,
|
|
0,
|
|
"HA required MN-AAA, but it was not provided");
|
|
return IP_FALSE;
|
|
}
|
|
else
|
|
{
|
|
/* Continue */
|
|
return IP_FALSE;
|
|
}
|
|
|
|
/* OK; we've setup the message structure; time to invoke the access request */
|
|
if (!ipmip4_radius_access_request(&ctx->ipmip4,proc, ifp_config->radius, (Ipmip4_radius_func_t)ipmipha_aaa_radius_auth_process, msg, &pbuf->ipmip4, node, auth_type))
|
|
{
|
|
if (pbuf->ipmip4.ipmip.message == IP_NULL)
|
|
ipmip_pktbuf_error(&pbuf->ipmip4.ipmip,
|
|
0,
|
|
"FA not able to communicate with RADIUS server");
|
|
return IP_FALSE;
|
|
}
|
|
|
|
return IP_TRUE;
|
|
}
|
|
|
|
if (pbuf->ipmip4.ext.mobile.mn_aaa != IP_NULL)
|
|
return IP_FALSE;
|
|
|
|
return IP_FALSE;
|
|
}
|
|
|
|
/*
|
|
****************************************************************************
|
|
* 10 GLOBAL FUNCTIONS
|
|
****************************************************************************
|
|
*/
|
|
|
|
|
|
IP_GLOBAL void ipmipha_aaa_radius_install(void);
|
|
IP_GLOBAL void
|
|
ipmipha_aaa_radius_install(void)
|
|
{
|
|
ipcom_memset(&ipmipha_aaa_radius_srv, 0, sizeof(ipmipha_aaa_radius_srv));
|
|
|
|
ipmipha_aaa_radius_srv.name = IPMIPHA_AAA_RADIUS;
|
|
ipmipha_aaa_radius_srv.ifp_data_size = sizeof(Ipmipha_aaa_radius_config_ifp_t);
|
|
ipmipha_aaa_radius_srv.config_ifp = (Ipmipha_extension_config_ifp_t)ipmipha_aaa_radius_config_ifp;
|
|
|
|
ipmipha_aaa_radius_srv.pkt_req_validate = (Ipmipha_extension_pkt_req_validate_t)ipmipha_aaa_radius_pkt_req_verify;
|
|
ipmipha_aaa_radius_srv.pkt_rep_mobile_home = (Ipmipha_extension_pkt_req_mobile_home_t)ipmipha_aaa_radius_pkt_rep_mobile_home;
|
|
ipmipha_aaa_radius_srv.provide = (Ipmipha_extension_provide_t)ipmipha_aaa_radius_provide;
|
|
ipmipha_aaa_radius_srv.setup = (Ipmipha_extension_setup_t)ipmipha_aaa_radius_setup;
|
|
|
|
/**/
|
|
ipmipha_aaa_radius_srv.pktaux.pktbuf_data_size = sizeof(Ipmipha_aaa_radius_pktbuf_data_t);
|
|
ipmipha_aaa_radius_srv.pktaux.pktbuf_data_free = (Ipmip_pktbuf_free_data_t)ipmipha_aaa_radius_pktaux_free;
|
|
|
|
ipmipha_context_register_extension(&ipmipha_aaa_radius_srv, IPMIPHA_FUNCTION_AAA);
|
|
}
|
|
|
|
#else
|
|
IP_GLOBAL void ipmipha_aaa_radius_install(void);
|
|
IP_GLOBAL void
|
|
ipmipha_aaa_radius_install(void)
|
|
{
|
|
/* Do nothing */
|
|
}
|
|
#endif
|
|
/*
|
|
****************************************************************************
|
|
* 11 PUBLIC FUNCTIONS
|
|
****************************************************************************
|
|
*/
|
|
|
|
|
|
/*
|
|
****************************************************************************
|
|
* END OF FILE
|
|
****************************************************************************
|
|
*/
|