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

1252 lines
41 KiB
C

/*
******************************************************************************
* INTERPEAK SOURCE FILE
*
* Document no: @(#) $Name: VXWORKS_ITER40_2019102207 $ $RCSfile: ipmip4_ipradius.c,v $ $Revision: 1.18.16.3 $
* $Source: /home/interpeak/CVSRoot/ipmip4/config/ipmip4_ipradius.c,v $
* $Author: jsheng $
* $State: Exp $ $Locker: $
*
* INTERPEAK_COPYRIGHT_STRING
* Design and implementation by Joel Hortelius <joel.hortelis@interpeak.se>
******************************************************************************
*/
#ifdef IPRADIUS
/*
****************************************************************************
* 1 DESCRIPTION
****************************************************************************
*/
/*
****************************************************************************
* 2 CONFIGURATION
****************************************************************************
*/
#include "ipmip4_config.h"
/*
****************************************************************************
* 3 INCLUDE FILES
****************************************************************************
*/
#define IPCOM_USE_CLIB_PROTO
#include <ipcom_clib.h>
#include <ipcom_clib2.h>
#include <ipcom_err.h>
#include <ipcom_inet.h>
#include <ipcom_ipd.h>
#include <ipcom_list.h>
#include <ipcom_hash.h>
#include <ipcom_os.h>
#include <ipcom_sock.h>
#include <ipcom_sock.h>
#include <ipcom_sock2.h>
#include <ipcom_sysctl.h>
#include <ipcom_syslog.h>
#include <ipcom_sysvar.h>
#include <ipradius.h>
#include <ipmip.h>
#include <private/ipmip_buffer.h>
#include <private/ipmip_cli.h>
#include "ipmip4.h"
#include <private/ipmip4_radius.h>
#include <private/ipmip4_context.h>
#include <private/ipmip4_sysext.h>
#include <private/ipmip4_pktbuf.h>
#include <private/ipmip4_util.h>
#if defined(IPMCRYPTO)
#include <ip/openssl/md5.h>
#else
#include <openssl/md5.h>
#endif
/*
****************************************************************************
* 4 DEFINES
****************************************************************************
*/
#define IPMIP4_IPRADIUS_BUFFER_SIZE 4096
#define IPMIP4_IPRADIUS_AUTH_SIZE 16
#ifdef IPCOM_SYSLOG_PRIORITY
#undef IPCOM_SYSLOG_PRIORITY
#endif
#define IPCOM_SYSLOG_PRIORITY IPMIP4_SYSTEM_PRIORITY
#ifdef IPCOM_SYSLOG_FACILITY
#undef IPCOM_SYSLOG_FACILITY
#endif
#define IPCOM_SYSLOG_FACILITY IPCOM_LOG_IPMIP
/*
****************************************************************************
* 5 TYPES
****************************************************************************
*/
typedef struct Ipmip4_ipradius_server
{
Ipradius_server auth;
Ipradius_server acct;
struct Ip_sockaddr_in lcl;
Ip_fd fd;
Ip_u32 msgid;
} Ipmip4_ipradius_server_t;
typedef struct Ipmip4_radius_context
{
Ipmip4_ipradius_server_t radius;
Ipcom_mutex lock;
struct Ipmip4_context *ctx;
Ipmip4_msgext_uhdr_t *nai;
/* User password */
char *pwd;
Ip_size_t pwd_len;
/* The procs I need for this particular context */
struct Ipmip_proc *proc;
struct Ipmip_proc *tmo2_proc;
} Ipmip4_radius_context_t;
/* Data required to properly handle the callback */
typedef struct Ipmip4_ipradius_cookie
{
Ipmip4_radius_func_t func;
Ipmip4_radius_context_t *radius;
Ipmip4_pktbuf_t *pbuf;
void *arg;
} Ipmip4_ipradius_cookie_t;
/* Data required to properly handle the callback */
typedef struct Ipmip4_ipradius_acct_cookie
{
Ipmip4_radius_func_t func;
Ipmip4_radius_context_t *radius;
Ipmip4_pktbuf_t *pbuf;
void *arg;
int state;
} Ipmip4_ipradius_acct_cookie_t;
/*
****************************************************************************
* 6 EXTERN PROTOTYPES
****************************************************************************
*/
/*
****************************************************************************
* 7 LOCAL PROTOTYPES
****************************************************************************
*/
/*
****************************************************************************
* 8 DATA
****************************************************************************
*/
/* A link symbol */
int ipmip4_ipradius_link_symbol;
/*
****************************************************************************
* 9 STATIC FUNCTIONS
****************************************************************************
*/
/*
*===========================================================================
* ipmip4_radius_event_callback
*===========================================================================
*/
IP_STATIC Ip_err
ipmip4_radius_event_callback(int event,
Ipradius_request* request,
Ipradius_header* request_packet,
Ipradius_header* response_packet,
Ipradius_server* server)
{
Ipmip4_ipradius_cookie_t *cookie = request->cookie;
Ipmip_proc_t *proc;
/* Select an appropriate proc structure */
if (ipcom_getpid() == cookie->radius->proc->pid)
proc = cookie->radius->proc;
else
proc = cookie->radius->tmo2_proc;
IPMIP_UNUSED_PARAMETER(request);
IPMIP_UNUSED_PARAMETER(server);
switch(event)
{
case IPRADIUS_EVENT_ACCESS_ACCEPT:
(*cookie->func) (IPMIP4_RADIUS_ACCESS_REQUEST_SUCCESS, cookie->radius->ctx, proc, cookie->radius, cookie->pbuf, cookie->arg, request_packet, response_packet);
break;
case IPRADIUS_EVENT_ACCESS_REJECT:
case IPRADIUS_EVENT_ACCESS_CHALLENGE:
case IPRADIUS_EVENT_ACCESS_TIMEOUT:
case IPRADIUS_EVENT_ACCESS_CANCELLED:
(*cookie->func) (IPMIP4_RADIUS_ACCESS_REQUEST_FAILURE, cookie->radius->ctx, proc, cookie->radius, cookie->pbuf, cookie->arg, request_packet, response_packet);
break;
default:
IP_PANIC();
break;
}
ipcom_free(cookie);
return IPCOM_SUCCESS;
}
/*
*===========================================================================
* ipmip4_radius_event_callback
*===========================================================================
*/
IP_STATIC Ip_err
ipmip4_radius_acct_callback(int event,
Ipradius_request* request,
Ipradius_header* request_packet,
Ipradius_header* response_packet,
Ipradius_server* server)
{
Ipmip4_ipradius_acct_cookie_t *cookie = request->cookie;
Ipmip_proc_t *proc;
Ip_u32 type;
/* Select an appropriate proc structure */
if (ipcom_getpid() == cookie->radius->proc->pid)
proc = cookie->radius->proc;
else
proc = cookie->radius->tmo2_proc;
IPMIP_UNUSED_PARAMETER(request);
IPMIP_UNUSED_PARAMETER(server);
switch(event)
{
case IPRADIUS_EVENT_ACCOUNTING_RESPONSE:
if (cookie->state == IPRADIUS_ACCT_Stop)
(*cookie->func) (IPMIP4_RADIUS_ACCOUNTING_STOP_RESPONSE, cookie->radius->ctx, proc, cookie->radius, IP_NULL, cookie->arg, request_packet, response_packet);
else
{
(*cookie->func) (IPMIP4_RADIUS_ACCOUNTING_START_RESPONSE, cookie->radius->ctx, proc, cookie->radius, cookie->pbuf, cookie->arg, request_packet, response_packet);
cookie->pbuf = IP_NULL;
return IPCOM_SUCCESS;
}
break;
case IPRADIUS_EVENT_ACCOUNTING_REQUEST:
if (ipradius_attr_get_u32(request_packet, IPRADIUS_ATTR_Acct_Status_Type, &type) != IPCOM_SUCCESS)
{
IPCOM_LOG0(ERR, "UNABLE TO LOCATE ACCOUNTING TYPE");
return IPCOM_SUCCESS;
}
/**/
switch (type)
{
case IPRADIUS_ACCT_Start:
(*cookie->func) (IPMIP4_RADIUS_ACCOUNTING_START, cookie->radius->ctx, proc, cookie->radius, cookie->pbuf, cookie->arg, request_packet, response_packet);
cookie->state = IPRADIUS_ACCT_Start;
break;
case IPRADIUS_ACCT_Stop:
(*cookie->func) (IPMIP4_RADIUS_ACCOUNTING_STOP, cookie->radius->ctx, proc, cookie->radius, cookie->pbuf, cookie->arg, request_packet, response_packet);
cookie->state = IPRADIUS_ACCT_Stop;
cookie->pbuf = IP_NULL;
break;
default:
IPCOM_LOG1(ERR, "UNKNOWN ACCOUNTING TYPE %d", type);
break;
}
return IPCOM_SUCCESS;
case IPRADIUS_EVENT_ACCOUNTING_CANCELLED:
case IPRADIUS_EVENT_ACCOUNTING_TIMEOUT:
(*cookie->func) (IPMIP4_RADIUS_ACCOUNTING_FAILED, cookie->radius->ctx, proc, cookie->radius, cookie->pbuf, cookie->arg, request_packet, IP_NULL);
break;
default:
IP_PANIC();
break;
}
ipcom_free(cookie);
return IPCOM_SUCCESS;
}
IP_STATIC void
ipmip4_radius_proc(Ipmip4_context_t *ctx,
Ipmip_proc_t *proc,
Ipmip4_radius_context_t *radius)
{
char *radbuf = ipcom_malloc(IPMIP4_IPRADIUS_BUFFER_SIZE);
IPMIP_UNUSED_PARAMETER(ctx);
/*********** tick loop ***********/
for (; proc->quit != IP_TRUE;)
{
Ip_fd_set rset;
int ret;
struct Ip_timeval tv;
/* Clear it */
IP_FD_ZERO(&rset);
/* Add the client socket */
IP_FD_SET(radius->radius.fd, &rset);
tv.tv_sec = 0;
tv.tv_usec = 200 * 1000;
ret = ipcom_socketselect(radius->radius.fd + 1, &rset, IP_NULL, IP_NULL, &tv);
/* Timeout */
if (ret == 0)
continue;
else if (ret < 0)
{
IPCOM_LOG2(WARNING, "radius context socketselect() failed : %s [%d]", ipcom_strerror(ipcom_errno), ipcom_errno);
break;
}
else
{
struct Ip_sockaddr_in sin4;
Ip_socklen_t sin4_len = sizeof(sin4);
/* Time to read */
ret = ipcom_recvfrom(radius->radius.fd, radbuf, IPMIP4_IPRADIUS_BUFFER_SIZE, 0, (struct Ip_sockaddr *)&sin4, &sin4_len);
if (ret <= 0)
{
IPCOM_LOG2(WARNING, "radius context recvfrom() failed : %s [%d]", ipcom_strerror(ipcom_errno), ipcom_errno);
}
else
{
ret = ipradius_read((Ipradius_header*)radbuf, ret, (struct Ip_sockaddr *)&sin4);
if (ret != IPCOM_SUCCESS)
IPCOM_LOG0(ERR, "radius - input parsing failed");
}
}
}
ipcom_free(radbuf);
}
/*
*===========================================================================
* ipmip4_radius_access_request_chap_auth
*===========================================================================
* Description: Add CHAP specific radius authentication VSE's based on the
* packet buffer.
* Parameters: ctx - Context
* proc - Current process
* radius - Radius context
* pbuf - Packet buffer
* msg - Radius access request buffer
* Returns: IP_TRUE on success
*
*/
IP_STATIC Ip_bool
ipmip4_radius_access_request_chap_auth(struct Ipmip4_context *ctx,
struct Ipmip_proc *proc,
Ipmip4_radius_context_t *radius,
Ipmip4_pktbuf_t *pbuf,
Ipmip4_radius_packet_t *omsg)
{
Ipmip4_ext_gen_auth_t *auth = (Ipmip4_ext_gen_auth_t *)pbuf->ext.mobile.mn_aaa;
Ip_size_t auth_size = IPMIP4_MSGEXT_LHDR_EXT_SIZE(pbuf->ext.mobile.mn_aaa);
Ipradius_header *msg = omsg;
IPMIP_UNUSED_PARAMETER(ctx);
IPMIP_UNUSED_PARAMETER(radius);
/* We're not interested in the SPI field; only the authenticator */
auth_size -= 4;
if (auth_size > 128)
{
ipmip_pktbuf_error(&pbuf->ipmip,
0,
"Authentication extension too large in RRQ; unable to handle");
return IP_FALSE;
}
else
{
Ip_u8 *ptr;
Ip_size_t size;
MD5_CTX md5;
Ip_u8 zero = 0;
/* Add the CHAP challenge */
MD5_Init(&md5);
ptr = IPMIP_BUFFER_PTR(&pbuf->ipmip.packet);
size = (Ip_size_t)((char *)pbuf->ext.mobile.mn_aaa - (char *)ptr) + IPMIP4_EXT_GENAUTHHDR_LENGTH;
MD5_Update(&md5, ptr, size);
MD5_Final((unsigned char *)proc->ntop.ntop_pbuf, &md5);
if (pbuf->ext.mobile.challenge == IP_NULL || IPMIP4_MSGEXT_SHDR_EXT_SIZE(pbuf->ext.mobile.challenge) == 0)
{
ptr = &zero;
size = 1;
}
else
{
/* Add the 237 low bytes of the challenge */
ptr = IPMIP4_MSGEXT_SHDR_EXT_DATA(pbuf->ext.mobile.challenge);
size = IPMIP4_MSGEXT_SHDR_EXT_SIZE(pbuf->ext.mobile.challenge);
}
if (size < 238)
ipcom_memcpy(&proc->ntop.ntop_pbuf[16], ptr, size);
else
{
Ip_size_t diff = size - 237;
size -= diff;
ipcom_memcpy(&proc->ntop.ntop_pbuf[16], ptr + diff, size);
}
/* Add the MD5 hash */
size += 16;
(void)ipradius_attr_add_array(msg,
IPRADIUS_ATTR_CHAP_Challenge,
(Ip_u8*)&proc->ntop.ntop_pbuf[0],
(Ip_u8)size);
proc->ntop.ntop_pbuf[0] = ptr[0];
ipcom_memcpy(&proc->ntop.ntop_pbuf[1], &auth->authenticator[0], auth_size);
/* Add the CHAP challenge */
(void)ipradius_attr_add_array(msg,
IPRADIUS_ATTR_CHAP_Password,
(Ip_u8*)proc->ntop.ntop_pbuf,
(Ip_u8)auth_size + 1);
return IP_TRUE;
}
}
IP_STATIC void
ipmip4_radius_dump_server(struct Ipmip_proc *proc,
Ipmip_cli_message_t *request,
Ipradius_server *server,
const char *vformat,
const char *pre)
{
ipmip_cli_config_printf(&request->message,
"%s.%s.address=%s",
vformat, pre, ipmip_ntop_inet(proc, server->server_addr.sin.sin_addr.s_addr));
ipmip_cli_config_printf(&request->message,
"%s.%s.secret=<hidden>",
vformat, pre);
ipmip_cli_config_printf(&request->message,
"%s.%s.port=%d",
vformat, pre, ip_ntohs(server->server_addr.sin.sin_port));
}
/*
*===========================================================================
* ipmip4_radius_read_server
*===========================================================================
* Description:
* Parameters:
* Returns:
*
*/
IP_STATIC Ip_bool
ipmip4_radius_read_server(Ipradius_server *server,
const char *defbase,
const char *vformat,
const char *pre,
Ip_u16 defport,
int server_type)
{
char *secret = IP_NULL;
Ip_u32 srv;
Ip_bool success = IP_FALSE;
Ip_size_t sz;
if (vformat)
{
if (!ipmip_sysvar_inet(0, &srv, IP_NULL, "%s.%s.address", vformat, pre) && defbase)
(void)ipmip_sysvar_inet(0, &srv, IP_NULL, "%s.%s.address", defbase, pre);
}
else
(void)ipmip_sysvar_inet(0, &srv, IP_NULL, "%s.%s.address", defbase, pre);
if (srv == 0)
{
IPCOM_LOG1(ERR, "IPMIP4: Radius configuration; %s server address not specified.", pre);
goto done_out;
}
if (vformat)
secret = ipmip_sysvar("%s.%s.secret", vformat, pre);
if (secret == IP_NULL && defbase)
secret = ipmip_sysvar("%s.%s.secret", defbase, pre);
if (!secret)
{
IPCOM_LOG1(ERR, "IPMIP4: Radius configuration; %s secret not specified", pre);
goto done_out;
}
/* Setup the server */
server->server_addr.sin.sin_family = IP_AF_INET;
server->server_addr.sin.sin_addr.s_addr = srv;
if (defbase)
defport = ipmip_sysvar_ulong(defport, "%s.%s.port", defbase, pre);
if (vformat)
defport = ipmip_sysvar_ulong(defport, "%s.%s.port", vformat, pre);
server->server_addr.sin.sin_port = ipcom_htons(defport);
IPCOM_SA_LEN_SET(&server->server_addr.sin, sizeof(struct Ip_sockaddr_in));
sz = ipcom_strlen(secret);
sz = IP_MIN(sz, sizeof(server->shared_secret));
ipcom_strncpy((char *)server->shared_secret, (char *)secret, sz);
/* Force terminate string unconditionally */
server->shared_secret[IPRADIUS_MAX_SECRET_SIZE - 1] = '\0';
/**/
server->shared_secret_len = sz;
server->index = 0;
server->pollnum = 3;
server->pollsec = 3;
server->server_type = server_type;
server->conf[0] = (unsigned long)-1;
success = IP_TRUE;
done_out:
if (secret)
ipcom_free(secret);
return success;
}
/*
****************************************************************************
* 10 GLOBAL FUNCTIONS
****************************************************************************
*/
/*
*===========================================================================
* ipmip4_radius_context_create
*===========================================================================
* Description: Create a radius context if so specified by the configuration
* parameters
* Parameters: ctx - MIPv4 context
* proc - Current process context
* func - Radius processing callback function
* format - Base configuration path
* Returns: A radius context if properly configured and enabled
*
*/
IP_GLOBAL Ipmip4_radius_context_t *
ipmip4_radius_context_create(struct Ipmip4_context *ctx,
struct Ipmip_proc *proc,
const char *defbase,
const char *format,
...)
{
char *vformat = IP_NULL;
Ipmip4_radius_context_t *radius = IP_NULL;
va_list ap;
if (format)
{
va_start(ap, format);
vformat = ipmip_util_vstrdup(format, ap);
va_end(ap);
}
if (!vformat && !defbase)
return IP_NULL;
radius = ipcom_calloc(1, sizeof(*radius));
if (!radius)
{
IPCOM_LOG0(ERR, "IPMIP4: Radius configuration; failed to allocate memory");
goto done_out;
}
(void)ipcom_mutex_create(&radius->lock);
/* Base parameters */
radius->ctx = ctx;
radius->radius.fd = IP_INVALID_SOCKET;
if (vformat)
radius->nai = (Ipmip4_msgext_uhdr_t *)ipmip4_sysext_nai_aaah("%s.nai", vformat);
if (defbase && radius->nai == IP_NULL)
radius->nai = (Ipmip4_msgext_uhdr_t *)ipmip4_sysext_nai_aaah("%s.nai", defbase);
if (vformat)
radius->pwd = ipmip_sysvar("%s.user_password", vformat);
if (defbase && radius->pwd == IP_NULL)
radius->pwd = ipmip_sysvar("%s.user_password", defbase);
if (radius->pwd)
radius->pwd_len = ipcom_strlen(radius->pwd);
ipmip4_radius_read_server(&radius->radius.auth, defbase, vformat, "access", 1812, IPRADIUS_ACCESS_SERVER);
ipmip4_radius_read_server(&radius->radius.acct, defbase, vformat, "accounting", 1813, IPRADIUS_ACCOUNTING_SERVER);
radius->radius.lcl.sin_family = IP_AF_INET;
if (vformat)
{
if (!ipmip_sysvar_inet(0, &radius->radius.lcl.sin_addr.s_addr, IP_NULL, "%s.local.address", vformat) && defbase)
(void)ipmip_sysvar_inet(0, &radius->radius.lcl.sin_addr.s_addr, IP_NULL, "%s.local.address", defbase);
}
else
{
(void)ipmip_sysvar_inet(0, &radius->radius.lcl.sin_addr.s_addr, IP_NULL, "%s.local.address", defbase);
}
radius->radius.lcl.sin_port = 0;
IPCOM_SA_LEN_SET(&radius->radius.lcl, sizeof(struct Ip_sockaddr_in));
/* Create the socket */
radius->radius.fd = ipcom_socket(IP_AF_INET, IP_SOCK_DGRAM, IP_IPPROTO_UDP);
if (radius->radius.fd == IP_INVALID_SOCKET)
{
IPCOM_LOG1(ERR, "IPMIP4: Radius configuration; failed to allocate datagram socket = %x", ipcom_errno);
goto error_out;
}
if (ipcom_bind(radius->radius.fd, (struct Ip_sockaddr *)&radius->radius.lcl, sizeof(radius->radius.lcl)) < 0)
{
IPCOM_LOG1(ERR, "IPMIP4: Radius configuration; failed to bind datagram socket = %x", ipcom_errno);
goto error_out;
}
/* Add the server */
if (radius->radius.auth.server_type != 0)
ipradius_server_add(&radius->radius.auth);
if (radius->radius.acct.server_type != 0)
ipradius_server_add(&radius->radius.acct);
radius->tmo2_proc = ipmip_proc_alloc();
if (radius->tmo2_proc == IP_NULL)
goto error_out;
/* Need to start the radius process */
radius->proc = ipmip_proc_start(&ctx->ipmip, proc, "radius", (Ipmip_proc_func_t)ipmip4_radius_proc, radius);
if (radius->proc == IP_NULL)
goto error_out;
done_out:
ipcom_free(vformat);
return radius;
error_out:
ipcom_mutex_delete(&radius->lock);
if (radius->radius.fd != IP_INVALID_SOCKET)
ipcom_socketclose(radius->radius.fd);
if (radius->tmo2_proc)
ipmip_proc_destroy(radius->tmo2_proc);
ipcom_free(radius);
radius = IP_NULL;
goto done_out;
}
IP_GLOBAL void
ipmip4_radius_context_dump(struct Ipmip4_context *ctx,
struct Ipmip_proc *proc,
Ipmip4_radius_context_t *radius,
Ipmip_cli_message_t *request,
const char *format,
...)
{
char *vformat = IP_NULL;
va_list ap;
IPMIP_UNUSED_PARAMETER(ctx);
va_start(ap, format);
vformat = ipmip_util_vstrdup(format, ap);
va_end(ap);
if (radius->nai)
{
Ip_u8 *data = &((Ip_u8 *)radius->nai)[3];
ipmip_cli_config_printf(&request->message,
"%s.nai=%s",
vformat, data);
}
if (radius->pwd)
{
ipmip_cli_config_printf(&request->message,
"%s.user_password=<hidden>",
vformat);
}
ipmip_cli_config_printf(&request->message,
"%s.local.address=%s",
vformat, ipmip_ntop_inet(proc, radius->radius.lcl.sin_addr.s_addr));
ipmip4_radius_dump_server(proc, request, &radius->radius.auth, vformat, "access");
ipmip4_radius_dump_server(proc, request, &radius->radius.acct, vformat, "accounting");
ipcom_free(vformat);
}
/*
*===========================================================================
* ipmip4_radius_context_destroy
*===========================================================================
* Description: Stop and destroy a radius context
* Parameters: ctx - The context
* proc - Current process
* radius - Radius context.
* Returns:
*
*/
IP_GLOBAL void
ipmip4_radius_context_destroy(struct Ipmip4_context *ctx,
struct Ipmip_proc *proc,
Ipmip4_radius_context_t *radius)
{
if (radius != IP_NULL)
{
/* Do stop the context */
ipmip_proc_stop(&ctx->ipmip, proc, radius->proc, IP_NULL, IP_NULL);
ipmip_proc_destroy(radius->tmo2_proc);
ipcom_mutex_delete(&radius->lock);
if (radius->radius.acct.server_type)
ipradius_server_remove(&radius->radius.acct);
if (radius->radius.auth.server_type)
ipradius_server_remove(&radius->radius.auth);
ipcom_socketclose(radius->radius.fd);
if (radius->pwd)
ipcom_free(radius->pwd);
if (radius->nai)
ipcom_free(radius->nai);
ipcom_free(radius);
}
}
/*
*===========================================================================
* ipmip4_radius_access_request
*===========================================================================
* Description: Create a radius access base message
* Parameters: ctx - Context
* proc - Current process
* radius - Radius context
* Returns: A message structure if successful
*
*/
IP_GLOBAL Ipmip4_radius_packet_t*
ipmip4_radius_access_request_init(struct Ipmip4_context *ctx,
struct Ipmip_proc *proc,
Ipmip4_radius_context_t *radius)
{
Ipradius_header *msg = ipradius_access_request_pkt_malloc();
IPMIP_UNUSED_PARAMETER(ctx);
IPMIP_UNUSED_PARAMETER(proc);
if (msg == IP_NULL)
return IP_NULL;
ipcom_mutex_lock(radius->lock);
msg->id = ++radius->radius.msgid;
ipcom_mutex_unlock(radius->lock);
msg->code = IPRADIUS_CODE_Access_Request;
return (Ipmip4_radius_packet_t*)msg;
}
/*
*===========================================================================
* ipmip4_radius_access_request
*===========================================================================
* Description: Do an ordinary access request; no challenge provided
* Parameters: ctx - Context
* proc - Current process
* radius - Radius context
* func - Radius callback function
* nai - Identity of the requesting node
* pbuf - Current transaction
* Returns: IP_TRUE on successful request transmission.
*
*/
IP_GLOBAL Ip_bool
ipmip4_radius_access_request(struct Ipmip4_context *ctx,
struct Ipmip_proc *proc,
Ipmip4_radius_context_t *radius,
Ipmip4_radius_func_t func,
Ipmip4_radius_packet_t *omsg,
Ipmip4_pktbuf_t *pbuf,
void *arg,
int auth_type)
{
Ipradius_request request = {0};
Ip_u8 errattr = 0;
Ipmip4_ipradius_cookie_t *cookie;
Ipradius_header *msg = omsg;
if (radius->radius.auth.server_type == 0)
{
ipmip_pktbuf_error(&pbuf->ipmip,
0,
"RADIUS access server not properly configured");
ipmip4_radius_access_request_free(ctx, proc, radius, omsg);
return IP_FALSE;
}
if (auth_type == IPMIP4_RADIUS_AUTH_CHAP)
{
if (!ipmip4_radius_access_request_chap_auth(ctx, proc, radius, pbuf, omsg))
{
ipmip4_radius_access_request_free(ctx, proc, radius, omsg);
return IP_FALSE;
}
}
if (auth_type == IPMIP4_RADIUS_AUTH_USER_PASSWORD)
{
if (radius->pwd == IP_NULL)
{
ipmip_pktbuf_error(&pbuf->ipmip,
0,
"RADIUS User-Password authentication requested, but no configured password");
ipmip4_radius_access_request_free(ctx, proc, radius, omsg);
return IP_FALSE;
}
}
cookie = ipcom_malloc(sizeof(*cookie));
if (!cookie)
{
ipradius_access_request_pkt_free(msg);
return IP_FALSE;
}
/* Store the cookie info */
cookie->func = func;
cookie->radius = radius;
cookie->pbuf = pbuf;
cookie->arg = arg;
ipcom_mutex_lock(radius->lock);
request.unique = msg->id;
ipcom_mutex_unlock(radius->lock);
msg->code = IPRADIUS_CODE_Access_Request;
/* */
if (auth_type == IPMIP4_RADIUS_AUTH_USER_PASSWORD)
{
request.pwd_type = IPRADIUS_PAP_Password;
request.pwd_len = IP_MIN(sizeof(request.pwd), radius->pwd_len);
ipcom_strncpy(request.pwd, radius->pwd, request.pwd_len);
}
else
request.pwd_type = IPRADIUS_No_Password;
request.fd = radius->radius.fd;
request.event_callback = ipmip4_radius_event_callback;
request.cookie = cookie;
request.num_servers = 1;
ipcom_memcpy(&request.serv_list[0].server_addr,
&radius->radius.auth.server_addr,
sizeof(union Ip_sockaddr_union));
request.serv_list[0].server_type = radius->radius.auth.server_type;
request.serv_list[0].pollnum = radius->radius.auth.pollnum;
request.serv_list[0].pollsec = radius->radius.auth.pollsec;
/* Store the radius context */
if (ipradius_access_request(msg, &request, &errattr) != IPCOM_SUCCESS)
{
IPCOM_LOG0(ERR, "Ipradius access request failed");
ipcom_free(cookie);
return IP_FALSE;
}
return IP_TRUE;
}
/*
*===========================================================================
* ipmip4_radius_access_request_free
*===========================================================================
* Description: Free a radius access base message
* Parameters: ctx - Context
* proc - Current process
* radius - Radius context
* msg - Message
* Returns:
*
*/
IP_GLOBAL void
ipmip4_radius_access_request_free(struct Ipmip4_context *ctx,
struct Ipmip_proc *proc,
struct Ipmip4_radius_context *radius,
Ipmip4_radius_packet_t *msg)
{
IPMIP_UNUSED_PARAMETER(ctx);
IPMIP_UNUSED_PARAMETER(proc);
IPMIP_UNUSED_PARAMETER(radius);
ipradius_access_request_pkt_free((Ipradius_header *)msg);
}
/*
*===========================================================================
* ipmip4_radius_accounting_start
*===========================================================================
* Description: Start radius accounting for the session
* Parameters: ctx - Context
* proc - Process
* func - Callback function
* unique_id - Unique session ID
* pbuf - Packet buffer
* Returns: IP_TRUE on success.
*
*/
IP_GLOBAL Ip_bool
ipmip4_radius_accounting_start(struct Ipmip4_context *ctx,
struct Ipmip_proc *proc,
struct Ipmip4_radius_context *radius,
Ipmip4_radius_func_t func,
Ip_u32 unique_id,
Ipmip4_pktbuf_t *pbuf,
void *arg)
{
Ipradius_request request;
Ipmip4_ipradius_acct_cookie_t *cookie;
IPMIP_UNUSED_PARAMETER(ctx);
IPMIP_UNUSED_PARAMETER(proc);
if (radius->radius.acct.server_type == 0)
return IP_FALSE;
cookie = ipcom_malloc(sizeof(*cookie));
if (!cookie)
return IP_FALSE;
ipcom_memset(&request, 0, sizeof(request));
/**/
request.unique = unique_id;
request.pwd_type = 0;
request.pwd_len = 0;
request.chap_ident = 0;
/* Set RADIUS socket descriptor and event callback. */
request.fd = radius->radius.fd;
request.event_callback = ipmip4_radius_acct_callback;
request.num_servers = 1;
ipcom_memcpy(&request.serv_list[0].server_addr,
&radius->radius.acct.server_addr,
sizeof(union Ip_sockaddr_union));
request.serv_list[0].server_type = radius->radius.acct.server_type;
request.serv_list[0].pollnum = radius->radius.acct.pollnum;
request.serv_list[0].pollsec = radius->radius.acct.pollsec;
cookie->func = func;
cookie->radius = radius;
cookie->pbuf = pbuf;
cookie->arg = arg;
request.cookie = cookie;
/* Start the accounting. */
if (ipradius_accounting_session_start(&request, 0) != IPCOM_SUCCESS)
{
IPCOM_LOG0(ERR, "Failed to start accounting");
ipcom_free(cookie);
return IP_FALSE;
}
return IP_TRUE;
}
/*
*===========================================================================
* ipmip4_radius_accounting_stop
*===========================================================================
* Description: Stop radius accounting for the session
* Parameters: ctx - Context
* proc - Process
* unique_id - Unique session ID
* Returns: IP_TRUE on success.
*
*/
IP_GLOBAL Ip_bool
ipmip4_radius_accounting_stop(struct Ipmip4_context *ctx,
struct Ipmip_proc *proc,
struct Ipmip4_radius_context *radius,
Ip_u32 unique_id)
{
int ret = ipradius_accounting_session_stop(unique_id, 1);
IPMIP_UNUSED_PARAMETER(ctx);
IPMIP_UNUSED_PARAMETER(proc);
IPMIP_UNUSED_PARAMETER(radius);
return ret == IPCOM_SUCCESS;
}
/*
*===========================================================================
* ipmip4_radius_attr_add
*===========================================================================
* Description: Add a radius extension
* Parameters: ctx - Context
* proc - Current process
* radius - Radius context
* msg - Message
* type - Type of extension
* data - Payload
* size - Size of payload
* Returns:
*
*/
IP_GLOBAL void
ipmip4_radius_attr_add(struct Ipmip4_context *ctx,
struct Ipmip_proc *proc,
struct Ipmip4_radius_context *radius,
Ipmip4_radius_packet_t *msg,
Ip_u8 type,
void *data,
Ip_size_t size)
{
IPMIP_UNUSED_PARAMETER(ctx);
IPMIP_UNUSED_PARAMETER(proc);
IPMIP_UNUSED_PARAMETER(radius);
(void)ipradius_attr_add_array((Ipradius_header *)msg, type, data, size);
}
/*
*===========================================================================
* ipmip4_radius_attr_vendor_add
*===========================================================================
* Description: Add a radius VSA
* Parameters: ctx - Context
* proc - Current process
* radius - Radius context
* msg - Message
* vendor - Vendor
* type - Vendor Type
* data - Payload
* size - Size of payload
* Returns:
*
*/
IP_GLOBAL void
ipmip4_radius_attr_vendor_add(struct Ipmip4_context *ctx,
struct Ipmip_proc *proc,
struct Ipmip4_radius_context *radius,
Ipmip4_radius_packet_t *msg,
Ip_u32 vendor,
Ip_u8 type,
void *data,
Ip_size_t size)
{
Ip_u8 *ptr;
if ((size + 6) > sizeof(proc->ntop.ntop_pbuf))
return;
/* Do create a VENDOR VSA RADIUS attribute */
ptr = (Ip_u8 *)proc->ntop.ntop_pbuf;
/* Set VENDOR */
IP_SET_HTONL(&ptr[0], vendor);
ptr[4] = type;
ptr[5] = size + 2;
/* Copy VSA data */
ipcom_memcpy(&ptr[6], data, size);
/* Add the VSA */
ipmip4_radius_attr_add(ctx, proc, radius, msg, IPMIP4_RADIUS_ATTR_Vendor_Specific, proc->ntop.ntop_pbuf, size + 6);
}
/*
*===========================================================================
* ipmip4_radius_attr_next
*===========================================================================
* Description: Get next radius extension
* Parameters: ctx - Context
* proc - Current process
* radius - Radius context
* msg - Message
* last - Last retrieved attribute or IP_NULL if first.
* Returns:
*
*/
IP_GLOBAL Ip_u8 *
ipmip4_radius_attr_next(struct Ipmip4_context *ctx,
struct Ipmip_proc *proc,
struct Ipmip4_radius_context *radius,
Ipmip4_radius_packet_t *msg,
Ip_u8 *last)
{
IPMIP_UNUSED_PARAMETER(ctx);
IPMIP_UNUSED_PARAMETER(proc);
IPMIP_UNUSED_PARAMETER(radius);
/* Get next attribute */
return ipradius_attr_get_next((Ipradius_header *)msg, last);
}
/*
*===========================================================================
* ipmip4_radius_aaah
*===========================================================================
* Description: Return the AAAH NAI for a radius context. The memory is dynamically
* allocated and must be freed by the caller.
* Parameters: ctx - Context
* proc - Process
* radius - Radius AAAH NAI
* Returns: The AAAH NAI.
*
*/
IP_GLOBAL Ipmip4_msgext_uhdr_t *
ipmip4_radius_aaah(struct Ipmip4_context *ctx,
struct Ipmip_proc *proc,
struct Ipmip4_radius_context *radius)
{
IPMIP_UNUSED_PARAMETER(ctx);
IPMIP_UNUSED_PARAMETER(proc);
if (radius->nai)
return ipmip4_msgext_shdr_dup(radius->nai);
return IP_NULL;
}
/*
*===========================================================================
* ipmip4_radius_decrypt_tunnel_password
*===========================================================================
* Description:
* Parameters:
* Returns:
*
*/
IP_GLOBAL const char *
ipmip4_radius_decrypt_tunnel_password(struct Ipmip4_context *ctx,
struct Ipmip_proc *proc,
struct Ipmip4_radius_context *radius,
Ipmip4_radius_packet_t *request,
Ip_u8 *attr,
Ip_size_t attr_len,
Ipmip_buffer_t *buffer)
{
Ip_u8 *salt;
Ip_u8 *data;
MD5_CTX md5;
char *decrypt;
Ipradius_header *req = (Ipradius_header *)request;
int i = 0;
int j = 0;
IPMIP_UNUSED_PARAMETER(ctx);
/* Add the CHAP challenge */
MD5_Init(&md5);
ipmip_buffer_init(buffer);
salt = &attr[0];
data = &attr[2];
attr_len -= 2;
(void)ipmip_buffer_reserve(buffer, attr_len);
decrypt = IPMIP_BUFFER_PTR(buffer);
ipmip_buffer_append(buffer, IP_NULL, attr_len);
MD5_Update(&md5, radius->radius.auth.shared_secret, radius->radius.auth.shared_secret_len);
MD5_Update(&md5, req->auth, 16);
MD5_Update(&md5, salt, 2);
MD5_Final((unsigned char *)proc->ntop.ntop_pbuf, &md5);
while (j < (int)attr_len)
{
for (i = 0; i < 16; i++, j++)
decrypt[j] = data[j] ^ proc->ntop.ntop_pbuf[i];
if (j < (int)attr_len)
{
MD5_Init(&md5);
MD5_Update(&md5, radius->radius.auth.shared_secret, radius->radius.auth.shared_secret_len);
MD5_Update(&md5, &data[j - 16], 16);
MD5_Final((unsigned char *)proc->ntop.ntop_pbuf, &md5);
}
}
decrypt = IPMIP_BUFFER_PTR(buffer);
i = decrypt[0];
if (i >= (int)attr_len)
{
ipmip_buffer_release(buffer);
return IP_NULL;
}
decrypt++;
decrypt[i] = '\0';
return decrypt;
}
/*
****************************************************************************
* 11 PUBLIC FUNCTIONS
****************************************************************************
*/
#else /* IPRADIUS */
int ipmip4_radius_empty_file = 0;
#endif
/*
****************************************************************************
* END OF FILE
****************************************************************************
*/