📄 radius_tx.c
字号:
/* radius_tx.c *//* Implementations of fucntions that handle the transmission of RADIUS packets. *//* Copyright 1984 - 2000 Wind River Systems, Inc. */#include "copyright_wrs.h"/*modification history____________________Date Init Change description031102 md Enhancement - moving polling socket read to seperate tasks and replace taskLock/unLock with rwos_radius_data_mutex030402 md Add support for EAP030402 md Bug fix - authenticate accounting response when verify response authenticator is enable111401 md Fixed SPR#70426 - pool packet identifiers per server092701 md Fixed SPR#70639 retransmission of accounting requests with RADIUS_ACCT_DELAY_TIME attribute052301 tk Added a check on user_count before deleting server in radius_resend_packet. This check adds an extra measure of security to avoid deletion of the server while some client may have not freed the server handle it has obtained from the RADIUS Client.040501 tk Fixed memory leaks, added new feature to send request to secondary server(s) when primary server is down or not responding.121900 md Fixed ACCT_DELAY_TIME with encryption whenever the content is changed and or new id is used121900 md Merged from visual source safe*/#include <string.h>#include <errnoLib.h>#include "radius.h"#ifdef __RADIUS_MIB__#include "radius_mib_include.h"#endif#ifdef VIRTUAL_STACK#include "vsLib.h"#endif#ifdef __EAP__#include "radius_message_digest.h"#endif /* __EAP__ */#define OUT_OF_MBUF 0x37 /* errno for network buffer depletion condition *//************************************************************************/static enum TEST send_radius_udp_packet (RADIUS_PACKET *sptr_packet, enum RADIUS_CODE code, UINT length, RADIUS_SERVER* p_server);static void update_delay_time_for_retransmission (RADIUS_PACKET *sptr_packet, RADIUS_REQUEST_ENTRY *sptr_request_entry, UINT retransmission_interval, RADIUS_SERVER *p_server, bool* ep_error_packet_id);/************************************************************************/#ifdef __EAP__enum TEST radius_write_message_authenticator_to_packet (RADIUS_PACKET *sptr_packet, BYTE *msg_authenticator, RADIUS_LIST_CONTROLLER* p_radius_attribute_list_controller){ RW_CONTAINER_ITERATOR attribute_iterator; RADIUS_ATTRIBUTE_ENTRY_IN_PACKET *sptr_attribute_entry_in_packet; RADIUS_ATTRIBUTE_ENTRY* p_attribute; if (sptr_packet == NULL) { return (FAIL); } sptr_attribute_entry_in_packet = (RADIUS_ATTRIBUTE_ENTRY_IN_PACKET *) &sptr_packet->data; attribute_iterator = p_radius_attribute_list_controller->iterator; rw_container_goto_front (attribute_iterator); while (rw_container_is_at_end (attribute_iterator) == false) { p_attribute = rw_container_at (attribute_iterator); if (p_attribute->type == RADIUS_MESSAGE_AUTHENTICATOR) { memcpy (&sptr_attribute_entry_in_packet->value[0], msg_authenticator, HMAC_MD5_RESULT_LENGTH); memcpy (&p_attribute->value[0], msg_authenticator, HMAC_MD5_RESULT_LENGTH); return (PASS); } sptr_attribute_entry_in_packet = (RADIUS_ATTRIBUTE_ENTRY_IN_PACKET *) ((BYTE *) sptr_attribute_entry_in_packet + (BYTE) (p_attribute->length_of_attribute_value + RADIUS_SIZE_OF_ATTRIBUTE_HEADER_IN_PACKET)); rw_container_next (attribute_iterator); } return (FAIL);}/*****************************************************************************************/enum TEST radius_initialize_message_authenticator (RADIUS_LIST_CONTROLLER* p_radius_attribute_list_controller){ RW_CONTAINER_ITERATOR attribute_iterator; RADIUS_ATTRIBUTE_ENTRY* p_attribute; attribute_iterator = p_radius_attribute_list_controller->iterator; rw_container_goto_front (attribute_iterator); while (rw_container_is_at_end (attribute_iterator) == false) { p_attribute = rw_container_at (attribute_iterator); if (p_attribute->type == RADIUS_MESSAGE_AUTHENTICATOR) { memset (&p_attribute->value[0], 0, HMAC_MD5_RESULT_LENGTH); return (PASS); } rw_container_next (attribute_iterator); } return (FAIL);}#endif /* __EAP__ *//************************************************************************/enum TEST radius_send_packet (RADIUS_SERVER_HANDLE server_handle, RADIUS_REQUEST_HANDLE radius_request_handle, RADIUS_REQUEST_CALLBACKS *p_callbacks, enum RADIUS_CODE code, RADIUS_ATTRIBUTE_LIST_HANDLE attribute_list_handle, bool* ep_error_callback_called, bool any_server){ RADIUS_PACKET *sptr_packet; UINT length; RADIUS_LIST_CONTROLLER* p_radius_attribute_list_controller; RW_CONTAINER_ITERATOR server_iterator_copy; RADIUS_REQUEST_ENTRY *sptr_request_entry; USHORT authenticator[8]; RADIUS_SERVER *p_server;#ifdef __EAP__ BYTE message_authenticator[16]; BYTE hmac_md5_result[HMAC_MD5_RESULT_LENGTH];#endif /* __EAP__ */#ifdef __RADIUS_BREAKPOINT__ check_for_radius_runtime_breakpoint ();#endif /* __RADIUS_BREAKPOINT__ */ p_server = (RADIUS_SERVER*) rw_container_at ((RW_CONTAINER_ITERATOR) server_handle); /* handle better be a valid one :) */ if ((p_server == NULL) || (p_server->deleted == true)) { radius_printf (RADIUS_ALARM_PRINTF, "RADIUS: radius_server_request: Invalid server chosen\n"); rwos_mutex_release (rwos_radius_data_mutex); (*p_callbacks->fptr_radius_error_callback) (radius_request_handle, RADIUS_INVALID_SERVER_SPECIFIED); rwos_mutex_acquire (rwos_radius_data_mutex, WAIT_FOREVER); *ep_error_callback_called = true; return (FAIL); } if (p_server->pending_request_count >= MAXIMUM_NUMBER_OF_OUTSTANDING_REQUESTS) { radius_printf (RADIUS_ALARM_PRINTF, "RADIUS: radius_server_request: Max number of outstanding requests reached\n"); rwos_mutex_release (rwos_radius_data_mutex); (*p_callbacks->fptr_radius_error_callback) (radius_request_handle, RADIUS_MAXIMUM_NUMBER_OF_OUTSTANDING_REQUEST_REACHED); rwos_mutex_acquire (rwos_radius_data_mutex, WAIT_FOREVER); *ep_error_callback_called = true; return (FAIL); } if (radius_get_next_available_packet_identifier_per_server (p_server, &p_server->packet_identifier_count) == FAIL) { radius_printf (RADIUS_ALARM_PRINTF, "RADIUS: radius_server_request: Failed to find available packet identifier\n"); rwos_mutex_release (rwos_radius_data_mutex); (*p_callbacks->fptr_radius_error_callback) (radius_request_handle, RADIUS_MAXIMUM_NUMBER_OF_OUTSTANDING_REQUEST_REACHED); rwos_mutex_acquire (rwos_radius_data_mutex, WAIT_FOREVER); *ep_error_callback_called = true; return (FAIL); } authenticator[0] = (USHORT) rand (); authenticator[1] = (USHORT) rand (); authenticator[2] = (USHORT) rand (); authenticator[3] = (USHORT) rand (); authenticator[4] = (USHORT) rand (); authenticator[5] = (USHORT) rand (); authenticator[6] = (USHORT) rand (); authenticator[7] = (USHORT) rand (); p_radius_attribute_list_controller = (RADIUS_LIST_CONTROLLER*) attribute_list_handle;#ifdef __EAP__ if (radius_check_eap_and_ma_attribute (p_radius_attribute_list_controller) == true) { memset (message_authenticator, 0, 16); radius_add_attribute_to_list (attribute_list_handle, RADIUS_MESSAGE_AUTHENTICATOR, 16, message_authenticator); }#endif /* __EAP__ */ if (radius_encrypt_attributes_with_authenticator (p_radius_attribute_list_controller->p_list, (BYTE *) &authenticator[0], p_server) == FAIL) { radius_free_packet_identifier_per_server (p_server, p_server->packet_identifier_count); return (FAIL); } length = get_radius_attribute_list_length (p_radius_attribute_list_controller); length += sizeof (RADIUS_PACKET_HEADER); sptr_packet = (RADIUS_PACKET *) buffer_malloc (length); if (sptr_packet == NULL) { radius_free_packet_identifier_per_server (p_server, p_server->packet_identifier_count); return (FAIL); } sptr_packet->header.code = (BYTE) code; sptr_packet->header.length = swap ((USHORT) length); sptr_packet->header.identifier = (BYTE) p_server->packet_identifier_count; if (radius_write_attributes_to_packet (sptr_packet, p_radius_attribute_list_controller) == FAIL) { radius_free_packet_identifier_per_server (p_server, p_server->packet_identifier_count); buffer_free (sptr_packet); return (FAIL); } if (code == RADIUS_ACCOUNTING_REQUEST) { memset (&sptr_packet->header.authenticator[0], 0, RADIUS_SIZE_OF_AUTHENTICATOR); if (radius_accounting_fill_in_request_authenticator (sptr_packet, length, p_server, (BYTE *) &authenticator[0]) == false) { radius_free_packet_identifier_per_server (p_server, p_server->packet_identifier_count); buffer_free (sptr_packet); return (FAIL); } } else { memcpy (&sptr_packet->header.authenticator[0], &authenticator[0], RADIUS_SIZE_OF_AUTHENTICATOR); } sptr_request_entry = (RADIUS_REQUEST_ENTRY *) table_malloc (1, sizeof (RADIUS_REQUEST_ENTRY)); if (sptr_request_entry == NULL) { radius_free_packet_identifier_per_server (p_server, p_server->packet_identifier_count); buffer_free (sptr_packet); return (FAIL); }#ifdef __EAP__ memset (&hmac_md5_result[0], 0, HMAC_MD5_RESULT_LENGTH); radius_hmac_md5 ((unsigned char *)sptr_packet, length, p_server->bp_secret, p_server->secret_length, (BYTE *)&hmac_md5_result[0]); radius_write_message_authenticator_to_packet (sptr_packet, (BYTE *)&hmac_md5_result[0], p_radius_attribute_list_controller);#endif /* __EAP__ */ sptr_request_entry->sptr_packet = sptr_packet; sptr_request_entry->request_time = 0; sptr_request_entry->request_timestamp = rwos_get_system_elapsed_time (); sptr_request_entry->request_retry_count = 0; sptr_request_entry->request_handle = radius_request_handle; sptr_request_entry->p_callbacks = (RADIUS_REQUEST_CALLBACKS *) table_malloc (1, sizeof (RADIUS_REQUEST_CALLBACKS)); sptr_request_entry->any_server = any_server; sptr_request_entry->backup_server = false; if (sptr_request_entry->p_callbacks == NULL) { radius_free_packet_identifier_per_server (p_server, p_server->packet_identifier_count); buffer_free (sptr_packet); buffer_free (sptr_request_entry); return (FAIL); } sptr_request_entry->p_callbacks->fptr_radius_normal_callback = p_callbacks->fptr_radius_normal_callback; sptr_request_entry->p_callbacks->fptr_radius_error_callback = p_callbacks->fptr_radius_error_callback; /* A copy of the server handle is created for safety reason. Since the client (of RADIUS Client) owns the server handle, it may free it while request is still pending. */ server_iterator_copy = rw_container_create_copy_of_iterator ((RW_CONTAINER_ITERATOR) server_handle); sptr_request_entry->server_handle = (RADIUS_SERVER_HANDLE)server_iterator_copy; sptr_request_entry->packet_header.code = (BYTE) code; sptr_request_entry->packet_header.identifier = (BYTE) (p_server->packet_identifier_count); sptr_request_entry->packet_header.length = (USHORT) length; memcpy (&sptr_request_entry->packet_header.authenticator[0], &authenticator[0], RADIUS_SIZE_OF_AUTHENTICATOR); print_radius_packet_header ("RADIUS: radius_send_packet", &sptr_packet->header); print_radius_attributes (p_radius_attribute_list_controller); if (send_radius_udp_packet (sptr_packet, code, length, p_server) == FAIL) { radius_free_packet_identifier_per_server (p_server, p_server->packet_identifier_count); rw_container_free_iterator (server_iterator_copy); table_free (sptr_request_entry); buffer_free (sptr_packet); return (FAIL); }#ifdef __RADIUS_MIB__ semTake (g_sem_radius_mib, WAIT_FOREVER);#endif switch (code) { case RADIUS_ACCESS_REQUEST: ++p_server->statistics.authentication_access_requests_tx; ++p_server->statistics.authentication_pending_access_requests; break; case RADIUS_ACCOUNTING_REQUEST: ++p_server->statistics.accounting_requests_tx; ++p_server->statistics.accounting_pending_access_requests; break; default: /* should not happen! */ break; }#ifdef __RADIUS_MIB__ semGive (g_sem_radius_mib);#endif rw_container_add_back (radius.request_controller.p_list, (RW_CONTAINER_ITEM*) sptr_request_entry); ++p_server->pending_request_count; return (PASS);}/*****************************************************************************************/static void update_delay_time_for_retransmission (RADIUS_PACKET *sptr_packet, RADIUS_REQUEST_ENTRY *sptr_request_entry, UINT retransmission_interval, RADIUS_SERVER *p_server, bool* ep_error_packet_id){ enum RADIUS_ATTRIBUTE_TYPE type; UINT attribute_length; RADIUS_ATTRIBUTE_ENTRY_IN_PACKET *sptr_attribute_entry_in_packet; UINT packet_length; UINT total_packet_length; BYTE *bp_value; UINT delay_time; if (sptr_packet == NULL) { return; } sptr_attribute_entry_in_packet = (RADIUS_ATTRIBUTE_ENTRY_IN_PACKET *) &sptr_packet->data; packet_length = (UINT) (swap (sptr_packet->header.length)); total_packet_length = (UINT) (swap (sptr_packet->header.length)); if (packet_length < sizeof (RADIUS_PACKET_HEADER)) { return; } packet_length -= sizeof (RADIUS_PACKET_HEADER); while (packet_length > 0) { type = sptr_attribute_entry_in_packet->type; if (type == RADIUS_ACCT_DELAY_TIME)
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -