Files
2026-07-30 11:19:44 +05:30

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