static void Radius_client_list_add(rtapd *rtapd, struct radius_msg *msg,
				   RadiusType msg_type, u8 *shared_secret, size_t shared_secret_len)
{
	struct radius_msg_list *entry, *prev;

	if (eloop_terminated())
	{
		/* No point in adding entries to retransmit queue since event
		 * loop has already been terminated. */
		DBGPRINT(RT_DEBUG_TRACE,"eloop_terminate \n");
		Radius_msg_free(msg);
		free(msg);
		return;
	}

	entry = malloc(sizeof(*entry));
	if (entry == NULL)
	{
		DBGPRINT(RT_DEBUG_TRACE,"Failed to add RADIUS packet into retransmit list\n");
		Radius_msg_free(msg);
		free(msg);
		return;
	}

	memset(entry, 0, sizeof(*entry));
	entry->msg = msg;
	entry->msg_type = msg_type;
	entry->shared_secret = shared_secret;
	entry->shared_secret_len = shared_secret_len;
	time(&entry->first_try);
	entry->next_try = entry->first_try + RADIUS_CLIENT_FIRST_WAIT;
	entry->attempts = 1;
	entry->next_wait = RADIUS_CLIENT_FIRST_WAIT * 2;

	if (!rtapd->radius->msgs)
		eloop_register_timeout(RADIUS_CLIENT_FIRST_WAIT, 0, Radius_client_timer, rtapd, NULL);

	entry->next = rtapd->radius->msgs;
	rtapd->radius->msgs = entry;

	if (rtapd->radius->num_msgs >= RADIUS_CLIENT_MAX_ENTRIES)
	{
		DBGPRINT(RT_DEBUG_TRACE,"Removing the oldest un-ACKed RADIUS packet due to retransmit list limits.\n");
		prev = NULL;
		while (entry->next)
		{
			prev = entry;
			entry = entry->next;
		}
		if (prev)
		{
			prev->next = NULL;
			Radius_client_msg_free(entry);
		}
	} else
		rtapd->radius->num_msgs++;
}
Example #2
0
struct radius_msg *Radius_msg_parse(const u8 *data, size_t len)
{
	struct radius_msg *msg;
	struct radius_hdr *hdr;
	struct radius_attr_hdr *attr;
	size_t msg_len;
	unsigned char *pos, *end;

	if (data == NULL || len < sizeof(*hdr))
		return NULL;

	hdr = (struct radius_hdr *) data;

	msg_len = ntohs(hdr->length);
	if (msg_len < sizeof(*hdr) || msg_len > len)
	{
		DBGPRINT(RT_DEBUG_ERROR,"Invalid RADIUS message length\n");
		return NULL;
	}

	if (msg_len < len)
	{
		DBGPRINT(RT_DEBUG_INFO,"Ignored %d extra bytes after RADIUS message\n", len - msg_len);
	}

	msg = (struct radius_msg *) malloc(sizeof(*msg));
	if (msg == NULL)
		return NULL;

	if (Radius_msg_initialize(msg, msg_len))
	{
		free(msg);
		return NULL;
	}

	memcpy(msg->buf, data, msg_len);
	msg->buf_size = msg->buf_used = msg_len;

	/* parse attributes */
	pos = (unsigned char *) (msg->hdr + 1);
	end = msg->buf + msg->buf_used;
	while (pos < end)
	{
		if (end - pos < sizeof(*attr))
			goto fail;

		attr = (struct radius_attr_hdr *) pos;

		if (pos + attr->length > end || attr->length < sizeof(*attr))
			goto fail;

		/* TODO: check that attr->length is suitable for attr->type */

		if (Radius_msg_add_attr_to_array(msg, attr))
			goto fail;

		pos += attr->length;
	}

	return msg;

 fail:
	Radius_msg_free(msg);
	free(msg);
	return NULL;
}
static void Radius_client_msg_free(struct radius_msg_list *req)
{
	Radius_msg_free(req->msg);
	free(req->msg);
	free(req);
}
static void Radius_client_receive(int sock, void *eloop_ctx, void *sock_ctx)
{
	rtapd *rtapd = eloop_ctx;
	RadiusType msg_type = (RadiusType) sock_ctx;
	int len, i,len_80211hdr=24;
	unsigned char buf[3000];
	struct radius_msg *msg;
	struct radius_rx_handler *handlers;
	size_t num_handlers;
	struct radius_msg_list *req, *prev_req;

	DBGPRINT(RT_DEBUG_INFO,"RADIUS_CLIENT_RECEIVE : msg_type= %d \n", msg_type);
	len = recv(sock, buf, sizeof(buf), 0);
	if (len < 0)
	{
		perror("recv[RADIUS]");
		return;
	}
	if (len == sizeof(buf))
	{
		DBGPRINT(RT_DEBUG_ERROR,"Possibly too long UDP frame for our buffer - dropping it\n");
		return;
	}
	
	if(buf[0]!=0xff)
	{
		int i;
		DBGPRINT(RT_DEBUG_INFO,"  r_dump %d bytes:",len);
		for (i = 0; i < len_80211hdr; i++)
			DBGPRINT(RT_DEBUG_INFO," %02x", buf[i]);
		DBGPRINT(RT_DEBUG_INFO,"\n");
	}

	msg = Radius_msg_parse(buf, len);
	if (msg == NULL)
	{
		DBGPRINT(RT_DEBUG_ERROR,"Parsing incoming RADIUS frame failed\n");
		return;
	}

	handlers = rtapd->radius->auth_handlers;
	num_handlers = rtapd->radius->num_auth_handlers;

	prev_req = NULL;
	req = rtapd->radius->msgs;
	while (req)
	{
		/* TODO: also match by src addr:port of the packet when using
		 * alternative RADIUS servers (?) */
		if (req->msg_type == msg_type && req->msg->hdr->identifier == msg->hdr->identifier)
			break;

		prev_req = req;
		req = req->next;
	}

	if (req == NULL)
	{
		goto fail;
	}

	/* Remove ACKed RADIUS packet from retransmit list */
	if (prev_req)
		prev_req->next = req->next;
	else
		rtapd->radius->msgs = req->next;
	rtapd->radius->num_msgs--;

	for (i = 0; i < num_handlers; i++)
	{
		RadiusRxResult res;
		res = handlers[i].handler(rtapd, msg, req->msg, req->shared_secret, req->shared_secret_len, handlers[i].data);
		switch (res) 
		{
			case RADIUS_RX_PROCESSED:
			Radius_msg_free(msg);
			free(msg);
			/* continue */
			case RADIUS_RX_QUEUED:
			Radius_client_msg_free(req);
			return;
			case RADIUS_RX_UNKNOWN:
			/* continue with next handler */
			break;
		}
	}

	DBGPRINT(RT_DEBUG_ERROR,"No RADIUS RX handler found (type=%d code=%d id=%d) - dropping "
		   "packet\n", msg_type, msg->hdr->code, msg->hdr->identifier);
	Radius_client_msg_free(req);

 fail:
	Radius_msg_free(msg);
	free(msg);
}