/* ****************************************************************************** * 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 ****************************************************************************** */ #ifdef IPRADIUS /* **************************************************************************** * 1 DESCRIPTION **************************************************************************** */ /* **************************************************************************** * 2 CONFIGURATION **************************************************************************** */ #include "ipmip4_config.h" /* **************************************************************************** * 3 INCLUDE FILES **************************************************************************** */ #define IPCOM_USE_CLIB_PROTO #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "ipmip4.h" #include #include #include #include #include #if defined(IPMCRYPTO) #include #else #include #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=", 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=", 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 **************************************************************************** */