972 lines
40 KiB
C
972 lines
40 KiB
C
|
|
/*
|
|
******************************************************************************
|
|
* INTERPEAK SOURCE FILE
|
|
*
|
|
* Document no: @(#) $Name: VXWORKS_ITER40_2019102207 $ $RCSfile: ipmipfa_aaa_radius.c,v $ $Revision: 1.4.16.2 $
|
|
* $Source: /home/interpeak/CVSRoot/ipmipfa/config/ipmipfa_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 "ipmipfa_config.h"
|
|
|
|
/*
|
|
****************************************************************************
|
|
* 3 INCLUDE FILES
|
|
****************************************************************************
|
|
*/
|
|
#ifdef IPMIPFA_RADIUS_ENABLE
|
|
|
|
#define IPCOM_USE_CLIB_PROTO
|
|
#include <ipcom_clib.h>
|
|
#include <ipcom_os.h>
|
|
#include <ipcom_sock.h>
|
|
#include <ipcom_sock6.h>
|
|
#include <ipcom_inet.h>
|
|
#include <ipcom_list.h>
|
|
#include <ipcom_hash.h>
|
|
#include <ipcom_err.h>
|
|
#include <ipcom_sysvar.h>
|
|
#include <ipcom_syslog.h>
|
|
#include <ipcom_shell.h>
|
|
#include <ipcom_route.h>
|
|
|
|
#include <ipnet.h>
|
|
#include <ipnet_radvd.h>
|
|
|
|
#include <ipmip.h>
|
|
#include <private/ipmip_util.h>
|
|
#include <private/ipmip_sysvar.h>
|
|
|
|
#include <ipmip4.h>
|
|
#include <private/ipmip4_context.h>
|
|
#include <private/ipmip4_util.h>
|
|
#include <private/ipmip4_sysext.h>
|
|
#include <private/ipmip4_radius.h>
|
|
|
|
#include "ipmipfa.h"
|
|
#include "ipmipfa_h.h"
|
|
#include "ipmipfa_attr_h.h"
|
|
#include "ipmipfa_if.h"
|
|
#include "ipmipfa_node.h"
|
|
#include "ipmipfa_pktbuf.h"
|
|
|
|
/*
|
|
****************************************************************************
|
|
* 4 DEFINES
|
|
****************************************************************************
|
|
*/
|
|
#define IPMIPFA_AAA_RADIUS "AAA-RADIUS"
|
|
|
|
/*
|
|
****************************************************************************
|
|
* 5 TYPES
|
|
****************************************************************************
|
|
*/
|
|
|
|
typedef struct Ipmipfa_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;
|
|
} Ipmipfa_aaa_radius_config_ifp_t;
|
|
|
|
typedef struct Ipmipfa_aaa_radius_pktbuf_data
|
|
{
|
|
Ip_bool keyrep;
|
|
char *tunnel_pwd;
|
|
Ip_u32 spi_mf_num;
|
|
Ip_u32 spi_aaa_num;
|
|
Ip_u8 nonce[16];
|
|
} Ipmipfa_aaa_radius_pktbuf_data_t;
|
|
|
|
/*
|
|
****************************************************************************
|
|
* 6 EXTERN PROTOTYPES
|
|
****************************************************************************
|
|
*/
|
|
|
|
/*
|
|
****************************************************************************
|
|
* 7 LOCAL PROTOTYPES
|
|
****************************************************************************
|
|
*/
|
|
|
|
/*
|
|
****************************************************************************
|
|
* 8 DATA
|
|
****************************************************************************
|
|
*/
|
|
static Ipmipfa_extension_t ipmipfa_aaa_radius_srv;
|
|
|
|
/*
|
|
****************************************************************************
|
|
* 9 STATIC FUNCTIONS
|
|
****************************************************************************
|
|
*/
|
|
IP_STATIC void
|
|
ipmipfa_aaa_radius_pktaux_free(struct Ipmipfa_data *data,
|
|
struct Ipmip_proc *proc,
|
|
struct Ipmipfa_pktbuf *pbuf,
|
|
Ipmipfa_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);
|
|
}
|
|
|
|
IP_STATIC void
|
|
ipmipfa_aaa_radius_acct_process(int event,
|
|
Ipmipfa_data_t *ctx,
|
|
Ipmip_proc_t *proc,
|
|
struct Ipmip4_radius_context *radius,
|
|
Ipmipfa_pktbuf_t *pbuf,
|
|
Ipmipfa_node_t *node,
|
|
Ipmip4_radius_packet_t *request,
|
|
Ipmip4_radius_packet_t *reply)
|
|
{
|
|
IPMIP_UNUSED_PARAMETER(reply);
|
|
IPMIP_UNUSED_PARAMETER(pbuf);
|
|
|
|
if (event == IPMIP4_RADIUS_ACCOUNTING_STOP)
|
|
{
|
|
Ip_u32 val;
|
|
|
|
/**** THE PBUF VARIABLE IS NOT VALID HERE; ONLY USE NODE */
|
|
|
|
/* Add username */
|
|
if (node->nai != IP_NULL)
|
|
{
|
|
ipmip4_radius_attr_add(&ctx->ipmip4,
|
|
proc,
|
|
radius,
|
|
request,
|
|
IPMIP4_RADIUS_ATTR_User_Name,
|
|
(Ip_u8*)IPMIP4_MSGEXT_SHDR_EXT_DATA(node->nai),
|
|
(Ip_u8)IPMIP4_MSGEXT_SHDR_EXT_SIZE(node->nai));
|
|
}
|
|
|
|
/* Add the FRAMED IP ADDRESS */
|
|
if (node->mib.faVisitorHomeAddress.s_addr != 0)
|
|
{
|
|
ipmip4_radius_attr_add(&ctx->ipmip4,
|
|
proc,
|
|
radius,
|
|
request,
|
|
IPMIP4_RADIUS_ATTR_Framed_IP_Address,
|
|
(Ip_u8*)&node->mib.faVisitorHomeAddress.s_addr,
|
|
(Ip_u8)sizeof(node->mib.faVisitorHomeAddress.s_addr));
|
|
}
|
|
|
|
/* Add the NAS IP address */
|
|
ipmip4_radius_attr_add(&ctx->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->faVisitorRcvOctets);
|
|
val = ip_htonl(val);
|
|
ipmip4_radius_attr_add(&ctx->ipmip4,
|
|
proc,
|
|
radius,
|
|
request,
|
|
IPMIP4_RADIUS_ACCT_Input_Octets,
|
|
(Ip_u8*)&val,
|
|
(Ip_u8)sizeof(val));
|
|
|
|
val = IP_U64_GETHI(node->faVisitorRcvOctets);
|
|
val = ip_htonl(val);
|
|
ipmip4_radius_attr_add(&ctx->ipmip4,
|
|
proc,
|
|
radius,
|
|
request,
|
|
IPMIP4_RADIUS_ACCT_Output_Gigawords,
|
|
(Ip_u8*)&val,
|
|
(Ip_u8)sizeof(val));
|
|
|
|
val = IP_U64_GETLO(node->faVisitorRcvPkts);
|
|
val = ip_htonl(val);
|
|
ipmip4_radius_attr_add(&ctx->ipmip4,
|
|
proc,
|
|
radius,
|
|
request,
|
|
IPMIP4_RADIUS_ACCT_Input_Packets,
|
|
(Ip_u8*)&val,
|
|
(Ip_u8)sizeof(val));
|
|
|
|
val = IP_U64_GETLO(node->faVisitorSndOctets);
|
|
val = ip_htonl(val);
|
|
ipmip4_radius_attr_add(&ctx->ipmip4,
|
|
proc,
|
|
radius,
|
|
request,
|
|
IPMIP4_RADIUS_ACCT_Output_Octets,
|
|
(Ip_u8*)&val,
|
|
(Ip_u8)sizeof(val));
|
|
|
|
val = IP_U64_GETHI(node->faVisitorSndOctets);
|
|
val = ip_htonl(val);
|
|
ipmip4_radius_attr_add(&ctx->ipmip4,
|
|
proc,
|
|
radius,
|
|
request,
|
|
IPMIP4_RADIUS_ACCT_Output_Gigawords,
|
|
(Ip_u8*)&val,
|
|
(Ip_u8)sizeof(val));
|
|
|
|
val = IP_U64_GETLO(node->faVisitorSndPkts);
|
|
val = ip_htonl(val);
|
|
ipmip4_radius_attr_add(&ctx->ipmip4,
|
|
proc,
|
|
radius,
|
|
request,
|
|
IPMIP4_RADIUS_ACCT_Output_Packets,
|
|
(Ip_u8*)&val,
|
|
(Ip_u8)sizeof(val));
|
|
|
|
val = (Ip_u32)(ipmip_util_time() - node->faVisitorCreationTime);
|
|
val = ip_htonl(val);
|
|
ipmip4_radius_attr_add(&ctx->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 != IP_NULL)
|
|
{
|
|
ipmip4_radius_attr_add(&ctx->ipmip4,
|
|
proc,
|
|
radius,
|
|
request,
|
|
IPMIP4_RADIUS_ATTR_User_Name,
|
|
(Ip_u8*)IPMIP4_MSGEXT_SHDR_EXT_DATA(node->nai),
|
|
(Ip_u8)IPMIP4_MSGEXT_SHDR_EXT_SIZE(node->nai));
|
|
}
|
|
|
|
/* Add the FRAMED IP ADDRESS */
|
|
if (node->mib.faVisitorHomeAddress.s_addr != 0)
|
|
{
|
|
ipmip4_radius_attr_add(&ctx->ipmip4,
|
|
proc,
|
|
radius,
|
|
request,
|
|
IPMIP4_RADIUS_ATTR_Framed_IP_Address,
|
|
(Ip_u8*)&node->mib.faVisitorHomeAddress.s_addr,
|
|
(Ip_u8)sizeof(node->mib.faVisitorHomeAddress.s_addr));
|
|
}
|
|
|
|
/* Add the NAS IP address */
|
|
ipmip4_radius_attr_add(&ctx->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(INFO, proc,
|
|
ipmip_log_event_add(&ctx->ipmip4.ipmip,
|
|
proc,
|
|
"Node %s RADIUS accounting started",
|
|
ipmipfa_node_describe(proc, node)));
|
|
|
|
/* Is it our start? */
|
|
node->faVisitorAccounting = 1;
|
|
ipmip_timer_execute(&ctx->ipmip4.ipmip, &node->service);
|
|
}
|
|
else if (event == IPMIP4_RADIUS_ACCOUNTING_STOP_RESPONSE)
|
|
{
|
|
IPMIP4_EVENT_IF(INFO, proc,
|
|
ipmip_log_event_add(&ctx->ipmip4.ipmip,
|
|
proc,
|
|
"Node %s RADIUS accounting stopped",
|
|
ipmipfa_node_describe(proc, node)));
|
|
/* Is it our start? */
|
|
ipmip_timer_execute(&ctx->ipmip4.ipmip, &node->service);
|
|
}
|
|
else
|
|
{
|
|
/* SOME KIND OF ERROR */
|
|
IPMIP4_EVENT_IF(WARNING, proc,
|
|
ipmip_log_event_add(&ctx->ipmip4.ipmip,
|
|
proc,
|
|
"Node %s RADIUS accounting failed",
|
|
ipmipfa_node_describe(proc, node)));
|
|
|
|
ipmip_timer_execute(&ctx->ipmip4.ipmip, &node->service);
|
|
}
|
|
}
|
|
|
|
IP_STATIC void
|
|
ipmipfa_aaa_radius_auth_process(int event,
|
|
Ipmipfa_data_t *ctx,
|
|
Ipmip_proc_t *proc,
|
|
struct Ipmip4_radius_context *radius,
|
|
Ipmipfa_pktbuf_t *pbuf,
|
|
Ipmipfa_node_t *node,
|
|
Ipmip4_radius_packet_t *request,
|
|
Ipmip4_radius_packet_t *reply)
|
|
{
|
|
IPMIP_UNUSED_PARAMETER(node);
|
|
if (event == IPMIP4_RADIUS_ACCESS_REQUEST_SUCCESS)
|
|
{
|
|
Ipmipfa_aaa_radius_pktbuf_data_t *aaa = ipmip_pktbuf_pktaux_data_get(&ctx->ipmip4.ipmip, &pbuf->ipmip4.ipmip, ipmipfa_aaa_radius_srv.pktaux.pktbuf_data_index, IP_TRUE);
|
|
Ip_u8 *attr = IP_NULL;
|
|
/**/
|
|
|
|
if(IP_NULL == aaa)
|
|
return;
|
|
|
|
IPMIP4_EVENT_IF(INFO, proc,
|
|
ipmip_log_event_add(&ctx->ipmip4.ipmip,
|
|
proc,
|
|
"Node %s RADIUS authorization accepted",
|
|
ipmipfa_node_describe(proc, node)));
|
|
|
|
|
|
/* Go through the attributes */
|
|
while ((attr = ipmip4_radius_attr_next(&ctx->ipmip4, proc, radius, reply, attr)) != IP_NULL)
|
|
{
|
|
/**/
|
|
switch (IPMIP4_RADIUS_ATTR_TYPE(attr))
|
|
{
|
|
case IPMIP4_RADIUS_ATTR_Framed_IP_Address:
|
|
#if 0
|
|
IPCOM_LOG3(DEBUG2, "Extension: %d/%d Framed IP Address = %s",
|
|
attr[0],
|
|
attr[1],
|
|
ipmip_ntop_inet(proc, IP_GET_32ON8(IPMIP4_RADIUS_ATTR_DATA(attr, 0))));
|
|
#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(&ctx->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->reginfo.faVisitorResolvedHomeAgent = 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->reginfo.faVisitorResolvedHomeAgent);
|
|
#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:
|
|
break;
|
|
case IPMIP4_RADIUS_VENDOR_3GPP2_MN_AAA_Removal_Indication:
|
|
#if 0
|
|
IPCOM_LOG2(DEBUG2, "Extension: %d/%d (VSA) Vendor = 3GPP2, MN-AAA Removal Indication",
|
|
IPMIP4_RADIUS_ATTR_TYPE(attr),
|
|
IPMIP4_RADIUS_ATTR_LEN(attr));
|
|
#endif
|
|
|
|
/* Discard anything outside the inner authentication */
|
|
ipmip_buffer_shrink(&pbuf->ipmip4.ipmip.packet,
|
|
((Ip_u8 *)pbuf->pktinfo.faVisitorInnerAuth - (Ip_u8 *)IPMIP_BUFFER_DATA(&pbuf->ipmip4.ipmip.packet)) + pbuf->pktinfo.faVisitorInnerAuthSize);
|
|
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;
|
|
|
|
}
|
|
}
|
|
|
|
/**/
|
|
/* Do we have a tunnel password? */
|
|
if (pbuf->ipmip4.ext.mobile.mn_fa_keyreq != IP_NULL && 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_fa_keyreq;
|
|
Ip_u32 i;
|
|
void *ident;
|
|
|
|
aaa->spi_mf_num = IP_GET_NTOHL(&keyreq->spi);
|
|
aaa->spi_aaa_num = IP_GET_NTOHL(&auth->spi[0]);
|
|
|
|
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.faVisitorHomeAddress;
|
|
i = sizeof(pbuf->pktinfo.faVisitorHomeAddress);
|
|
}
|
|
|
|
/* Create the SPI */
|
|
if (node->faVisitorMobileSA)
|
|
ipmip4_auth_spi_free(node->faVisitorMobileSA);
|
|
|
|
/* Claim it */
|
|
node->faVisitorMobileSA = ipmip4_auth_spi_generate(&ctx->ipmip4,
|
|
proc,
|
|
aaa->spi_mf_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 authorization request failed");
|
|
}
|
|
|
|
/* Are we satisfied? */
|
|
if (pbuf->ipmip4.ipmip.message == IP_NULL)
|
|
pbuf->node->faVisitorAAAVerificationTime = ipmip_util_time();
|
|
ipmip_timer_execute(&ctx->ipmip4.ipmip, &pbuf->node->service);
|
|
}
|
|
|
|
/*
|
|
*===========================================================================
|
|
* ipmipfa_radius_request
|
|
*===========================================================================
|
|
* Description: Create the basic parts of a radius access-request
|
|
* Parameters:
|
|
* Returns:
|
|
*
|
|
*/
|
|
IP_STATIC Ipmip4_radius_packet_t *
|
|
ipmipfa_aaa_radius_request(Ipmipfa_data_t *ctx,
|
|
Ipmip_proc_t *proc,
|
|
Ipmipfa_aaa_radius_config_ifp_t *ifp_config,
|
|
Ipmipfa_pktbuf_t *pbuf)
|
|
{
|
|
Ipmip4_radius_packet_t *msg = ipmip4_radius_access_request_init(&ctx->ipmip4, proc, ifp_config->radius);
|
|
|
|
if (msg == IP_NULL)
|
|
{
|
|
ipmip_pktbuf_error(&pbuf->ipmip4.ipmip,
|
|
0,
|
|
"FA 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(&ctx->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));
|
|
}
|
|
|
|
/* Add the FRAMED IP ADDRESS */
|
|
if (pbuf->pktinfo.faVisitorHomeAddress != 0)
|
|
{
|
|
ipmip4_radius_attr_add(&ctx->ipmip4,
|
|
proc,
|
|
ifp_config->radius,
|
|
msg,
|
|
IPMIP4_RADIUS_ATTR_Framed_IP_Address,
|
|
(Ip_u8*)&pbuf->pktinfo.faVisitorHomeAddress,
|
|
(Ip_u8)sizeof(pbuf->pktinfo.faVisitorHomeAddress));
|
|
}
|
|
|
|
/* Add the 3GPP2 VENDOR extension for Foreign Agent Address */
|
|
ipmip4_radius_attr_vendor_add(&ctx->ipmip4,
|
|
proc,
|
|
ifp_config->radius,
|
|
msg,
|
|
IPMIP4_RADIUS_VENDOR_3GGP2,
|
|
IPMIP4_RADIUS_VENDOR_3GPP2_Foreign_Agent_Address,
|
|
&pbuf->reginfo.faVisitorCOA,
|
|
4);
|
|
|
|
/* Add the 3GPP2 Home Agent extension */
|
|
if (pbuf->pktinfo.faVisitorHomeAgentAddress)
|
|
{
|
|
/* There's an explicit address requested */
|
|
ipmip4_radius_attr_vendor_add(&ctx->ipmip4,
|
|
proc,
|
|
ifp_config->radius,
|
|
msg,
|
|
IPMIP4_RADIUS_VENDOR_3GGP2,
|
|
IPMIP4_RADIUS_VENDOR_3GPP2_Home_Agent_IP_Address,
|
|
&pbuf->pktinfo.faVisitorHomeAgentAddress,
|
|
4);
|
|
}
|
|
else
|
|
{
|
|
/* DHAA? Should I add it? */
|
|
ipmip4_radius_attr_vendor_add(&ctx->ipmip4,
|
|
proc,
|
|
ifp_config->radius,
|
|
msg,
|
|
IPMIP4_RADIUS_VENDOR_3GGP2,
|
|
IPMIP4_RADIUS_VENDOR_3GPP2_Home_Agent_IP_Address,
|
|
&pbuf->pktinfo.faVisitorHomeAgentAddressRequested,
|
|
4);
|
|
}
|
|
|
|
|
|
/* Add the NAS IP address */
|
|
ipmip4_radius_attr_add(&ctx->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 Ip_bool
|
|
ipmipfa_aaa_radius_pkt_req_verify(struct Ipmipfa_data *ctx,
|
|
struct Ipmip_proc *proc,
|
|
void *global_config,
|
|
Ipmipfa_aaa_radius_config_ifp_t *ifp_config,
|
|
void *node_config,
|
|
struct Ipmipfa_node *node,
|
|
struct Ipmipfa_pktbuf *pbuf)
|
|
{
|
|
/* 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();
|
|
|
|
/* Store the SPI for bookkeeping */
|
|
pbuf->reginfo.faVisitorSPIMobileAAA = spi;
|
|
|
|
/* Still in effect? */
|
|
if ((unsigned)(now - pbuf->node->faVisitorAAAVerificationTime) < 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 && pbuf->ipmip4.ext.mobile.mn_fa_keyreq == IP_NULL)
|
|
{
|
|
/* If not keygen; there has to be security association's that correspond to the overall security policy */
|
|
if (pbuf->pktinfo.faVisitorMobileForeignSAPolicyOK != 0 && pbuf->pktinfo.faVisitorMobileHomeSAPolicyOK != 0)
|
|
return IP_FALSE;
|
|
}
|
|
}
|
|
|
|
|
|
/* Is it a CHAP authentication attempt? */
|
|
if (spi == IPMIP4_AUTH_SPI_CHAP_SPI)
|
|
{
|
|
/* Create the request */
|
|
if ((msg = ipmipfa_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,
|
|
"FA 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,
|
|
"FA 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)ipmipfa_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;
|
|
}
|
|
|
|
/**/
|
|
return IP_FALSE;
|
|
}
|
|
|
|
|
|
IP_STATIC void
|
|
ipmipfa_aaa_radius_pkt_rep_forward(struct Ipmipfa_data *ctx,
|
|
struct Ipmip_proc *proc,
|
|
void *global_config,
|
|
Ipmipfa_aaa_radius_config_ifp_t *ifp_config,
|
|
void *node_config,
|
|
struct Ipmipfa_node *node,
|
|
struct Ipmipfa_pktbuf *pbuf)
|
|
{
|
|
Ipmipfa_aaa_radius_pktbuf_data_t *aaa = ipmip_pktbuf_pktaux_data_get(&ctx->ipmip4.ipmip, &pbuf->ipmip4.ipmip, ipmipfa_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_fa_t *keyrep = (Ipmip4_ext_keyrep_fa_t *)proc->ntop.ntop_pbuf;
|
|
|
|
ipcom_memset(keyrep, 0, sizeof(*keyrep));
|
|
|
|
/**/
|
|
keyrep->type = IPMIP4_EXT_TYPE_MN_FA_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->length, (IPMIP4_EXT_KEYREP_FA_LENGTH + 16 - IPMIP4_MSGEXT_LHDR_HDR_SIZE));
|
|
IP_SET_HTONL(&keyrep->aaa_spi, aaa->spi_aaa_num);
|
|
IP_SET_HTONL(&keyrep->spi, aaa->spi_mf_num);
|
|
|
|
/**/
|
|
ipcom_memcpy(&keyrep->nonce[0], &aaa->nonce[0], 16);
|
|
|
|
/* Append keygen material */
|
|
ipmip4_msgext_buffer_append_lhdr(&pbuf->ipmip4.ipmip.packet, (void *)proc->ntop.ntop_pbuf);
|
|
}
|
|
}
|
|
|
|
|
|
/**/
|
|
IP_STATIC int
|
|
ipmipfa_aaa_radius_provide(struct Ipmipfa_data *ctx,
|
|
struct Ipmip_proc *proc,
|
|
int action,
|
|
void *global_config,
|
|
Ipmipfa_aaa_radius_config_ifp_t *ifp_config,
|
|
void *node_config,
|
|
struct Ipmipfa_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)ipmipfa_aaa_radius_acct_process,
|
|
node->faVisitorIdentity,
|
|
IP_NULL,
|
|
node))
|
|
|
|
{
|
|
|
|
IPMIP4_EVENT_IF(ERR, proc,
|
|
ipmip_log_event_add(&ctx->ipmip4.ipmip,
|
|
proc,
|
|
"FA 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)
|
|
{
|
|
/* Is accounting enabled? */
|
|
if (node->faVisitorAccounting)
|
|
{
|
|
if (ifp_config->radius != IP_NULL)
|
|
{
|
|
/* Must terminate the accounting session */
|
|
if (!ipmip4_radius_accounting_stop(&ctx->ipmip4,
|
|
proc,
|
|
ifp_config->radius,
|
|
node->faVisitorIdentity))
|
|
return IPMIP_CALLBACK_RET_FAILED;
|
|
|
|
return IPMIP_CALLBACK_RET_PENDING;
|
|
}
|
|
}
|
|
}
|
|
|
|
/* Don't delay */
|
|
return IPMIP_CALLBACK_RET_SUCCESS;
|
|
}
|
|
|
|
IP_STATIC Ip_bool
|
|
ipmipfa_aaa_radius_setup(struct Ipmipfa_data *ctx,
|
|
struct Ipmip_proc *proc,
|
|
int action,
|
|
void *global_config,
|
|
Ipmipfa_aaa_radius_config_ifp_t *ifp_config,
|
|
void *node_config,
|
|
struct Ipmipfa_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
|
|
ipmipfa_aaa_radius_config_ifp(struct Ipmipfa_data *ctx,
|
|
struct Ipmip_proc *proc,
|
|
int action,
|
|
struct Ipmipfa_iff *ifp,
|
|
void *gcfg,
|
|
Ipmipfa_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, "ipmipfa.aaa.radius.enable"), "ipmipfa.if.%s.aaa.radius.enable", ifp->iff.ipmip.ifname))
|
|
{
|
|
cfg->radius = ipmip4_radius_context_create(&ctx->ipmip4, proc, "ipmipfa.aaa.radius", "ipmipfa.if.%s.aaa.radius", ifp->iff.ipmip.ifname);
|
|
cfg->access = ipmip_sysvar_bool(ipmip_sysvar_bool(IP_FALSE, "ipmipfa.aaa.radius.access"), "ipmipfa.if.%s.aaa.radius.access", ifp->iff.ipmip.ifname);
|
|
cfg->access_require = ipmip_sysvar_bool(ipmip_sysvar_bool(IP_FALSE, "ipmipfa.aaa.radius.access.required"), "ipmipfa.if.%s.aaa.radius.access.required", ifp->iff.ipmip.ifname);
|
|
cfg->access_timeout = ipmip_sysvar_ulong(ipmip_sysvar_ulong(0, "ipmipfa.aaa.radius.access.time_interval"), "ipmipfa.if.%s.aaa.radius.access.time_interval", ifp->iff.ipmip.ifname);
|
|
cfg->accounting = ipmip_sysvar_bool(ipmip_sysvar_bool(IP_FALSE, "ipmipfa.aaa.radius.accounting"), "ipmipfa.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,
|
|
"ipmipfa.if.%s.aaa.radius.enable=enabled",
|
|
ifp->iff.ipmip.ifname);
|
|
ipmip_cli_config_printf(&request->message,
|
|
"ipmipfa.if.%s.aaa.radius.access=%s",
|
|
ifp->iff.ipmip.ifname, cfg->access? "enabled" : "disabled");
|
|
ipmip_cli_config_printf(&request->message,
|
|
"ipmipfa.if.%s.aaa.radius.access.required=%s",
|
|
ifp->iff.ipmip.ifname, cfg->access_require? "enabled" : "disabled");
|
|
ipmip_cli_config_printf(&request->message,
|
|
"ipmipfa.if.%s.aaa.radius.access.time_interval=%d",
|
|
ifp->iff.ipmip.ifname, cfg->access_timeout);
|
|
ipmip_cli_config_printf(&request->message,
|
|
"ipmipfa.if.%s.aaa.radius.accounting=%s",
|
|
ifp->iff.ipmip.ifname, cfg->accounting? "enabled" : "disabled");
|
|
ipmip4_radius_context_dump(&ctx->ipmip4, proc, cfg->radius, request, "ipmipfa.if.%s.aaa.radius", ifp->iff.ipmip.ifname);
|
|
}
|
|
else
|
|
{
|
|
ipmip_cli_config_printf(&request->message,
|
|
"ipmipfa.if.%s.aaa.radius.enable=disabled",
|
|
ifp->iff.ipmip.ifname);
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
/*
|
|
****************************************************************************
|
|
* 10 GLOBAL FUNCTIONS
|
|
****************************************************************************
|
|
*/
|
|
|
|
IP_GLOBAL void ipmipfa_aaa_radius_install(void);
|
|
IP_GLOBAL void
|
|
ipmipfa_aaa_radius_install(void)
|
|
{
|
|
ipcom_memset(&ipmipfa_aaa_radius_srv, 0, sizeof(ipmipfa_aaa_radius_srv));
|
|
|
|
ipmipfa_aaa_radius_srv.name = IPMIPFA_AAA_RADIUS;
|
|
ipmipfa_aaa_radius_srv.ifp_data_size = sizeof(Ipmipfa_aaa_radius_config_ifp_t);
|
|
ipmipfa_aaa_radius_srv.config_ifp = (Ipmipfa_extension_config_ifp_t)ipmipfa_aaa_radius_config_ifp;
|
|
|
|
ipmipfa_aaa_radius_srv.pkt_req_validate = (Ipmipfa_extension_pkt_req_validate_t)ipmipfa_aaa_radius_pkt_req_verify;
|
|
ipmipfa_aaa_radius_srv.pkt_rep_forward = (Ipmipfa_extension_pkt_rep_forward_t)ipmipfa_aaa_radius_pkt_rep_forward;
|
|
ipmipfa_aaa_radius_srv.provide = (Ipmipfa_extension_provide_t)ipmipfa_aaa_radius_provide;
|
|
ipmipfa_aaa_radius_srv.setup = (Ipmipfa_extension_setup_t)ipmipfa_aaa_radius_setup;
|
|
|
|
/**/
|
|
ipmipfa_aaa_radius_srv.pktaux.pktbuf_data_size = sizeof(Ipmipfa_aaa_radius_pktbuf_data_t);
|
|
ipmipfa_aaa_radius_srv.pktaux.pktbuf_data_free = (Ipmip_pktbuf_free_data_t)ipmipfa_aaa_radius_pktaux_free;
|
|
|
|
ipmipfa_context_register_extension(&ipmipfa_aaa_radius_srv, IPMIPFA_FUNCTION_AAA);
|
|
}
|
|
|
|
#else
|
|
IP_GLOBAL void ipmipfa_aaa_radius_install(void);
|
|
IP_GLOBAL void
|
|
ipmipfa_aaa_radius_install(void)
|
|
{
|
|
/* Do nothing */
|
|
}
|
|
#endif
|
|
|
|
/*
|
|
****************************************************************************
|
|
* 11 PUBLIC FUNCTIONS
|
|
****************************************************************************
|
|
*/
|
|
|
|
/*
|
|
****************************************************************************
|
|
* END OF FILE
|
|
****************************************************************************
|
|
*/
|