diff --git a/radius_lib/Makefile b/radius_lib/Makefile new file mode 100644 index 000000000..1425cc912 --- /dev/null +++ b/radius_lib/Makefile @@ -0,0 +1,21 @@ +ALL=radius_lib + +include ../src/build.rules + + +CFLAGS += -I../src +CFLAGS += -I../src/utils + +LIBS = ../src/radius/libradius.a +LIBS += ../src/crypto/libcrypto.a +LIBS += ../src/utils/libutils.a + +CFLAGS += -DCONFIG_SONIC_RADIUS + +_OBJS_VAR := LIBS +include ../src/objs.mk + +radius_lib: $(LIBS) + echo "Building Radius lib ..." +clean: common-clean + rm -f core *~ *.o *.d diff --git a/src/crypto/Makefile b/src/crypto/Makefile index ce0997091..b69a0d59a 100644 --- a/src/crypto/Makefile +++ b/src/crypto/Makefile @@ -6,6 +6,7 @@ CFLAGS += -DCONFIG_SHA256 CFLAGS += -DCONFIG_SHA384 CFLAGS += -DCONFIG_HMAC_SHA384_KDF CFLAGS += -DCONFIG_INTERNAL_SHA384 +CFLAGS += -fPIC LIB_OBJS= \ aes-cbc.o \ diff --git a/src/radius/Makefile b/src/radius/Makefile index 8cfb33d35..abf0bce11 100644 --- a/src/radius/Makefile +++ b/src/radius/Makefile @@ -1,9 +1,13 @@ CFLAGS += -DCONFIG_IPV6 +CFLAGS += -fPIC +CFLAGS += -DCONFIG_SONIC_RADIUS +CFLAGS += -DCONFIG_SONIC_RADIUS_MAB LIB_OBJS= \ radius.o \ radius_client.o \ radius_das.o \ radius_server.o +LIB_OBJS += radius_attr_parse.o include ../lib.rules diff --git a/src/radius/radius.c b/src/radius/radius.c index be16e27b9..e497e81e2 100644 --- a/src/radius/radius.c +++ b/src/radius/radius.c @@ -14,6 +14,18 @@ #include "crypto/crypto.h" #include "radius.h" +#ifdef CONFIG_SONIC_RADIUS +#include "radius_attr_parse.h" +#include "radius_client.h" + +#define RADIUS_KEY_MAX_LEN 65 + +char *rulePtr; +char *redirectAclsPtr; + +#define RADIUS_ATTR_VAL_IPADM "aaa:service=ip_admission" +#define RADIUS_ATTR_VAL_IPDOWN "aaa:event=acl-download" +#endif /** * struct radius_msg - RADIUS message structure for new and parsed messages @@ -46,6 +58,11 @@ struct radius_msg { * attr_used - Total number of attributes in the array */ size_t attr_used; + +#ifdef CONFIG_SONIC_RADIUS + /* unique identifier to map the station */ + unsigned int correlator; +#endif }; @@ -171,6 +188,9 @@ static const struct radius_attr_type radius_attrs[] = { { RADIUS_ATTR_USER_NAME, "User-Name", RADIUS_ATTR_TEXT }, { RADIUS_ATTR_USER_PASSWORD, "User-Password", RADIUS_ATTR_UNDIST }, +#ifdef CONFIG_SONIC_RADIUS + { RADIUS_ATTR_CHAP_PASSWORD, "CHAP-Password", RADIUS_ATTR_UNDIST }, +#endif { RADIUS_ATTR_NAS_IP_ADDRESS, "NAS-IP-Address", RADIUS_ATTR_IP }, { RADIUS_ATTR_NAS_PORT, "NAS-Port", RADIUS_ATTR_INT32 }, { RADIUS_ATTR_SERVICE_TYPE, "Service-Type", RADIUS_ATTR_INT32 }, @@ -231,6 +251,9 @@ static const struct radius_attr_type radius_attrs[] = RADIUS_ATTR_HEXDUMP }, { RADIUS_ATTR_ACCT_INTERIM_INTERVAL, "Acct-Interim-Interval", RADIUS_ATTR_INT32 }, +#ifdef CONFIG_SONIC_RADIUS + { RADIUS_ATTR_NAS_PORT_ID, "NAS-Port-Id", RADIUS_ATTR_TEXT }, +#endif { RADIUS_ATTR_CHARGEABLE_USER_IDENTITY, "Chargeable-User-Identity", RADIUS_ATTR_TEXT }, { RADIUS_ATTR_NAS_IPV6_ADDRESS, "NAS-IPv6-Address", RADIUS_ATTR_IPV6 }, @@ -1728,3 +1751,420 @@ int radius_gen_session_id(u8 *id, size_t len) */ return os_get_random(id, len); } + +#ifdef CONFIG_SONIC_RADIUS + + +struct radius_msg * radius_copy_resp(struct radius_msg *in) +{ + struct radius_attr_hdr *attr; + unsigned char *pos, *end; + struct radius_msg *msg; + + msg = os_zalloc(sizeof(*msg)); + if (msg == NULL) + goto fail; + + msg->buf = wpabuf_alloc_copy(in->buf->buf, in->hdr->length); + if (msg->buf == NULL || radius_msg_initialize(msg)) + goto fail; + + msg->hdr = wpabuf_mhead(msg->buf); + + /* parse attributes */ + pos = wpabuf_mhead_u8(msg->buf) + sizeof(struct radius_hdr); + end = wpabuf_mhead_u8(msg->buf) + wpabuf_len(msg->buf); + while (pos < end) { + if ((size_t) (end - pos) < sizeof(*attr)) + goto fail; + + attr = (struct radius_attr_hdr *) pos; + + if (attr->length > end - pos || attr->length < sizeof(*attr)) + goto fail; + + if (radius_msg_add_attr_to_array(msg, attr)) + goto fail; + + pos += attr->length; + } + + return msg; + +fail: + if (msg) + radius_msg_free(msg); +return NULL; + +} + +/************************************************************************** + * @purpose Process RADIUS Accept from server + * + * @param *clientType @b{(input)} client type + * @param *radiusMsg @b{(input)} RADIUS message + * @param *attrInfo @b{(output)} client attribute info + * + * @returns 0 + * @returns -1 + * + * @comments + * + * @end + *************************************************************************/ +int radiusClientAcceptProcess(void *radiusMsg, attrInfo_t *attrInfo) +{ + radiusAttr_t *radiusAttr; + struct radius_msg *msg = (struct radius_msg *)radiusMsg; + radiusAttrParseFn_t fn; + int i =0; + struct radius_hdr *hdr = radius_msg_get_hdr(msg); + + if ((NULL == attrInfo) || (NULL == msg) ||( NULL == hdr)) + { + return -1; + } + + if (0 == attrInfo->attrFlags) + { + attrInfo->terminationAction = TERMINATION_ACTION_DEFAULT; + attrInfo->sessionTimeout = 0; + memset(attrInfo->serverState, 0, SERVER_STATE_LEN); + attrInfo->serverStateLen = 0; + attrInfo->vlanAttrFlags = 0; + memset(attrInfo->vlanString, '\0', sizeof(attrInfo->vlanString)); + } + + rulePtr = NULL; + redirectAclsPtr = NULL; + + for (i = 0; i < msg->attr_used; i++) + { + radiusAttr = (radiusAttr_t *)radius_get_attr_hdr(msg, i); + + if (0 == radiusAttrMapEntryGet(radiusAttr->type, &fn)) + { + fn(radiusAttr, attrInfo); + } + } + return 0; +} + +struct radius_msg * radius_client_update_auth_msg_data + (struct radius_msg *old_msg, + const u8 *shared_secret, + size_t shared_secret_len) +{ + struct radius_msg *msg = NULL; + unsigned int i = 0; + struct radius_attr_hdr *radiusAttr; + struct radius_hdr *hdr; + + if (!old_msg) + return NULL; + + hdr = radius_msg_get_hdr(old_msg); + + if (!hdr) + return NULL; + + msg = radius_msg_new(hdr->code, hdr->identifier); + + if (!msg) + return NULL; + + if (radius_msg_make_authenticator(msg) < 0) + goto fail; + + /* loop through the attributes and copy*/ + for (i = 0; i < old_msg->attr_used; i++) + { + radiusAttr = radius_get_attr_hdr(old_msg, i); + if (RADIUS_ATTR_TYPE_MESSAGE_AUTHENTICATOR == radiusAttr->type) + { + continue; + } + radius_msg_copy_attr(msg, old_msg, radiusAttr->type); + } + + msg->correlator = old_msg->correlator; + + radius_msg_finish(msg, shared_secret, shared_secret_len); + + radius_msg_dump(msg); + + return msg; + +fail: + radius_msg_free(msg); + return NULL; +} + +#ifdef CONFIG_SONIC_RADIUS_MAB + +int radiusClientChallengeProcess(void *radiusMsg, challenge_info_t *get_data) +{ + radiusAttr_t *radiusAttr; + struct radius_msg *msg = (struct radius_msg *)radiusMsg; + radiusAttrParseFn_t fn; + int i =0; + + if ((!get_data) || (!get_data->attrInfo)) + { + return -1; + } + + for (i = 0; i < msg->attr_used; i++) + { + radiusAttr = (radiusAttr_t *)radius_get_attr_hdr(msg, i); + if (RADIUS_ATTR_TYPE_NAS_PORT == radiusAttr->type) + { + if (0 != radiusAttrNasPortValidate(get_data->nas_port, radiusAttr)) + return -1; + } + else if (RADIUS_ATTR_TYPE_EAP_MESSAGE == radiusAttr->type) + { + if (0 != radiusAttrChallengeCopy(radiusAttr, get_data)) + return -1; + } + else + { + if (0 == radiusAttrMapEntryGet(radiusAttr->type, &fn)) + fn(radiusAttr, get_data->attrInfo); + } + + } + return 0; +} + +/* new start */ +int radius_eap_attr_add(void *req_attr, struct radius_msg *msg) +{ + eapPacket_t *eapPkt; + unsigned short eapLen = 0; + + if (!req_attr || !msg) + return -1; + + access_req_info_t *req = (access_req_info_t *)req_attr; + bool firstFrag = true; + + eapPkt = (eapPacket_t *)req->supp_eap_data; + /* EAP-Message */ + eapLen = eapPkt->length; /* Already endian-ized */ + eapPkt->length = htons(eapPkt->length); + radius_msg_add_eap(msg, (u8 *)eapPkt, eapLen); + + return 0; +} + +int radius_mab_attr_add(void *req_attr, struct radius_msg *msg) +{ + if (!req_attr || !msg) + return -1; + + access_req_info_t *req = (access_req_info_t *)req_attr; + u8 shared_secret[RADIUS_KEY_MAX_LEN]; + size_t shared_secret_len; + + if (MAB_AUTH_TYPE_PAP == req->mab_auth_type) + { + os_memset(shared_secret, 0, RADIUS_KEY_MAX_LEN); + /* get the current authentication server shared secret */ + if (radius_mab_current_auth_server_key_get(req->cxt, shared_secret, + &shared_secret_len)) { + return -1; + } + + /* user password */ + if ((req->user_name) && (0 != req->user_name_len) && + (!radius_msg_add_attr_user_password(msg, req->user_name, req->user_name_len, + shared_secret, shared_secret_len))) { + return -1; + } + } + else if ((MAB_AUTH_TYPE_CHAP == req->mab_auth_type) && req->challenge) + { + /* chap password */ + if ((req->chap_password) && (0 != req->chap_password_len) && + (!radius_msg_add_attr(msg, RADIUS_ATTR_CHAP_PASSWORD, + req->chap_password, req->chap_password_len))) { + return -1; + } + + /* chap challenge */ + if (!radius_msg_add_attr(msg, RADIUS_ATTR_CHAP_CHALLENGE, + req->challenge, req->challenge_len)) { + return -1; + } + } + + /* service-type */ + if (!radius_msg_add_attr_int32(msg, RADIUS_ATTR_TYPE_SERVICE_TYPE, + RADIUS_SERVICE_TYPE_CALL_CHECK)) + return -1; + + if (MAB_AUTH_TYPE_EAP_MD5 == req->mab_auth_type) + { + if (0 > radius_eap_attr_add(req_attr, msg)) + return -1; + } + + return 0; +} + + +int radius_access_req_common_attr_add(void *req_attr, struct radius_msg *msg) +{ + if (!req_attr || !msg) + return -1; + + access_req_info_t *req = (access_req_info_t *)req_attr; + /* Called station */ + if (req->calledId_len) + { + if (!radius_msg_add_attr(msg, RADIUS_ATTR_TYPE_CALLED_STATION_ID, req->calledId, + strlen(req->calledId))) + return -1; + } + + /* Calling station */ + if (req->callingId_len) + { + if (!radius_msg_add_attr(msg, RADIUS_ATTR_TYPE_CALLING_STATION_ID, req->callingId, + strlen(req->callingId))) + return -1; + } + /* NAS-Port */ + if (!radius_msg_add_attr_int32(msg, RADIUS_ATTR_TYPE_NAS_PORT, + req->nas_port)) + return -1; + + /* NAS-Port-ID */ + if (!radius_msg_add_attr(msg, RADIUS_ATTR_TYPE_NAS_PORT_ID, + req->nas_portid, strlen(req->nas_portid))) + return -1; + + /* NAS-Port-Type */ + if (!radius_msg_add_attr_int32(msg, RADIUS_ATTR_TYPE_NAS_PORT_TYPE, + RADIUS_NAS_PORT_TYPE_ETHERNET)) + return -1; + + + /* Framed-MTU */ + if (!radius_msg_add_attr_int32(msg, RADIUS_ATTR_TYPE_FRAMED_MTU, + 1500)) + return -1; + + /* State */ + if (req->attrInfo->serverStateLen != 0) + { + if (!radius_msg_add_attr(msg, RADIUS_ATTR_TYPE_STATE, + req->attrInfo->serverState, req->attrInfo->serverStateLen)) + return -1; + } + + /* NAS IP */ + if (req->nas_ip.family == AF_INET) + { + if (!radius_msg_add_attr(msg, RADIUS_ATTR_TYPE_NAS_IP_ADDRESS, + (u8 *) &(req->nas_ip.addr.ipv4.s_addr), 4)) + return -1; + } + +#ifdef CONFIG_IPV6 + /* NAS IPv6 */ + if (req->nas_ip.family == AF_INET6) + { + if (!radius_msg_add_attr(msg, RADIUS_ATTR_TYPE_NAS_IPV6_ADDRESS, + (u8 *) &(req->nas_ip.addr.ipv6.in6), 16)) + return -1; + } +#endif /* L7_IPV6_PACKAGE */ + + if (strlen(req->nas_id)) + { + if (!radius_msg_add_attr(msg, RADIUS_ATTR_TYPE_NAS_IDENTIFIER, + (u8 *) req->nas_id, strlen(req->nas_id))) + return -1; + } + + return 0; +} + +int radiusAccessRequestSend(void *req_attr) +{ + u8 radius_identifier; + access_req_info_t *req = (access_req_info_t *)req_attr; + struct radius_msg *msg; + + if (!req_attr) + return -1; + + if (radius_mab_server_id_get(req->cxt, &radius_identifier)) + return -1; + + msg = radius_msg_new(RADIUS_CODE_ACCESS_REQUEST, radius_identifier); + + if (!msg) + return -1; + + if (radius_msg_make_authenticator(msg) < 0) + goto fail; + + /* User-Name */ + if ((req->user_name) && (0 != req->user_name_len) && + (!radius_msg_add_attr(msg, RADIUS_ATTR_USER_NAME, + req->user_name, req->user_name_len))) { + goto fail; + } + + if (0 > radius_mab_attr_add(req, msg)) + goto fail; + + if (0 > radius_access_req_common_attr_add(req, msg)) + goto fail; + + msg->correlator = req->correlator; + req->msg_req = (void *)msg; + + return 0; + + +fail: + radius_msg_free(msg); + return -1; + +} + +int radius_get_resp_code(void *data, unsigned int *code) +{ + if ((!data) || (!code)) + return -1; + + struct radius_msg *msg = (struct radius_msg *)data; + struct radius_hdr *hdr = radius_msg_get_hdr(msg); + + *code = hdr->code; + return 0; +} + +int radius_get_req_correlator(struct radius_msg *data, unsigned int *code) +{ + if ((!data) || (!code)) + return -1; + + *code = data->correlator; + return 0; +} + +int radius_resp_req_map_validate(void *cxt, void *data, int msg_len) +{ + struct radius_msg *msg = (struct radius_msg *)data; + radius_client_receive_proces(cxt, RADIUS_AUTH, msg, msg_len); + return 0; +} + +#endif /* CONFIG_SONIC_RADIUS_MAB */ + +#endif /* CONFIG_SONIC_RADIUS */ diff --git a/src/radius/radius.h b/src/radius/radius.h index 630c0f9d0..bcae8d267 100644 --- a/src/radius/radius.h +++ b/src/radius/radius.h @@ -50,6 +50,9 @@ struct radius_attr_hdr { enum { RADIUS_ATTR_USER_NAME = 1, RADIUS_ATTR_USER_PASSWORD = 2, +#ifdef CONFIG_SONIC_RADIUS + RADIUS_ATTR_CHAP_PASSWORD = 3, +#endif RADIUS_ATTR_NAS_IP_ADDRESS = 4, RADIUS_ATTR_NAS_PORT = 5, RADIUS_ATTR_SERVICE_TYPE = 6, @@ -82,6 +85,9 @@ enum { RADIUS_ATTR_USER_NAME = 1, RADIUS_ATTR_ACCT_OUTPUT_GIGAWORDS = 53, RADIUS_ATTR_EVENT_TIMESTAMP = 55, RADIUS_ATTR_EGRESS_VLANID = 56, +#ifdef CONFIG_SONIC_RADIUS + RADIUS_ATTR_CHAP_CHALLENGE = 60, +#endif RADIUS_ATTR_NAS_PORT_TYPE = 61, RADIUS_ATTR_TUNNEL_TYPE = 64, RADIUS_ATTR_TUNNEL_MEDIUM_TYPE = 65, @@ -91,6 +97,9 @@ enum { RADIUS_ATTR_USER_NAME = 1, RADIUS_ATTR_MESSAGE_AUTHENTICATOR = 80, RADIUS_ATTR_TUNNEL_PRIVATE_GROUP_ID = 81, RADIUS_ATTR_ACCT_INTERIM_INTERVAL = 85, +#ifdef CONFIG_SONIC_RADIUS + RADIUS_ATTR_NAS_PORT_ID = 87, +#endif RADIUS_ATTR_CHARGEABLE_USER_IDENTITY = 89, RADIUS_ATTR_NAS_IPV6_ADDRESS = 95, RADIUS_ATTR_ERROR_CAUSE = 101, @@ -124,7 +133,11 @@ enum { RADIUS_ATTR_USER_NAME = 1, #define RADIUS_TERMINATION_ACTION_RADIUS_REQUEST 1 /* NAS-Port-Type */ +#ifdef CONFIG_SONIC_RADIUS +#define RADIUS_NAS_PORT_TYPE_IEEE_802_11 15 +#else #define RADIUS_NAS_PORT_TYPE_IEEE_802_11 19 +#endif /* Acct-Status-Type */ #define RADIUS_ACCT_STATUS_TYPE_START 1 @@ -338,4 +351,15 @@ u8 radius_msg_find_unlisted_attr(struct radius_msg *msg, u8 *attrs); int radius_gen_session_id(u8 *id, size_t len); +#ifdef CONFIG_SONIC_RADIUS +struct radius_msg * radius_copy_resp(struct radius_msg *msg); +int radiusAccessRequestSend(void *req_attr); +int radius_get_resp_code(void *data, unsigned int *code); +int radius_get_req_correlator(struct radius_msg *data, unsigned int *code); +int radius_resp_req_map_validate(void *cxt, void *data, int msg_len); +struct radius_msg * radius_client_update_auth_msg_data + (struct radius_msg *old_msg, + const u8 *shared_secret, + size_t shared_secret_len); +#endif #endif /* RADIUS_H */ diff --git a/src/radius/radius_attr_parse.c b/src/radius/radius_attr_parse.c new file mode 100644 index 000000000..d6aaee800 --- /dev/null +++ b/src/radius/radius_attr_parse.c @@ -0,0 +1,308 @@ +#include +#include +#include +#include +#include +#include "radius_attr_parse.h" +#include "utils/includes.h" +#include "utils/common.h" +#include "utils/wpabuf.h" +#include "wpa_debug.h" + +#define EAP_RRMD5 4 /* MD5-Challenge */ +#define CHALLENGE_LEN 16 + +int radiusUsernameAttrGet(radiusAttr_t *radiusAttr, attrInfo_t *attrInfo) +{ + RADIUS_IF_NULLPTR_RETURN(radiusAttr); + RADIUS_IF_NULLPTR_RETURN(attrInfo); + + memset(attrInfo->userName,'\0', sizeof(attrInfo->userName)); + memcpy(attrInfo->userName, + (char *)radiusAttr + sizeof(radiusAttr_t), + radiusAttr->length - sizeof(radiusAttr_t)); + attrInfo->userNameLen = radiusAttr->length - sizeof(radiusAttr_t); + attrInfo->attrFlags |= RADIUS_FLAG_ATTR_USER_NAME; + + return 0; +} + +int radiusServiceTypeAttrGet(radiusAttr_t *radiusAttr, attrInfo_t *attrInfo) +{ + unsigned int temp = 0; + RADIUS_IF_NULLPTR_RETURN(radiusAttr); + RADIUS_IF_NULLPTR_RETURN(attrInfo); + + attrInfo->attrFlags |= RADIUS_FLAG_ATTR_TYPE_SERVICE_TYPE; + memcpy(&temp, + ((char *)radiusAttr + sizeof(radiusAttr_t)), + radiusAttr->length - sizeof(radiusAttr_t)); + attrInfo->accessLevel = ntohl(temp); + + return 0; +} + +int radiusNasPortAttrGet(radiusAttr_t *radiusAttr, attrInfo_t *attrInfo) +{ + unsigned int nas_port = 0; + RADIUS_IF_NULLPTR_RETURN(radiusAttr); + + memcpy(&nas_port, + ((char *)radiusAttr + sizeof(radiusAttr_t)), + radiusAttr->length - sizeof(radiusAttr_t)); + nas_port = ntohl(nas_port); + + return nas_port; +} + + + +int radiusReplyMsgAttrGet(radiusAttr_t *radiusAttr, attrInfo_t *attrInfo) +{ + RADIUS_IF_NULLPTR_RETURN(radiusAttr); + RADIUS_IF_NULLPTR_RETURN(attrInfo); + + attrInfo->attrFlags |= RADIUS_FLAG_ATTR_REPLY_MSG; + return 0; +} + + +int radiusClassAttrGet(radiusAttr_t *radiusAttr, attrInfo_t *attrInfo) +{ + RADIUS_IF_NULLPTR_RETURN(radiusAttr); + RADIUS_IF_NULLPTR_RETURN(attrInfo); + + attrInfo->attrFlags |= RADIUS_FLAG_ATTR_TYPE_CLASS; + memset(attrInfo->serverClass,0, + SERVER_CLASS_LEN); + memcpy(attrInfo->serverClass, + (char *)radiusAttr + sizeof(radiusAttr_t), + radiusAttr->length - sizeof(radiusAttr_t)); + attrInfo->serverClassLen = + radiusAttr->length - sizeof(radiusAttr_t); + + return 0; +} + +int radiusStateAttrGet(radiusAttr_t *radiusAttr, attrInfo_t *attrInfo) +{ + RADIUS_IF_NULLPTR_RETURN(radiusAttr); + RADIUS_IF_NULLPTR_RETURN(attrInfo); + + attrInfo->attrFlags |= RADIUS_FLAG_ATTR_TYPE_STATE; + memset(attrInfo->serverState,0, + SERVER_STATE_LEN); + memcpy(attrInfo->serverState, + (char *)radiusAttr + sizeof(radiusAttr_t), + radiusAttr->length - sizeof(radiusAttr_t)); + attrInfo->serverStateLen = + radiusAttr->length - sizeof(radiusAttr_t); + + return 0; +} + +int radiusSessionTimeoutAttrGet(radiusAttr_t *radiusAttr, attrInfo_t *attrInfo) +{ + unsigned int attrVal = 0; + RADIUS_IF_NULLPTR_RETURN(radiusAttr); + RADIUS_IF_NULLPTR_RETURN(attrInfo); + + attrInfo->attrFlags |= RADIUS_FLAG_ATTR_TYPE_SESSION_TIMEOUT; + /* Set the sessionTimeout value which will be picked up by the timer state machine */ + memcpy((char *)&attrVal, (char *)radiusAttr + sizeof(radiusAttr_t), + radiusAttr->length - sizeof(radiusAttr_t)); + attrInfo->sessionTimeout = ntohl(attrVal); + + return 0; +} + +int radiusTerminationActionAttrGet(radiusAttr_t *radiusAttr, attrInfo_t *attrInfo) +{ + unsigned int attrVal = 0; + + RADIUS_IF_NULLPTR_RETURN(radiusAttr); + RADIUS_IF_NULLPTR_RETURN(attrInfo); + + attrInfo->attrFlags |= RADIUS_FLAG_ATTR_TYPE_TERMINATION_ACTION; + /* Set the terminationAction value which will be picked up by the timer state machine */ + memcpy((char *)&attrVal, (char *)radiusAttr + sizeof(radiusAttr_t), + radiusAttr->length - sizeof(radiusAttr_t)); + attrInfo->terminationAction = ntohl(attrVal); + + return 0; +} + + +int radiusEapMsgAttrGet(radiusAttr_t *radiusAttr, attrInfo_t *attrInfo) +{ + eapPacket_t *eapPkt; + + RADIUS_IF_NULLPTR_RETURN(radiusAttr); + RADIUS_IF_NULLPTR_RETURN(attrInfo); + + attrInfo->attrFlags |= RADIUS_FLAG_ATTR_TYPE_EAP_MESSAGE; + /* If this is the first EAP msg in the frame, save the ID and set flag. */ + if (attrInfo->rcvdEapAttr == false) + { + eapPkt = (eapPacket_t *)((char *)radiusAttr + sizeof(radiusAttr_t)); + attrInfo->idFromServer = eapPkt->id; + attrInfo->rcvdEapAttr = true; + } + + return 0; +} + +int radiusTunnelTypeAttrGet(radiusAttr_t *radiusAttr, attrInfo_t *attrInfo) +{ + unsigned int attrVal = 0; + RADIUS_IF_NULLPTR_RETURN(radiusAttr); + RADIUS_IF_NULLPTR_RETURN(attrInfo); + + attrInfo->attrFlags |= RADIUS_FLAG_ATTR_TYPE_TUNNEL_TYPE; + /* get the tunnel type */ + memcpy((char *)&attrVal, (char *)radiusAttr + sizeof(radiusAttr_t), + radiusAttr->length - sizeof(radiusAttr_t)); + if(((ntohl(attrVal)) & 0x00FFFFFF) == RADIUS_TUNNEL_TYPE_VLAN) + { + attrInfo->vlanAttrFlags |= 0x1; + } + + return 0; +} + +int radiusTunnelMediumAttrGet(radiusAttr_t *radiusAttr, attrInfo_t *attrInfo) +{ + unsigned int attrVal = 0; + RADIUS_IF_NULLPTR_RETURN(radiusAttr); + RADIUS_IF_NULLPTR_RETURN(attrInfo); + + attrInfo->attrFlags |= RADIUS_FLAG_ATTR_TYPE_TUNNEL_MEDIUM_TYPE; + /* get the tunnel medium type */ + memcpy((char *)&attrVal, (char *)radiusAttr + sizeof(radiusAttr_t), + radiusAttr->length - sizeof(radiusAttr_t)); + if(((ntohl(attrVal)) & 0x00FFFFFF) == RADIUS_TUNNEL_MEDIUM_TYPE_802) + { + attrInfo->vlanAttrFlags |= 0x2; + } + + return 0; +} + +int radiusTunnelGrpIdAttrGet(radiusAttr_t *radiusAttr, attrInfo_t *attrInfo) +{ + RADIUS_IF_NULLPTR_RETURN(radiusAttr); + RADIUS_IF_NULLPTR_RETURN(attrInfo); + + attrInfo->attrFlags |= RADIUS_FLAG_ATTR_TYPE_TUNNEL_PRIVATE_GROUP_ID; + char tagField; + unsigned int len=1; + unsigned int stringLen=0; + + memset(attrInfo->vlanString, 0, sizeof(attrInfo->vlanString)); + /* ignore the tag 1 byte */ + memcpy((char *)&tagField,(char *)radiusAttr + sizeof(radiusAttr_t),1); + + if(tagField > 0x1F) /* RFC 2868 Section 3.6 */ + { + len = 0; + } + + stringLen=(RADIUS_VLAN_ASSIGNED_LEN < ((radiusAttr->length - sizeof(radiusAttr_t))-len))? + RADIUS_VLAN_ASSIGNED_LEN:((radiusAttr->length - sizeof(radiusAttr_t))-len); + + memcpy((char *)attrInfo->vlanString, (char *)radiusAttr + sizeof(radiusAttr_t)+len, + stringLen); + + attrInfo->vlanAttrFlags |= 0x4; + + return 0; +} + +int radiusAttrNasPortValidate(unsigned int nas_port, radiusAttr_t *radiusAttr) +{ + if (nas_port != radiusNasPortAttrGet(radiusAttr, NULL)) + return -1; + return 0; +} + +int radiusChallengeCopy(radiusAttr_t *radiusAttr, challenge_info_t *get_data) +{ + radiusAttr_t *eapTlv; + unsigned char *eapBuf, *tempChallenge; + unsigned char ch; + + RADIUS_IF_NULLPTR_RETURN(radiusAttr); + RADIUS_IF_NULLPTR_RETURN(get_data); + + eapBuf = get_data->supp_data; + + memcpy(eapBuf, (unsigned char *)radiusAttr + sizeof(radiusAttr_t), + radiusAttr->length - sizeof(radiusAttr_t)); + + eapTlv = (radiusAttr_t *)((unsigned char *) eapBuf + sizeof(eapPacket_t)); + ch = (unsigned char )EAP_RRMD5; + if (memcmp(&eapTlv->type,(unsigned char *)&ch,sizeof(unsigned char))==0) + { + ch = (unsigned char )CHALLENGE_LEN; + if (memcmp(&eapTlv->length,(unsigned char *)&ch,sizeof(unsigned char))<=0) + { + *get_data->challenge_len = (unsigned int)eapTlv->length; + tempChallenge = (unsigned char *) ((unsigned char *) eapTlv + sizeof(radiusAttr_t)); + memset(get_data->challenge, 0, CHALLENGE_LEN); + memcpy(get_data->challenge,tempChallenge, *get_data->challenge_len); + } + else + { + /* length exceeds the limit. + fail to serve challenge.*/ + return -1; + } + } + return 0; +} + +int radiusAttrChallengeCopy(radiusAttr_t *radiusAttr, challenge_info_t *get_data) +{ + if (!radiusAttr || !get_data || !get_data->attrInfo) + return -1; + + radiusEapMsgAttrGet(radiusAttr, get_data->attrInfo); + + /* copy the challenge */ + radiusChallengeCopy(radiusAttr, get_data); + + return 0; +} + +int radiusAttrMapEntryGet(unsigned int attrType, radiusAttrParseFn_t *fn) +{ + static radiusAttrParseFnMap_t radiusAttrMapTbl[] = { + { RADIUS_ATTR_TYPE_USER_NAME, radiusUsernameAttrGet}, + { RADIUS_ATTR_TYPE_SERVICE_TYPE, radiusServiceTypeAttrGet}, + { RADIUS_ATTR_TYPE_REPLY_MESSAGE, radiusReplyMsgAttrGet}, + { RADIUS_ATTR_TYPE_CLASS, radiusClassAttrGet}, + { RADIUS_ATTR_TYPE_SESSION_TIMEOUT, radiusSessionTimeoutAttrGet}, + { RADIUS_ATTR_TYPE_TERMINATION_ACTION, radiusTerminationActionAttrGet}, + { RADIUS_ATTR_TYPE_EAP_MESSAGE, radiusEapMsgAttrGet}, + { RADIUS_ATTR_TYPE_TUNNEL_TYPE, radiusTunnelTypeAttrGet}, + { RADIUS_ATTR_TYPE_TUNNEL_MEDIUM_TYPE, radiusTunnelMediumAttrGet}, + { RADIUS_ATTR_TYPE_TUNNEL_PRIVATE_GROUP_ID, radiusTunnelGrpIdAttrGet}, + { RADIUS_ATTR_TYPE_NAS_PORT, radiusNasPortAttrGet}, + { RADIUS_ATTR_TYPE_STATE, radiusStateAttrGet}, + }; + + unsigned int i = 0; + + for (i = 0; i < (sizeof(radiusAttrMapTbl)/sizeof(radiusAttrParseFnMap_t)); i++) + { + if (attrType == radiusAttrMapTbl[i].attrType) + { + *fn = radiusAttrMapTbl[i].fn; + return 0; + } + } + + return -1; +} + + diff --git a/src/radius/radius_attr_parse.h b/src/radius/radius_attr_parse.h new file mode 100644 index 000000000..925ce618d --- /dev/null +++ b/src/radius/radius_attr_parse.h @@ -0,0 +1,706 @@ +#ifndef RADIUS_ATTR_PARSE_H +#define RADIUS_ATTR_PARSE_H + +#include + +#define L7_AF_INET 1 +#define L7_AF_INET6 2 + + + +#define RADIUS_VALUE_LENGTH 253 + +#define RADIUS_ATTR_TYPE_USER_NAME 1 +#define RADIUS_ATTR_TYPE_USER_PASSWORD 2 +#define RADIUS_ATTR_TYPE_CHAP_PASSWORD 3 +#define RADIUS_ATTR_TYPE_NAS_IP_ADDRESS 4 +#define RADIUS_ATTR_TYPE_NAS_PORT 5 +#define RADIUS_ATTR_TYPE_SERVICE_TYPE 6 +#define RADIUS_ATTR_TYPE_FRAMED_PROTOCOL 7 +#define RADIUS_ATTR_TYPE_FRAMED_IP_ADDRESS 8 +#define RADIUS_ATTR_TYPE_FRAMED_IP_NETMASK 9 +#define RADIUS_ATTR_TYPE_FRAMED_ROUTING 10 +#define RADIUS_ATTR_TYPE_FILTER_ID 11 +#define RADIUS_ATTR_TYPE_FRAMED_MTU 12 +#define RADIUS_ATTR_TYPE_FRAMED_COMPRESSION 13 +#define RADIUS_ATTR_TYPE_LOGIN_IP_HOST 14 +#define RADIUS_ATTR_TYPE_LOGIN_SERVICE 15 +#define RADIUS_ATTR_TYPE_LOGIN_TCP_PORT 16 + +#define RADIUS_ATTR_TYPE_REPLY_MESSAGE 18 +#define RADIUS_ATTR_TYPE_CALLBACK_NUMBER 19 +#define RADIUS_ATTR_TYPE_CALLBACK_ID 20 + +#define RADIUS_ATTR_TYPE_FRAMED_ROUTE 22 +#define RADIUS_ATTR_TYPE_FRAMED_IPX_NETWORK 23 +#define RADIUS_ATTR_TYPE_STATE 24 +#define RADIUS_ATTR_TYPE_CLASS 25 +#define RADIUS_ATTR_TYPE_VENDOR 26 +#define RADIUS_ATTR_TYPE_SESSION_TIMEOUT 27 +#define RADIUS_ATTR_TYPE_IDLE_TIMEOUT 28 +#define RADIUS_ATTR_TYPE_TERMINATION_ACTION 29 +#define RADIUS_ATTR_TYPE_CALLED_STATION_ID 30 +#define RADIUS_ATTR_TYPE_CALLING_STATION_ID 31 +#define RADIUS_ATTR_TYPE_NAS_IDENTIFIER 32 +#define RADIUS_ATTR_TYPE_PROXY_STATE 33 +#define RADIUS_ATTR_TYPE_LOGIN_LAT_SERVICE 34 +#define RADIUS_ATTR_TYPE_LOGIN_LAT_NODE 35 +#define RADIUS_ATTR_TYPE_LOGIN_LAT_GROUP 36 +#define RADIUS_ATTR_TYPE_FRAMED_APPLETALK_LINK 37 +#define RADIUS_ATTR_TYPE_FRAMED_APPLETALK_NETWORK 38 +#define RADIUS_ATTR_TYPE_FRAMED_APPLETALK_ZONE 39 +#define RADIUS_ATTR_TYPE_ACCT_STATUS_TYPE 40 +#define RADIUS_ATTR_TYPE_ACCT_DELAY_TIME 41 +#define RADIUS_ATTR_TYPE_ACCT_INPUT_OCTETS 42 +#define RADIUS_ATTR_TYPE_ACCT_OUTPUT_OCTETS 43 +#define RADIUS_ATTR_TYPE_ACCT_SESSION_ID 44 +#define RADIUS_ATTR_TYPE_ACCT_AUTHENTIC 45 +#define RADIUS_ATTR_TYPE_ACCT_SESSION_TIME 46 +#define RADIUS_ATTR_TYPE_ACCT_INPUT_PACKETS 47 +#define RADIUS_ATTR_TYPE_ACCT_OUTPUT_PACKETS 48 +#define RADIUS_ATTR_TYPE_ACCT_TERMINATE_CAUSE 49 +#define RADIUS_ATTR_TYPE_ACCT_MULTI_SESSION_ID 50 +#define RADIUS_ATTR_TYPE_ACCT_LINK_COUNT 51 +#define RADIUS_ATTR_TYPE_ACCT_G_IBYTES 52 +#define RADIUS_ATTR_TYPE_ACCT_G_OBYTES 53 + +#define RADIUS_ATTR_TYPE_EVENT_TIMESTAMP 55 + +#define RADIUS_ATTR_TYPE_CHAP_CHALLENGE 60 +#define RADIUS_ATTR_TYPE_NAS_PORT_TYPE 61 +#define RADIUS_ATTR_TYPE_PORT_LIMIT 62 +#define RADIUS_ATTR_TYPE_LOGIN_LAST_PORT 63 +#define RADIUS_ATTR_TYPE_TUNNEL_TYPE 64 +#define RADIUS_ATTR_TYPE_TUNNEL_MEDIUM_TYPE 65 + +#define RADIUS_ATTR_TYPE_CONNECT_INFO 77 + +#define RADIUS_ATTR_TYPE_EAP_MESSAGE 79 +#define RADIUS_ATTR_TYPE_MESSAGE_AUTHENTICATOR 80 +#define RADIUS_ATTR_TYPE_TUNNEL_PRIVATE_GROUP_ID 81 +#define RADIUS_ATTR_TYPE_NAS_PORT_ID 87 +#define RADIUS_ATTR_TYPE_NAS_FILTER_RULE 92 +#define RADIUS_ATTR_TYPE_NAS_IPV6_ADDRESS 95 +#define RADIUS_ATTR_TYPE_EAP_KEY_NAME 102 +#define RADIUS_ATTR_TYPE_FRAMED_IPV6_ADDRESS 168 + +#define RADIUS_ATTR_TYPE_VLAN_ID 199 + + +#define RADIUS_ATTR_SIZE_SERVICE_TYPE 6 +/* +** The Service-Type value codes +*/ +#define RADIUS_SERVICE_TYPE_LOGIN 1 +#define RADIUS_SERVICE_TYPE_FRAMED 2 +#define RADIUS_SERVICE_TYPE_CALLBACK_LOGIN 3 +#define RADIUS_SERVICE_TYPE_CALLBACK_FRAMED 4 +#define RADIUS_SERVICE_TYPE_OUTBOUND 5 +#define RADIUS_SERVICE_TYPE_ADMIN 6 +#define RADIUS_SERVICE_TYPE_NAS_PROMPT 7 +#define RADIUS_SERVICE_TYPE_AUTHEN_ONLY 8 +#define RADIUS_SERVICE_TYPE_CALLBACK_NAS_PROMPT 9 +#define RADIUS_SERVICE_TYPE_CALL_CHECK 10 + +/* +** The Framed Protocol value types +*/ +#define RADIUS_FRAMED_PROTOCOL_PPP 1 +#define RADIUS_FRAMED_PROTOCOL_SLIP 2 +#define RADIUS_FRAMED_PROTOCOL_ARAP 3 +#define RADIUS_FRAMED_PROTOCOL_SLP_MLP 4 +#define RADIUS_FRAMED_PROTOCOL_IPX_SLIP 5 + +/* +** The Framed Routing value types +*/ +#define RADIUS_FRAMED_ROUTING_NONE 0 +#define RADIUS_FRAMED_ROUTING_SEND 1 +#define RADIUS_FRAMED_ROUTING_LISTEN 2 +#define RADIUS_FRAMED_ROUTING_SEND_LISTEN 3 + +/* +** The Framed Compression value types +*/ +#define RADIUS_FRAMED_COMPRESSION_NONE 0 +#define RADIUS_FRAMED_COMPRESSION_VJ_TCPIP 1 +#define RADIUS_FRAMED_COMPRESSION_IPX_HDR 2 + +/* +** The Login Service value codes +*/ +#define RADIUS_LOGIN_SERVICE_TELNET 0 +#define RADIUS_LOGIN_SERVICE_RLOGIN 1 +#define RADIUS_LOGIN_SERVICE_TCP_CLEAR 2 +#define RADIUS_LOGIN_SERVICE_PORT_MASTER 3 +#define RADIUS_LOGIN_SERVICE_LAST 4 + +/* +** The Termination Action value codes +*/ +#define RADIUS_TERMINATION_ACTION_DEFAULT 0 +#define RADIUS_TERMINATION_ACTION_RADIUS 1 + +/* +** NAS Port Types +*/ +#define RADIUS_NAS_PORT_TYPE_ASYNC 0 +#define RADIUS_NAS_PORT_TYPE_SYNC 1 +#define RADIUS_NAS_PORT_TYPE_ISDN_SYNC 2 +#define RADIUS_NAS_PORT_TYPE_ISDN_SYNC_V120 3 +#define RADIUS_NAS_PORT_TYPE_ISDN_SYNC_V110 4 +#define RADIUS_NAS_PORT_TYPE_VIRTUAL 5 +#define RADIUS_NAS_PORT_TYPE_PIAFS 6 +#define RADIUS_NAS_PORT_TYPE_HDLC_CLEAR_CHANNEL 7 +#define RADIUS_NAS_PORT_TYPE_X25 8 +#define RADIUS_NAS_PORT_TYPE_X75 9 +#define RADIUS_NAS_PORT_TYPE_G3_FAX 10 +#define RADIUS_NAS_PORT_TYPE_SDSL 11 +#define RADIUS_NAS_PORT_TYPE_ADSL_CAP 12 +#define RADIUS_NAS_PORT_TYPE_ADSL_DMT 13 +#define RADIUS_NAS_PORT_TYPE_IDSL 14 +#define RADIUS_NAS_PORT_TYPE_ETHERNET 15 +#define RADIUS_NAS_PORT_TYPE_XDSL 16 +#define RADIUS_NAS_PORT_TYPE_CABLE 17 +#define RADIUS_NAS_PORT_TYPE_WIRELESS_OTHER 18 +#define RADIUS_NAS_PORT_TYPE_WIRELESS_802_11 19 + +/* +** The Account-Status-Type value codes +*/ +#define RADIUS_ACCT_STATUS_TYPE_START 1 +#define RADIUS_ACCT_STATUS_TYPE_STOP 2 +#define RADIUS_ACCT_STATUS_TYPE_INTERIM 3 + +/* +** Radius Account Authentic value codes +*/ +#define RADIUS_ACCT_AUTHENTIC_RADIUS 1 +#define RADIUS_ACCT_AUTHENTIC_LOCAL 2 +#define RADIUS_ACCT_AUTHENTIC_REMOTE 3 + +/* +** The Accounting Termination Cause value codes +*/ +#define RADIUS_ACCT_TERM_CAUSE_USER_REQUEST 1 +#define RADIUS_ACCT_TERM_CAUSE_LOST_CARRIER 2 +#define RADIUS_ACCT_TERM_CAUSE_LOST_SERVICE 3 +#define RADIUS_ACCT_TERM_CAUSE_IDLE_TIMEOUT 4 +#define RADIUS_ACCT_TERM_CAUSE_SESSION_TIMEOUT 5 +#define RADIUS_ACCT_TERM_CAUSE_ADMIN_RESET 6 +#define RADIUS_ACCT_TERM_CAUSE_ADMIN_REBOOT 7 +#define RADIUS_ACCT_TERM_CAUSE_PORT_ERROR 8 +#define RADIUS_ACCT_TERM_CAUSE_NAS_ERROR 9 +#define RADIUS_ACCT_TERM_CAUSE_NAS_REQUEST 10 +#define RADIUS_ACCT_TERM_CAUSE_NAS_REBOOT 11 +#define RADIUS_ACCT_TERM_CAUSE_PORT_UNNEEDED 12 +#define RADIUS_ACCT_TERM_CAUSE_PORT_PREEMPTED 13 +#define RADIUS_ACCT_TERM_CAUSE_PORT_SUSPENDED 14 +#define RADIUS_ACCT_TERM_CAUSE_SERVICE_UNAVAILABLE 15 +#define RADIUS_ACCT_TERM_CAUSE_CALLBACK 16 +#define RADIUS_ACCT_TERM_CAUSE_USER_ERROR 17 +#define RADIUS_ACCT_TERM_CAUSE_HOST_REQUEST 18 +#define RADIUS_ACCT_TERM_CAUSE_SUPPLICANT_RESTART 19 +#define RADIUS_ACCT_TERM_CAUSE_REAUTHENTICATION_FAILURE 20 +#define RADIUS_ACCT_TERM_CAUSE_PORT_REINITIALIZED 21 +#define RADIUS_ACCT_TERM_CAUSE_PORT_ADMINISTRATIVELY_DISABLED 22 + +/* +** The types of the attribute values in storage representation +*/ +#define RADIUS_ATTR_VALUE_TYPE_STRING 1 +#define RADIUS_ATTR_VALUE_TYPE_INTEGER 2 +#define RADIUS_ATTR_VALUE_TYPE_IP_ADDR 3 +#define RADIUS_ATTR_VALUE_TYPE_DATE 4 + +/* +** The LVL7 vendor-specific wireless attribute types +*/ +#define LVL7_MAX_INPUT_OCTETS_VATTR 124 +#define LVL7_MAX_OUTPUT_OCTETS_VATTR 125 +#define LVL7_MAX_TOTAL_OCTETS_VATTR 126 +#define LVL7_CAPTIVE_PORTAL_GROUPS_VATTR 127 + +/* + ** Microsoft vendor specific attribute +*/ +#define RADIUS_VENDOR_ID_MICROSOFT 311 +#if 0 +#define RADIUS_VENDOR_ATTR_MS_MPPE_SEND_KEY 16 +#define RADIUS_VENDOR_ATTR_MS_MPPE_RECV_KEY 17 +#endif +/* + ** Wireless ISP - roaming (WISPr) vendor specific attributes +*/ +#define RADIUS_VENDOR_ID_WISPR 14122 + +#define RADIUS_VENDOR_ATTR_WISPR_BANDWIDTH_MAX_UP 7 +#define RADIUS_VENDOR_ATTR_WISPR_BANDWIDTH_MAX_DOWN 8 + + +/* The type of attribute values for Tunnel Type attribute +*/ +#define RADIUS_TUNNEL_TYPE_VLAN 13 + + +/* The type of attribute values for Tunnel Medium type attribute +*/ +#define RADIUS_TUNNEL_MEDIUM_TYPE_802 6 + +#define RADIUS_ATTR_TYPE_TUNNEL_TYPE_SPECIFIED 0x1 +#define RADIUS_ATTR_TYPE_TUNNEL_MEDIUM_TYPE_SPECIFIED 0x2 +#define RADIUS_ATTR_TYPE_TUNNEL_PRIVATE_GROUP_ID_SPECIFIED 0x4 +#define RADIUS_REQUIRED_TUNNEL_ATTRIBUTES_SPECIFIED 0x7 + +#define RADIUS_TOKEN_LENGTH 32 + +#define RADIUS_AUTHENTICATOR_LENGTH 16 + +#define RADIUS_MS_KEY_SIZE 256 + +#define RADIUS_MS_KEY_SALT_LEN 2 + +#define RADIUS_VENDOR_ID_SIZE 4 + +#define RADIUS_VEND_ATTR_VEND_TYPE_SIZE 1 +#define RADIUS_VEND_ATTR_VEND_LEN_SIZE 1 +#define RADIUS_VEND_ATTR_HEAD_SIZE (RADIUS_VENDOR_ID_SIZE + \ + RADIUS_VEND_ATTR_VEND_TYPE_SIZE + \ + RADIUS_VEND_ATTR_VEND_LEN_SIZE) + +/* + * Cisco vendor specific attributes + */ +#define RADIUS_VENDOR_ID_CISCO 9 +#define RADIUS_VENDOR_ATTR_CISCO_AV_PAIR 1 +#define RADIUS_VENDOR_ROLES_ATTR "shell:roles" +#define RADIUS_VENDOR_PRIV_LVL_ATTR "shell:priv-lvl=" + + + +#define VENDOR_ATTR_LEN 256 + +/* + * ** The Termination Action value codes + * */ +#define TERMINATION_ACTION_DEFAULT 0 +#define TERMINATION_ACTION_RADIUS 1 + + +#define SERVER_STATE_LEN 253 +#define SERVER_CLASS_LEN 253 + + +#define FILTER_NAME_LEN 256 +#define ACL_NAME_LEN 256 +#define MAX_ACL_RULES_SIZE 4096 + +#define RADIUS_VLAN_ASSIGNED_LEN 32 /* Radius Assigned vlan length */ +#define ACL_NAME_LEN_MAX 128 + + /* Supports 1 Ipv4 and 1 Ipv6 and each name should be appended by \n as the delimiter and 1 character for null termination. */ +#define MAX_REDIRECT_ACL_SIZE 2 * (ACL_NAME_LEN_MAX + 1 + 1) + +#define ACLS_MAX 4 /* none, ipv4, ipv6 and mac */ + + +#define MAX_ACL_RULES_STRING_SIZE 255 +#define MAX_ACL_RULES 128 +#define RULES_BUFF_MAX MAX_ACL_RULES*MAX_ACL_RULES_STRING_SIZE + +#define MAX_FRAMED_IPV6_ADDRESS_SIZE 16 + +#define REDIRECT_URL_LEN 256 +#define EAP_KEY_NAME_LEN 256 +#define RADIUS_MS_KEY_SIZE 256 /* This value should be same as that of the RADIUS_MS_KEY_SIZE value */ +#define VENDOR_ATTR_LEN 256 + +#define VENDOR_ATTR_LEN 256 + +#define RADIUS_VENDOR_9 0 +#define RADIUS_VENDOR_311 1 + +#define MAX_VENDOR_IDS 2 /* 0 -none, cisco , msft */ + + +#define LOGF syslog + + +#define EAP_AWARE_CLIENT 1 +#define EAP_UNAWARE_CLIENT 2 + +#define MAB_AUTH_TYPE_EAP_MD5 1 +#define MAB_AUTH_TYPE_PAP 2 +#define MAB_AUTH_TYPE_CHAP 3 + +#define RADIUS_VENDOR_DEVICE_CLASS_VOICE "device-traffic-class=voice" +#define RADIUS_VENDOR_DEVICE_CLASS_SWITCH "device-traffic-class=switch" + + + +/* MACsec attribute */ +#define RADIUS_LINKSEC_POLICY_PATTERN "linksec-policy=" +#define RADIUS_VENDOR_MUST_SECURE_ATTR "must-secure" +#define RADIUS_VENDOR_SHOULD_SECURE_ATTR "should-secure" +#define RADIUS_VENDOR_MUST_NOT_SECURE_ATTR "must-not-secure" + +#define RADIUS_ACS_SEC_DACL_NAME "xACSACLx-IP" +#define RADIUS_DACL_PATTERN ":inacl" +#define RADIUS_REDIRECT_URL_PATTERN "url-redirect=" +#define RADIUS_REDIRECT_ACL_PATTERN "url-redirect-acl=" +#define RADIUS_CISCOSECURE_ATTR "ACS:CiscoSecure-Defined-ACL" +#define RADIUS_CISCOSECURE_V6_ATTR "ipv6:CiscoSecure-Defined-ACL" + +#define RADIUS_ATTR_VAL_IPADM "aaa:service=ip_admission" +#define RADIUS_ATTR_VAL_IPDOWN "aaa:event=acl-download" + +#define RADIUS_VENDOR_9_VOICE 1<<0 +#define RADIUS_VENDOR_9_DACL 1<<1 +#define RADIUS_VENDOR_9_SWITCH 1<<2 +#define RADIUS_VENDOR_9_REDIRECT_URL 1<<3 +#define RADIUS_VENDOR_9_REDIRECT_ACL 1<<4 +#define RADIUS_VENDOR_9_ACS_SEC_DACL 1<<5 +#define RADIUS_VENDOR_9_LINKSEC_POLICY 1<<6 + +#define RADIUS_VENDOR_311_MS_MPPE_SEND_KEY 1<<0 +#define RADIUS_VENDOR_311_MS_MPPE_RECV_KEY 1<<1 + +#define RADIUS_VENDOR9_ACS_SEC_DACL_MASK_POS 1 <<0 +#define RADIUS_VENDOR9_REDIRECT_ACL_MASK_POS 1 <<1 +#define RADIUS_IF_NULLPTR_RETURN(_p) \ + if (NULL == _p) \ + { \ + return -1; \ + } + +typedef enum clientStatus_e +{ + NEW_CLIENT = 1, + AUTH_FAIL, + AUTH_SUCCESS, + AUTH_TIMEOUT, + AUTH_SERVER_COMM_FAILURE, + CLIENT_DISCONNECTED, + METHOD_CHANGE, + RADIUS_SERVERS_DEAD, + RADIUS_FIRST_PASS_DACL_DATA, + RADIUS_DACL_INFO, + MKA_PEER_TIMEOUT +} clientStatus_t; + +typedef enum radiusAttrFlags_s +{ + RADIUS_FLAG_ATTR_TYPE_STATE = (1 << 0), + RADIUS_FLAG_ATTR_TYPE_SERVICE_TYPE = (1 << 1), + RADIUS_FLAG_ATTR_TYPE_CLASS = (1 << 2), + RADIUS_FLAG_ATTR_TYPE_SESSION_TIMEOUT = (1 << 3), + RADIUS_FLAG_ATTR_TYPE_TERMINATION_ACTION = (1 << 4), + RADIUS_FLAG_ATTR_TYPE_EAP_MESSAGE = (1 << 5), + RADIUS_FLAG_ATTR_TYPE_VENDOR = (1 << 6), + RADIUS_FLAG_ATTR_TYPE_FILTER_ID = (1 << 7), + RADIUS_FLAG_ATTR_TYPE_TUNNEL_TYPE = (1 << 8), + RADIUS_FLAG_ATTR_TYPE_TUNNEL_MEDIUM_TYPE = (1 << 9), + RADIUS_FLAG_ATTR_TYPE_TUNNEL_PRIVATE_GROUP_ID = (1 << 10), + RADIUS_FLAG_ATTR_TYPE_FRAMED_IP_ADDRESS = (1 << 11), + RADIUS_FLAG_ATTR_TYPE_FRAMED_IPV6_ADDRESS = (1 << 12), + RADIUS_FLAG_ATTR_TYPE_ACS_SEC_DACL_TYPE = (1 << 13), + RADIUS_FLAG_ATTR_TYPE_EAP_KEY_NAME = (1 << 14), + RADIUS_FLAG_ATTR_USER_NAME = (1 << 15), + RADIUS_FLAG_ATTR_REPLY_MSG = (1 << 16) +}radiusAttrFlags_t; + +typedef enum macsecLinkSecPolicy_s +{ + MACSEC_LINKSEC_POLICY_INVALID = 0, + + /* Secure connection if both peers are MACsec capable */ + MACSEC_LINKSEC_POLICY_SHOULD_SECURE, + + /* Host traffic will be dropped unless it successfully negotiates MACsec. */ + MACSEC_LINKSEC_POLICY_MUST_SECURE, + + /* MACsec disabled. */ + MACSEC_LINKSEC_POLICY_MUST_NOT_SECURE +} macsecLinksecPolicy_t; + +typedef struct in4_addr_s +{ + unsigned int s_addr; /* 32 bit IPv4 address in network byte order */ +}in4_addr_t; + +/*************************************** + * * + * * 128-bit IP6 address. + * ***************************************/ +typedef struct in6_addr_s +{ + union + { + unsigned char addr8[16]; + unsigned short addr16[8]; + unsigned int addr32[4]; + } in6; +}in6_addr_t; + + +typedef struct inet_addr_s +{ + unsigned char family; /* AF_INET, AF_INET6, ... */ + union + { + struct in4_addr_s ipv4; + struct in6_addr_s ipv6; + } addr; +} inet_addr_t; + +typedef struct radiusAttr_s +{ + unsigned char type; + unsigned char length; /* length of entire attribute including the type and length fields */ +}radiusAttr_t; + +/* EAP packet header */ +typedef struct eapPacket_s +{ + unsigned char code; + unsigned char id; + unsigned short length; +} eapPacket_t; + +typedef struct vendorInfo_s +{ + unsigned int vendorId; + unsigned int vendorMask; +}vendorInfo_t; + +typedef struct daclRules_s +{ + unsigned int count; + unsigned int byte_count; + unsigned char *rulesBuff; +}daclRules_t; + + +typedef struct attr_named_lists_s +{ + unsigned char mask; + unsigned char name1[256]; + unsigned char name2[256]; +}attr_named_lists_t; + +typedef struct keyInfo_s +{ + unsigned char key[RADIUS_MS_KEY_SIZE]; + unsigned char keyLen; +} keyInfo_t; + +typedef struct attrInfo_s +{ + unsigned char userName[65]; + unsigned int userNameLen; + + unsigned char serverState[SERVER_STATE_LEN]; + unsigned int serverStateLen; + + unsigned char serverClass[SERVER_CLASS_LEN]; + unsigned int serverClassLen; + + unsigned int sessionTimeout; + unsigned int terminationAction; + + unsigned int accessLevel; + unsigned char idFromServer; /* Most recent ID in EAP pkt received from Auth Server (0-255) */ + unsigned char vlanString[RADIUS_VLAN_ASSIGNED_LEN+1]; + unsigned int vlanId; /* parsed VLAN id from vlan string */ + unsigned int attrFlags; + unsigned int vlanAttrFlags; + bool rcvdEapAttr; +}attrInfo_t; + +typedef struct challenge_info_s +{ + unsigned int nas_port; + char *challenge; + unsigned int *challenge_len; + attrInfo_t *attrInfo; + unsigned char *supp_data; +}challenge_info_t; + +typedef struct access_req_info_s +{ + char *user_name; + unsigned int user_name_len; + + char *chap_password; + unsigned int chap_password_len; + + char *challenge; + unsigned int challenge_len; + + unsigned int mab_auth_type; + + char *calledId; + unsigned int calledId_len; + + char *callingId; + unsigned int callingId_len; + + unsigned int nas_port; + + char *nas_portid; + unsigned int nas_portid_len; + + char *supp_eap_data; + unsigned int correlator; + + attrInfo_t *attrInfo; + unsigned char supp_mac[6]; + + inet_addr_t nas_ip; + unsigned char nas_id[64]; + + void *msg_req; + void *cxt; +}access_req_info_t; + +typedef struct acs_access_req_info_s +{ + char *user_name; + unsigned int user_name_len; + + char *serverState; + unsigned int server_state_len; + + unsigned int correlator; + + unsigned char supp_mac[6]; + void *msg_req; + void *cxt; +}acs_access_req_info_t; + +typedef struct clientAuthInfo_s +{ + unsigned char addr[6]; + unsigned int eapolVersion; + char bam_used[64]; + attrInfo_t attrInfo; + char userName[65]; + unsigned int userNameLength; +}clientAuthInfo_t; + +typedef struct clientStatusReply_s +{ + char intf[66]; + char method[64]; + unsigned int status; + union + { + clientAuthInfo_t authInfo; + char enableStatus[64]; + }info; +}clientStatusReply_t; + +typedef enum radius_mab_cmd_s +{ + RADIUS_MAB_CMD_NONE = 0, + RADIUS_MAB_SERVER_ADD, + RADIUS_MAB_SERVER_MODIFY, + RADIUS_MAB_SERVER_DELETE, + RADIUS_MAB_GLOBAL_CFG, + RADIUS_MAB_SERVERS_RELOAD, + RADIUS_MAB_SERVER_ELOOP_TERMINATE +}radius_mab_cmd_t; + + +typedef struct mab_key_s +{ + unsigned char key[65]; + unsigned int key_len; +}mab_key_t; + + +typedef struct mab_radius_server_s +{ + unsigned char radius_type[64]; /* auth or accounting */ + unsigned char serv_addr[128]; + unsigned char serv_port[32]; + unsigned char serv_priority[32]; + mab_key_t key; +}mab_radius_server_t; + +typedef struct mab_radius_access_req_s +{ + void *req_attr; + void *msg; +}mab_radius_access_req_t; + +typedef struct mab_radius_cmd_msg_s +{ + unsigned char cmd[32]; + union { + mab_radius_server_t server; + mab_radius_access_req_t access_req; + unsigned char mab_cli_mac_addr[6 /*ETH_ALEN*/]; + }cmd_data; + void *data; +}mab_radius_cmd_msg_t; + +typedef void(*mabRadiusCmdFn_t) (void *cxt, void *cmd_data); + +typedef struct radius_mab_cmd_entry_s +{ + unsigned char *cmd; + mabRadiusCmdFn_t hdlr; +}radius_mab_cmd_entry_t; + +typedef int(*radiusAttrParseFn_t) (radiusAttr_t *radiusAttr, attrInfo_t *attrInfo); + +int radiusAttrMapEntryGet(unsigned int attrType, radiusAttrParseFn_t *fn); + +typedef struct radiusAttrParseFnMap_s +{ + unsigned int attrType; + radiusAttrParseFn_t fn; +}radiusAttrParseFnMap_t; + +int radiusVendorAttrGet(radiusAttr_t *radiusAttr, attrInfo_t *attrInfo); + +int radiusClientAcceptProcess(void *msg, attrInfo_t *attrInfo); +int radiusClientChallengeProcess(void *radiusMsg, challenge_info_t *get_data); +int radiusAttrNasPortValidate(unsigned int nas_port, radiusAttr_t *radiusAttr); +int radiusChallengeCopy(radiusAttr_t *radiusAttr, challenge_info_t *get_data); +int radiusAttrChallengeCopy(radiusAttr_t *radiusAttr, challenge_info_t *get_data); +int radius_mab_server_send(void *req, void *msg); +int radius_acs_mab_server_send(void *req, void *msg); +int radius_mab_server_id_get(void *req, unsigned char *radius_identifier); +int radius_mab_current_auth_server_key_get(void *req, unsigned char *shared_secret, + size_t *shared_secret_len); +int radius_server_update(bool op, void *data, mab_radius_server_t *server); +#if 0 +int radius_server_update(bool op, void *data, const char *radius_type, + const char *serv_addr, const char *serv_priority, + const char *radius_key, const char *serv_port); +#endif +int radius_client_get_stats(void *data, char *buf, size_t buflen); + +void mab_eloop_register(int fd, void *data); +int mab_radius_client_alloc(void **data); +void mab_radius_server_run(void *data); +int radius_mab_resp_req_map_validate(void *cxt, void *data, int msg_len); +void radius_mab_cmd_req_send(int client_fd, char *req, size_t req_len); +void radius_mab_client_flush(void *data); +void mab_radius_server_add(void *data, void *server); +void mab_radius_server_delete(void *data, void *server); +void mab_radius_server_reload(void *data, void *server); +void mab_radius_server_eloop_terminate(void *data, void *server); +void mab_radius_client_access_req_send(void *data, void *req); +void mab_radius_client_acs_access_req_send(void *data, void *req); +void mab_radius_client_clear_radius_msgs(void *data, void *req); +int radius_get_dwld_acl_type_get(void *attrInfo); +void** radius_sec_acl_req_rules_mem_get(unsigned int type, void *attrInfo); +unsigned char* radius_sec_acl_req_name_get(unsigned int type, void *attrInfo); +void mab_radius_server_debug_level_set(int level); +int mab_radius_server_debug_level_get(); +int radius_named_list_mask_clear(unsigned int pos, void *p); +int radius_dwld_pos_mask_clear_validate(unsigned int pos, void *p); +#endif diff --git a/src/radius/radius_client.c b/src/radius/radius_client.c index 2b7a604ed..1d9063e05 100644 --- a/src/radius/radius_client.c +++ b/src/radius/radius_client.c @@ -13,6 +13,12 @@ #include "radius_client.h" #include "eloop.h" +#ifdef CONFIG_SONIC_RADIUS +#include +#include +#include +#endif + /* Defaults for RADIUS retransmit values (exponential backoff) */ /** @@ -669,7 +675,9 @@ static void radius_client_list_add(struct radius_client_data *radius, size_t shared_secret_len, const u8 *addr) { struct radius_msg_list *entry, *prev; - +#ifdef CONFIG_SONIC_RADIUS + struct radius_hdr *hdr; +#endif if (eloop_terminated()) { /* No point in adding entries to retransmit queue since event * loop has already been terminated. */ @@ -702,8 +710,16 @@ static void radius_client_list_add(struct radius_client_data *radius, radius->msgs = entry; radius_client_update_timeout(radius); +#ifdef CONFIG_SONIC_RADIUS + hdr = radius_msg_get_hdr(msg); +#endif + if (radius->num_msgs >= RADIUS_CLIENT_MAX_ENTRIES) { +#ifdef CONFIG_SONIC_RADIUS + wpa_printf(MSG_INFO, "RADIUS: Removing the oldest un-ACKed packet due to retransmit list limits. num_msgs = %zd", radius->num_msgs); +#else wpa_printf(MSG_INFO, "RADIUS: Removing the oldest un-ACKed packet due to retransmit list limits"); +#endif prev = NULL; while (entry->next) { prev = entry; @@ -713,11 +729,19 @@ static void radius_client_list_add(struct radius_client_data *radius, prev->next = NULL; radius_client_msg_free(entry); } +#ifdef CONFIG_SONIC_RADIUS + } else { + radius->num_msgs++; + hostapd_logger(radius->ctx, NULL, HOSTAPD_MODULE_RADIUS, + HOSTAPD_LEVEL_DEBUG, "added RADIUS client to the list (type %d id=%d)" + " num_msgs %zu", msg_type, hdr->identifier, radius->num_msgs); + } +#else } else radius->num_msgs++; +#endif } - /** * radius_client_send - Send a RADIUS request * @radius: RADIUS client context from radius_client_init() @@ -908,8 +932,14 @@ static void radius_client_receive(int sock, void *eloop_ctx, void *sock_ctx) hostapd_logger(radius->ctx, req->addr, HOSTAPD_MODULE_RADIUS, HOSTAPD_LEVEL_DEBUG, "Received RADIUS packet matched with a pending " +#ifdef CONFIG_SONIC_RADIUS + "request (type=%d id=%d), round trip time %d.%02d sec", + msg_type, hdr->identifier, + roundtrip / 100, roundtrip % 100); +#else "request, round trip time %d.%02d sec", roundtrip / 100, roundtrip % 100); +#endif rconf->round_trip_time = roundtrip; /* Remove ACKed RADIUS packet from retransmit list */ @@ -957,6 +987,141 @@ static void radius_client_receive(int sock, void *eloop_ctx, void *sock_ctx) } + +#ifdef CONFIG_SONIC_RADIUS +void radius_client_receive_proces(void *cxt, + RadiusType msg_type, + struct radius_msg *msg, int len) +{ + struct radius_client_data *radius = cxt; + struct hostapd_radius_servers *conf = radius->conf; + int roundtrip; + struct radius_hdr *hdr; + struct radius_rx_handler *handlers; + size_t num_handlers, i; + struct radius_msg_list *req, *prev_req; + struct os_reltime now; + struct hostapd_radius_server *rconf; + int invalid_authenticator = 0; + + if (msg_type == RADIUS_ACCT) { + handlers = radius->acct_handlers; + num_handlers = radius->num_acct_handlers; + rconf = conf->acct_server; + } else { + handlers = radius->auth_handlers; + num_handlers = radius->num_auth_handlers; + rconf = conf->auth_server; + } + + if (msg == NULL) { + wpa_printf(MSG_INFO, "RADIUS: Parsing incoming frame failed"); + rconf->malformed_responses++; + return; + } + hdr = radius_msg_get_hdr(msg); + + hostapd_logger(radius->ctx, NULL, HOSTAPD_MODULE_RADIUS, + HOSTAPD_LEVEL_DEBUG, "checking associated req for (type %d id = %d)", msg_type, hdr->identifier); + if (conf->msg_dumps) + radius_msg_dump(msg); + + prev_req = NULL; + req = radius->msgs; + + if (!req) + { + hostapd_logger(radius->ctx, NULL, HOSTAPD_MODULE_RADIUS, + HOSTAPD_LEVEL_DEBUG, "Req is NULL while checking" + "associated req for (type %d id = %d)", msg_type, hdr->identifier); + } + while (req) { + /* TODO: also match by src addr:port of the packet when using + * alternative RADIUS servers (?) */ + + if ((req) && (req == req->next)) + { + wpa_printf(MSG_DEBUG, "%s: RADIUS: exiting circular loop", __func__); + goto fail; + } + + if (req->msg_type == msg_type && + radius_msg_get_hdr(req->msg)->identifier == + hdr->identifier) + break; + + prev_req = req; + req = req->next; + } + + if (req == NULL) { + hostapd_logger(radius->ctx, NULL, HOSTAPD_MODULE_RADIUS, + HOSTAPD_LEVEL_DEBUG, + "No matching RADIUS request found (type=%d " + "id=%d) - dropping packet", + msg_type, hdr->identifier); + goto fail; + } + + os_get_reltime(&now); + roundtrip = (now.sec - req->last_attempt.sec) * 100 + + (now.usec - req->last_attempt.usec) / 10000; + hostapd_logger(radius->ctx, req->addr, HOSTAPD_MODULE_RADIUS, + HOSTAPD_LEVEL_DEBUG, + "Received RADIUS packet matched with a pending " + "request (type=%d id=%d), round trip time %d.%02d sec", + msg_type, hdr->identifier, + roundtrip / 100, roundtrip % 100); + rconf->round_trip_time = roundtrip; + + /* Remove ACKed RADIUS packet from retransmit list */ + if (prev_req) + prev_req->next = req->next; + else + radius->msgs = req->next; + if (radius->num_msgs > 0) + { + radius->num_msgs--; + } + else + { + wpa_printf(MSG_DEBUG, "%s: RADIUS: num messages equal to 0, cannot decrement further", __func__); + } + + for (i = 0; i < num_handlers; i++) { + RadiusRxResult res; + res = handlers[i].handler(msg, req->msg, req->shared_secret, + req->shared_secret_len, + handlers[i].data); + switch (res) { + case RADIUS_RX_PROCESSED: + radius_msg_free(msg); + /* fall through */ + case RADIUS_RX_QUEUED: + radius_client_msg_free(req); + return; + case RADIUS_RX_INVALID_AUTHENTICATOR: + invalid_authenticator++; + /* fall through */ + case RADIUS_RX_UNKNOWN: + /* continue with next handler */ + break; + } + } + + hostapd_logger(radius->ctx, req->addr, HOSTAPD_MODULE_RADIUS, + HOSTAPD_LEVEL_DEBUG, "No RADIUS RX handler found " + "(type=%d code=%d id=%d)%s - dropping packet", + msg_type, hdr->code, hdr->identifier, + invalid_authenticator ? " [INVALID AUTHENTICATOR]" : + ""); + radius_client_msg_free(req); + + fail: + radius_msg_free(msg); +} +#endif + /** * radius_client_get_id - Get an identifier for a new RADIUS message * @radius: RADIUS client context from radius_client_init() @@ -1056,6 +1221,43 @@ static void radius_client_update_acct_msgs(struct radius_client_data *radius, } } +#ifdef CONFIG_SONIC_RADIUS +int radius_client_update_auth_msgs(struct radius_client_data *radius, + const u8 *shared_secret, + size_t shared_secret_len) +{ + struct radius_msg *temp; + struct radius_msg *msg = NULL; + struct radius_msg_list *entry; + + + if (!radius) + return -1; + + for (entry = radius->msgs; entry; entry = entry->next) { + if (entry->msg_type == RADIUS_AUTH) { + msg = NULL; + msg = radius_client_update_auth_msg_data(entry->msg, shared_secret, + shared_secret_len); + if (!msg) + goto msg_clean; + /* swap the msg pointers and update the entry details */ + temp = entry->msg; + entry->msg = msg; + + radius_msg_free(temp); + entry->shared_secret = shared_secret; + entry->shared_secret_len = shared_secret_len; + } + } + + return 0; + +msg_clean: + radius_msg_free(msg); + return -1; +} +#endif static int radius_change_server(struct radius_client_data *radius, @@ -1102,7 +1304,18 @@ radius_change_server(struct radius_client_data *radius, * missing state information. Client will likely retry * authentication, so this should not be an issue. */ if (auth) - radius_client_flush(radius, 1); + { +#ifdef CONFIG_SONIC_RADIUS + if (radius->msgs) { + eloop_cancel_timeout(radius_client_timer, radius, NULL); + } + radius_client_update_auth_msgs( + radius, nserv->shared_secret, + nserv->shared_secret_len); +#else + radius_client_flush(radius, 1); +#endif + } else { radius_client_update_acct_msgs( radius, nserv->shared_secret, @@ -1293,8 +1506,11 @@ static int radius_client_disable_pmtu_discovery(int s) return r; } - +#ifdef CONFIG_SONIC_RADIUS +void radius_close_auth_sockets(struct radius_client_data *radius) +#else static void radius_close_auth_sockets(struct radius_client_data *radius) +#endif { radius->auth_sock = -1; @@ -1312,8 +1528,11 @@ static void radius_close_auth_sockets(struct radius_client_data *radius) #endif /* CONFIG_IPV6 */ } - +#ifdef CONFIG_SONIC_RADIUS +void radius_close_acct_sockets(struct radius_client_data *radius) +#else static void radius_close_acct_sockets(struct radius_client_data *radius) +#endif { radius->acct_sock = -1; diff --git a/src/radius/radius_client.h b/src/radius/radius_client.h index 8ca0874db..a77f43b67 100644 --- a/src/radius/radius_client.h +++ b/src/radius/radius_client.h @@ -259,4 +259,17 @@ int radius_client_get_mib(struct radius_client_data *radius, char *buf, void radius_client_reconfig(struct radius_client_data *radius, struct hostapd_radius_servers *conf); +#ifdef CONFIG_SONIC_RADIUS +void radius_close_auth_sockets(struct radius_client_data *radius); +void radius_close_acct_sockets(struct radius_client_data *radius); + +void radius_client_receive_proces(void *cxt, RadiusType msg_type, struct radius_msg *msg, int len); + +int radius_resp_cb_register(struct radius_client_data *radius, + RadiusType msg_type, + int (*handler)(struct radius_msg *msg, + int msg_len, + void *data), + void *data); +#endif #endif /* RADIUS_CLIENT_H */ diff --git a/src/radius/radius_mab.c b/src/radius/radius_mab.c new file mode 100644 index 000000000..c73a1873a --- /dev/null +++ b/src/radius/radius_mab.c @@ -0,0 +1,780 @@ +#include +#include "mab_include.h" +#include "includes.h" +#include "common.h" +#include "eloop.h" +#include "radius.h" +#include "radius_client.h" +#include "mab_radius.h" + +struct radius_ctx { + struct radius_client_data *radius; + struct hostapd_radius_servers conf; + u8 radius_identifier; + struct in_addr own_ip_addr; +}; + +extern int wpa_debug_level; + +#define MAB_MAX_RADIUS_SERVERS FD_MAX_RADIUS_SERVERS + +int radius_server_info_copy(struct hostapd_radius_server *srv, + struct hostapd_ip_addr addr, int priority, + const mab_key_t *key, unsigned int port) +{ + if ((!srv) || (!key)) + return -1; + + srv->addr = addr; + srv->port = port; + srv->index = priority; + if (0 != srv->shared_secret_len) + { + free(srv->shared_secret); + srv->shared_secret_len = 0; + } + srv->shared_secret = (char *)malloc(key->key_len + 1); + if (!srv->shared_secret) + return -1; + + memset(srv->shared_secret, 0, key->key_len + 1); + strncpy(srv->shared_secret, key->key, key->key_len); + srv->shared_secret_len = key->key_len; + + return 0; +} + +int radius_server_info_input_cmp(struct hostapd_radius_server *s, + int priority, unsigned int port, + mab_key_t *key) +{ + if ((!s) || (!key)) + return -1; + + if ((s->port != port) || (s->index != priority)) + return -1; + /* server key check */ + if(s->shared_secret_len != key->key_len) + return -1; + if (0 != strncmp(s->shared_secret, key->key, key->key_len)) + return -1; + return 0; +} + +int radius_mab_server_id_get(void *req, unsigned char *radius_identifier) +{ + if ((!req) || (!radius_identifier)) + return -1; + if (!((struct radius_ctx *)req)->radius) + return -1; + + *radius_identifier = radius_client_get_id(((struct radius_ctx *)req)->radius); + + return 0; +} + +int radius_mab_current_auth_server_key_get(void *req, unsigned char *shared_secret, + size_t *shared_secret_len) +{ + if ((!req) || (!shared_secret) || (!shared_secret_len)) + return -1; + + struct hostapd_radius_server *auth_server = ((((struct radius_ctx *)req)->conf).auth_server); + + if ((!auth_server) || (!(auth_server->shared_secret)) || + (!(auth_server->shared_secret_len))) + return -1; + + strncpy(shared_secret, auth_server->shared_secret, auth_server->shared_secret_len); + *shared_secret_len = auth_server->shared_secret_len; + + return 0; +} + +int radius_mab_server_send(void *req_attr, void *in) +{ + access_req_info_t *req = (access_req_info_t *)req_attr; + struct radius_msg *msg = (struct radius_msg *)in; + + if (radius_client_send(((struct radius_ctx *)req->cxt)->radius, msg, RADIUS_AUTH, req->supp_mac) < 0) + return -1; + + return 0; +} + +int radius_acs_mab_server_send(void *req_attr, void *in) +{ + acs_access_req_info_t *req = (acs_access_req_info_t *)req_attr; + struct radius_msg *msg = (struct radius_msg *)in; + + if (radius_client_send(((struct radius_ctx *)req->cxt)->radius, msg, RADIUS_AUTH, req->supp_mac) < 0) + return -1; + + return 0; +} +int radius_mab_resp_req_map_validate(void *cxt, void *data, int msg_len) +{ + struct radius_ctx *ptr = cxt; + radius_resp_req_map_validate((void *)ptr->radius, data, msg_len); + return 0; +} + +/* Process the RADIUS frames from Authentication Server */ +RadiusRxResult radius_mab_receive_auth(struct radius_msg *msg, + struct radius_msg *req, + const unsigned char *shared_secret, + size_t shared_secret_len, + void *data) +{ +/* struct radius_msg *resp; */ + + printf("Received RADIUS Authentication message; code=%d\n", + radius_msg_get_hdr(msg)->code); + + unsigned int correlator = 0; + if (radius_get_req_correlator(req, &correlator)) + { + goto send_res; + } + + /* post to the mab queue */ + wpa_printf(MSG_DEBUG, + "Updating PAC with radius response (correlator = %d)", + correlator); + mabRadiusResponseCallback((void *)msg, correlator); + +send_res: + return RADIUS_RX_QUEUED; +} + + +void mab_read_process(void *eloop_ctx, unsigned char *buf, int len) +{ + mab_radius_cmd_msg_t *req = (mab_radius_cmd_msg_t *)buf; + unsigned int i = 0; + unsigned int n = (len/sizeof(*req)); + + radius_mab_cmd_entry_t radius_mab_cmd_tbl[] = { + {"server-add", mab_radius_server_add}, + {"server-delete", mab_radius_server_delete}, + {"server-reload", mab_radius_server_reload}, + {"access-req", mab_radius_client_access_req_send}, + {"acs-access-req", mab_radius_client_acs_access_req_send}, + {"server-terminate", mab_radius_server_eloop_terminate}, + {"clear-radius-msgs", mab_radius_client_clear_radius_msgs} + }; + + wpa_printf(MSG_DEBUG, "%s Received %d bytes for processing", __func__, len); + if ((!req) || (!req->cmd)) + return; + + wpa_printf(MSG_DEBUG, "%s Received %d commands for processing", __func__, n); + while (n) + { + wpa_printf(MSG_DEBUG, "%s Received %s command", __func__, req->cmd); + for (i = 0; i < (sizeof(radius_mab_cmd_tbl)/sizeof(radius_mab_cmd_entry_t)); i++) + { + if (0 == strcmp(radius_mab_cmd_tbl[i].cmd, req->cmd)) + { + wpa_printf(MSG_DEBUG, "%s invoking the associated handler for %s ", __func__, req->cmd); + radius_mab_cmd_tbl[i].hdlr(req->data, &req->cmd_data); + break; + } + } + n--; + req++; + } +} + +static void handle_mab_read(int sock, void *eloop_ctx, void *sock_ctx) +{ + int len, n; + unsigned char buf[1024]; + struct sockaddr_in c_addr; + + + wpa_printf(MSG_DEBUG, "%s [fd - %d], Received some data on fd..Starting to read", __func__, sock); + len = sizeof(c_addr); + + n = recvfrom(sock, (unsigned char *)buf, 1024, + MSG_WAITALL, ( struct sockaddr *) &c_addr, + &len); + if (n < 0) { + wpa_printf(MSG_ERROR, "recvfrom: %s", strerror(errno)); + return; + } + wpa_printf(MSG_DEBUG, "%s [fd - %d], Received %d bytes", __func__, sock, n); + + mab_read_process(eloop_ctx, buf, n); +} + + +void mab_eloop_register(int fd, void *data) +{ + wpa_printf(MSG_DEBUG, "mab_eloop_register: eloop init - start"); + + eloop_init(); + + if (eloop_register_read_sock(fd, handle_mab_read, data, NULL)) { + wpa_printf(MSG_ERROR, "Could not register mab eloop read socket"); + return; + } + + wpa_printf(MSG_DEBUG, "mab_eloop_register: eloop run - start"); + eloop_run(); + wpa_printf(MSG_DEBUG, "mab_eloop_register: eloop run - end"); +} + +void radius_mab_cmd_req_send(int client_fd, char *req, size_t req_len) +{ + struct sockaddr_in saddr; + struct hostent *local_host; /* need netdb.h for this */ + int n = 0; + + wpa_printf(MSG_DEBUG, "%s , fd - %d: initiate send ",__func__, client_fd); + + saddr.sin_family = AF_INET; + saddr.sin_port = htons(9395); + local_host = gethostbyname("127.0.0.1"); + saddr.sin_addr = *((struct in_addr *)local_host->h_addr); + + n = sendto(client_fd, (const char *)req, req_len, + MSG_CONFIRM, (const struct sockaddr *) &saddr, + sizeof(saddr)); + + wpa_printf(MSG_DEBUG, "%s , fd - %d: successfully sent %d bytes ",__func__, client_fd, n); +} + +int mab_radius_client_alloc(void **data) +{ + + struct radius_ctx *cxt = (struct radius_ctx *)malloc(sizeof(*cxt)); + + if (!cxt) + return -1; + + memset(cxt, 0, sizeof(*cxt)); + + cxt->conf.auth_servers = (struct hostapd_radius_server *)malloc(MAB_MAX_RADIUS_SERVERS *sizeof(struct hostapd_radius_server)); + if (cxt->conf.auth_servers == NULL) + goto rollback; + + cxt->conf.acct_servers = (struct hostapd_radius_server *)malloc(MAB_MAX_RADIUS_SERVERS *sizeof(struct hostapd_radius_server)); + if (cxt->conf.acct_servers == NULL) + goto rollback; + + memset(cxt->conf.auth_servers, 0, MAB_MAX_RADIUS_SERVERS*sizeof(struct hostapd_radius_server)); + cxt->conf.auth_server = NULL; + + memset(cxt->conf.acct_servers, 0, MAB_MAX_RADIUS_SERVERS*sizeof(struct hostapd_radius_server)); + cxt->conf.acct_server = NULL; + + *data = (void *)cxt; + return 0; + +rollback: + + if (cxt) + { + if (cxt->radius) + free(cxt->radius); + + if (cxt->conf.auth_servers) + free(cxt->conf.auth_servers); + + if (cxt->conf.acct_servers) + free(cxt->conf.acct_servers); + + if (cxt) + free(cxt); + } + return -1; +} + +static void radius_periodic_dummy(void *eloop_ctx, void *timeout_ctx) +{ + eloop_register_timeout(1, 0, radius_periodic_dummy, NULL, NULL); + return; +} + +int radius_mab_client_register(void *data) +{ + + struct radius_ctx *cxt = (struct radius_ctx *)data; + + if (!cxt) + return -1; + + + wpa_printf(MSG_DEBUG, "%s initializing the radius client ", __func__); + cxt->radius = radius_client_init(cxt, &cxt->conf); + + if (cxt->radius == NULL) { + wpa_printf(MSG_ERROR, "%s Failed to initialize RADIUS client", __func__); + goto rollback; + } + + /* Register a dummy timeout handler to let eloop wake every sec + * and evaluate terminate condition + */ + eloop_register_timeout(1, 0, radius_periodic_dummy, NULL, NULL); + + wpa_printf(MSG_DEBUG, "%s registering the radius client ", __func__); + if (radius_client_register(cxt->radius, RADIUS_AUTH, radius_mab_receive_auth, + cxt) < 0) { + wpa_printf(MSG_ERROR,"Failed to register RADIUS authentication handler"); + goto rollback; + } + + wpa_printf(MSG_DEBUG,"RADIUS registration success"); + return 0; + +rollback: + + if (cxt) + { + if (cxt->radius) + free(cxt->radius); + } + return -1; +} + + +int radius_mab_client_deregister(void *data) +{ + struct radius_ctx *cxt = (struct radius_ctx *)data; + + if (!cxt) + return -1; + + if (cxt->radius) + { + radius_client_deinit(cxt->radius); + cxt->radius = NULL; + } + + printf("RADIUS de registration success\n"); + return 0; + +} + +int radius_server_addr_idx_find(struct hostapd_radius_server *servers, struct hostapd_ip_addr addr) +{ + unsigned int i = 0; + + if (!servers) + return -1; + + for (i = 0; i < MAB_MAX_RADIUS_SERVERS; i++) + { + if (0 == memcmp(&servers->addr, &addr, sizeof(addr))) + return i; + servers++; + } + return -1; +} + +int radius_server_free_idx_find(struct hostapd_radius_server *servers, int index) +{ + unsigned int i = 0; + struct hostapd_ip_addr addr; + + memset(&addr, 0, sizeof(addr)); + + if (!servers) + return -1; + + for (i = 0; i < MAB_MAX_RADIUS_SERVERS; i++) + { + if ((0 == memcmp(&servers->addr, &addr, sizeof(addr))) || + (servers->index > index)) + return i; + + servers++; + } + return -1; +} + +int radius_server_sort(struct hostapd_radius_server *servers, unsigned int count) +{ + struct hostapd_radius_server s = {0}; + struct hostapd_ip_addr addr; + unsigned int i, j; + + if ((!servers) || (count > MAB_MAX_RADIUS_SERVERS)) + return -1; + + memset(&addr, 0, sizeof(addr)); + + for (i = 0; i < (count -1); i++) + { + for (j = 0; j < (count-(i+1)); j++) + { + if ((servers[j].index < servers[j+1].index) || + (0 == memcmp(&servers->addr, &addr, sizeof(addr)))) + { + s = servers[j]; + servers[j] = servers[j+1]; + servers[j+1] = s; + } + } + } + return 0; +} + +int radius_server_insert(struct hostapd_radius_server *servers, unsigned int idx, + struct hostapd_ip_addr addr, int priority, + const mab_key_t *key, unsigned int port) +{ + struct hostapd_radius_server *s, *d; + unsigned int i = 0; + + if ((!servers) || (idx >= MAB_MAX_RADIUS_SERVERS)) + return -1; + + d = servers + (MAB_MAX_RADIUS_SERVERS - 1); + s = servers + (MAB_MAX_RADIUS_SERVERS - 2); + + for (i = MAB_MAX_RADIUS_SERVERS - 1; i > idx; i--) + { + memcpy(d, s, sizeof(*s)); + s--; + d--; + } + + s = servers + idx; + memset(s, 0, sizeof(*s)); + return radius_server_info_copy(s, addr, priority, key, port); +} + +int radius_server_remove(struct hostapd_radius_server *servers, unsigned int idx) +{ + unsigned int i = 0; + struct hostapd_radius_server *s, *d; + + if ((!servers) || (idx >= MAB_MAX_RADIUS_SERVERS)) + return -1; + + s = servers + idx; + + /* free the memory allocated for shared secret */ + if (s->shared_secret) + free(s->shared_secret); + memset(s, 0, sizeof(*s)); + + d = s; + s++; + + for (i = idx; i < MAB_MAX_RADIUS_SERVERS -1; i++) + { + *d = *s; + memset(s, 0, sizeof(*s)); + d++; + s++; + } + + return 0; +} + +int dbg = 0; + +void dbg_flag(int flag) +{ + dbg = flag; +} + + +int radius_server_update(bool op, void *data, mab_radius_server_t *server) +{ + struct radius_ctx *cxt = (struct radius_ctx *)data; + + if (!cxt) + return -1; + + struct hostapd_radius_server *srv = NULL, *s = NULL; + struct hostapd_ip_addr addr; + unsigned int port, priority = 0, idx = 0; + int *num_servers = NULL; + + memset(&addr, 0, sizeof(addr)); + + /* get the ip address */ + if (hostapd_parse_ip_addr(server->serv_addr, &addr)) + return -1; + + if (server->serv_port) + port = atoi(server->serv_port); + + if (server->serv_priority) + priority = atoi(server->serv_priority); + + if (0 == strncmp(server->radius_type, "auth", strlen("auth"))) + { + srv = &(cxt->conf.auth_servers[0]); + num_servers = &(cxt->conf.num_auth_servers); + if (!server->serv_port) + { + port = 1812; + } + } + + if (0 == strncmp(server->radius_type, "acct", strlen("acct"))) + { + srv = &(cxt->conf.acct_servers[0]); + num_servers = &(cxt->conf.num_acct_servers); + if (!server->serv_port) + { + port = 1813; + } + } + + if (op) + { + if (MAB_MAX_RADIUS_SERVERS == (*num_servers)) + return -1; + + /* Check Radius server alreay exists and update any change in server data */ + idx = radius_server_addr_idx_find(srv, addr); + if ((-1 != idx) && (MAB_MAX_RADIUS_SERVERS > idx)) + { + s = (srv + idx); + if (0 == radius_server_info_input_cmp (s, priority, port, &server->key)) + return 0; + /* If no change in priority update the radius params in the existing server entry + * If change in priority, remove the entry and create new radius server entry + */ + if (s->index == priority) + { + radius_server_info_copy(s, addr, priority, &server->key, port); + } + else + { + radius_server_info_copy(s, addr, priority, &server->key, port); + radius_server_sort(srv, MAB_MAX_RADIUS_SERVERS); + } + } + else + { + idx = radius_server_free_idx_find(srv, priority); + if (-1 == idx) + return -1; + + radius_server_insert(srv, idx, addr, priority, &server->key, port); + /* Sort the Radius servers, when add new Radius server */ + radius_server_sort(srv, MAB_MAX_RADIUS_SERVERS); + (*num_servers)++; + printf ("%s num_servers %d \n", __func__, *num_servers); + } + } + else + { + if (0 == (*num_servers)) + return -1; + + idx = radius_server_addr_idx_find(srv, addr); + if (-1 == idx) + return -1; + + radius_server_remove(srv, idx); + (*num_servers)--; + } + + /* after every update always, place the highest priority server as current server */ + if (0 == strncmp(server->radius_type, "auth", strlen("auth"))) + { + if (*num_servers) + cxt->conf.auth_server = cxt->conf.auth_servers; + else + cxt->conf.auth_server = NULL; + + } + + if (0 == strncmp(server->radius_type, "acct", strlen("acct"))) + { + if (*num_servers) + cxt->conf.acct_server = cxt->conf.acct_servers; + else + cxt->conf.acct_server = NULL; + } + + + if (op) + { + cxt->conf.msg_dumps++; + } + else + { + cxt->conf.msg_dumps--; + } + + return 0; +} + +int radius_client_get_stats(void *data, char *buf, size_t buflen) +{ + struct radius_ctx *cxt; + + if ((data == NULL) || (buf == NULL)) + { + return -1; + } + + cxt = (struct radius_ctx *)data; + + return radius_client_get_mib(cxt->radius, buf, buflen); +} + + +void radius_mab_client_flush(void *data) +{ + struct radius_ctx *cxt; + + if (data == NULL) + { + return; + } + + cxt = (struct radius_ctx *)data; + + radius_client_flush(cxt->radius, 0); +} + + + +void mab_radius_server_add(void *data, void *req) +{ + mab_radius_server_t *server = req; + struct radius_ctx *cxt = (struct radius_ctx *)data; + + wpa_printf(MSG_DEBUG, "%s inserting server entry %s", __func__, server->serv_addr); + /* insert the entry */ + radius_server_update(TRUE, data, server); + + if (cxt->radius) + { + radius_mab_client_flush(cxt); + radius_close_auth_sockets(cxt->radius); + radius_close_acct_sockets(cxt->radius); + } + else + { + /* register the entry with radius client */ + if (0 != radius_mab_client_register(data)) + { + wpa_printf(MSG_ERROR,"radius mab client_register failed.."); + } + } +} + +void mab_radius_server_delete(void *data, void *req) +{ + mab_radius_server_t *server = req; + struct radius_ctx *cxt = (struct radius_ctx *)data; + + /* delete the existing entry and re-insert the new entry */ + radius_server_update(FALSE, data, server); + + if (cxt->radius) + { + radius_mab_client_flush(cxt); + radius_close_auth_sockets(cxt->radius); + radius_close_acct_sockets(cxt->radius); + } + + if (0 == cxt->conf.num_auth_servers) + { + /* de-register the entry with radius client */ + wpa_printf(MSG_DEBUG, "%s removing server entry %s", __func__, server->serv_addr); + if (0 != radius_mab_client_deregister(data)) + { + wpa_printf(MSG_ERROR,"radius mab client_deregister failed.."); + } + } +} + +void mab_radius_server_reload(void *data, void *req) +{ + struct radius_ctx *cxt = (struct radius_ctx *)data; + + if (cxt->radius) + { + radius_mab_client_flush(cxt); + radius_close_auth_sockets(cxt->radius); + radius_close_acct_sockets(cxt->radius); + } +} + +void mab_radius_client_access_req_send(void *data, void *req) +{ + mab_radius_access_req_t *access_req = req; + authmgrClientStatusInfo_t clientStatus; + access_req_info_t *req_info = (access_req_info_t *)(access_req->req_attr); + uint32 physPort; + + if (0 != ((struct radius_ctx *)(req_info->cxt))->conf.num_auth_servers) + { + /* invoke client access req send */ + radius_mab_server_send(access_req->req_attr, access_req->msg); + } + else + { + /* notify the inability to authenticate client as failure */ + memset(&clientStatus, 0, sizeof(authmgrClientStatusInfo_t)); + memcpy(&clientStatus.info.authInfo.macAddr, &(req_info->supp_mac), 6); + MAB_PORT_GET(physPort, req_info->correlator); + mabPortClientAuthStatusUpdate(physPort, clientStatus.info.authInfo.macAddr.addr, + "auth_fail", (void*) &clientStatus); + } + + if (access_req->req_attr) + free (access_req->req_attr); +} + +void mab_radius_client_acs_access_req_send(void *data, void *req) +{ + mab_radius_access_req_t *access_req = req; + /* invoke client access req send */ + radius_acs_mab_server_send(access_req->req_attr, access_req->msg); + + if (access_req->req_attr) + free (access_req->req_attr); +} + +void mab_radius_server_eloop_terminate(void *data, void *req) +{ + /* invoke eloop terminate */ + eloop_terminate(); +} + +void mab_radius_client_clear_radius_msgs(void *data, void *req) +{ + unsigned char *cli_mac_addr = req; + struct radius_ctx *cxt = (struct radius_ctx *)data; + + if (cxt->radius) + { + wpa_printf(MSG_DEBUG, "%s: Clear the RADIUS messages for client " MACSTR, + __func__, MAC2STR(cli_mac_addr)); + radius_client_flush_auth(cxt->radius, cli_mac_addr); + } +} + +void mab_radius_server_debug_level_set(int level) +{ + switch (level) + { + case MSG_MSGDUMP : + case MSG_DEBUG : + case MSG_INFO : + case MSG_WARNING : + case MSG_ERROR : + wpa_debug_level = level; + default: + break; + } +} + +int mab_radius_server_debug_level_get() +{ + return wpa_debug_level; +} diff --git a/src/utils/Makefile b/src/utils/Makefile index e8ad997ee..181f06774 100644 --- a/src/utils/Makefile +++ b/src/utils/Makefile @@ -1,6 +1,7 @@ #CFLAGS += -DWPA_TRACE CFLAGS += -DCONFIG_IPV6 CFLAGS += -DCONFIG_DEBUG_FILE +CFLAGS += -fPIC LIB_OBJS= \ base64.o \