Files
m241Neelima/components/ip_net2-6.9/ipmipha/config/ipmipha_aaa_radius.c
T
2026-07-30 11:19:44 +05:30

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
****************************************************************************
*/