コード例 #1
0
ファイル: radius_server.c プロジェクト: Aratori/Roaming
static int radius_server_request(struct radius_server_data *data,
				 struct radius_msg *msg,
				 struct sockaddr *from, socklen_t fromlen,
				 struct radius_client *client,
				 const char *from_addr, int from_port,
				 struct radius_session *force_sess)
{
	struct wpabuf *eap = NULL;
	int res, state_included = 0;
	u8 statebuf[4];
	unsigned int state;
	struct radius_session *sess;
	struct radius_msg *reply;
	int is_complete = 0;

	if (force_sess)
		sess = force_sess;
	else {
		res = radius_msg_get_attr(msg, RADIUS_ATTR_STATE, statebuf,
					  sizeof(statebuf));
		state_included = res >= 0;
		if (res == sizeof(statebuf)) {
			state = WPA_GET_BE32(statebuf);
			sess = radius_server_get_session(client, state);
		} else {
			sess = NULL;
		}
	}

	if (sess) {
		RADIUS_DEBUG("Request for session 0x%x", sess->sess_id);
	} else if (state_included) {
		RADIUS_DEBUG("State attribute included but no session found");
		radius_server_reject(data, client, msg, from, fromlen,
				     from_addr, from_port);
		return -1;
	} else {
		sess = radius_server_get_new_session(data, client, msg);
		if (sess == NULL) {
			RADIUS_DEBUG("Could not create a new session");
			radius_server_reject(data, client, msg, from, fromlen,
					     from_addr, from_port);
			return -1;
		}
	}

	if (sess->last_from_port == from_port &&
	    sess->last_identifier == radius_msg_get_hdr(msg)->identifier &&
	    os_memcmp(sess->last_authenticator,
		      radius_msg_get_hdr(msg)->authenticator, 16) == 0) {
		RADIUS_DEBUG("Duplicate message from %s", from_addr);
		data->counters.dup_access_requests++;
		client->counters.dup_access_requests++;

		if (sess->last_reply) {
			struct wpabuf *buf;
			buf = radius_msg_get_buf(sess->last_reply);
			res = sendto(data->auth_sock, wpabuf_head(buf),
				     wpabuf_len(buf), 0,
				     (struct sockaddr *) from, fromlen);
			if (res < 0) {
				wpa_printf(MSG_INFO, "sendto[RADIUS SRV]: %s",
					   strerror(errno));
			}
			return 0;
		}

		RADIUS_DEBUG("No previous reply available for duplicate "
			     "message");
		return -1;
	}
		      
	eap = radius_msg_get_eap(msg);
	if (eap == NULL) {
		RADIUS_DEBUG("No EAP-Message in RADIUS packet from %s",
			     from_addr);
		data->counters.packets_dropped++;
		client->counters.packets_dropped++;
		return -1;
	}

	RADIUS_DUMP("Received EAP data", wpabuf_head(eap), wpabuf_len(eap));

	/* FIX: if Code is Request, Success, or Failure, send Access-Reject;
	 * RFC3579 Sect. 2.6.2.
	 * Include EAP-Response/Nak with no preferred method if
	 * code == request.
	 * If code is not 1-4, discard the packet silently.
	 * Or is this already done by the EAP state machine? */

	wpabuf_free(sess->eap_if->eapRespData);
	sess->eap_if->eapRespData = eap;
	sess->eap_if->eapResp = TRUE;
	eap_server_sm_step(sess->eap);

	if ((sess->eap_if->eapReq || sess->eap_if->eapSuccess ||
	     sess->eap_if->eapFail) && sess->eap_if->eapReqData) {
		RADIUS_DUMP("EAP data from the state machine",
			    wpabuf_head(sess->eap_if->eapReqData),
			    wpabuf_len(sess->eap_if->eapReqData));
	} else if (sess->eap_if->eapFail) {
		RADIUS_DEBUG("No EAP data from the state machine, but eapFail "
			     "set");
	} else if (eap_sm_method_pending(sess->eap)) {
		radius_msg_free(sess->last_msg);
		sess->last_msg = msg;
		sess->last_from_port = from_port;
		os_free(sess->last_from_addr);
		sess->last_from_addr = os_strdup(from_addr);
		sess->last_fromlen = fromlen;
		os_memcpy(&sess->last_from, from, fromlen);
		return -2;
	} else {
		RADIUS_DEBUG("No EAP data from the state machine - ignore this"
			     " Access-Request silently (assuming it was a "
			     "duplicate)");
		data->counters.packets_dropped++;
		client->counters.packets_dropped++;
		return -1;
	}

	if (sess->eap_if->eapSuccess || sess->eap_if->eapFail)
		is_complete = 1;

	reply = radius_server_encapsulate_eap(data, client, sess, msg);

	if (reply) {
		struct wpabuf *buf;
		struct radius_hdr *hdr;

		RADIUS_DEBUG("Reply to %s:%d", from_addr, from_port);
		if (wpa_debug_level <= MSG_MSGDUMP) {
			radius_msg_dump(reply);
		}

		switch (radius_msg_get_hdr(reply)->code) {
		case RADIUS_CODE_ACCESS_ACCEPT:
			data->counters.access_accepts++;
			client->counters.access_accepts++;
			break;
		case RADIUS_CODE_ACCESS_REJECT:
			data->counters.access_rejects++;
			client->counters.access_rejects++;
			break;
		case RADIUS_CODE_ACCESS_CHALLENGE:
			data->counters.access_challenges++;
			client->counters.access_challenges++;
			break;
		}
		buf = radius_msg_get_buf(reply);
		res = sendto(data->auth_sock, wpabuf_head(buf),
			     wpabuf_len(buf), 0,
			     (struct sockaddr *) from, fromlen);
		if (res < 0) {
			wpa_printf(MSG_INFO, "sendto[RADIUS SRV]: %s",
				   strerror(errno));
		}
		radius_msg_free(sess->last_reply);
		sess->last_reply = reply;
		sess->last_from_port = from_port;
		hdr = radius_msg_get_hdr(msg);
		sess->last_identifier = hdr->identifier;
		os_memcpy(sess->last_authenticator, hdr->authenticator, 16);
	} else {
		data->counters.packets_dropped++;
		client->counters.packets_dropped++;
	}

	if (is_complete) {
		RADIUS_DEBUG("Removing completed session 0x%x after timeout",
			     sess->sess_id);
		eloop_cancel_timeout(radius_server_session_remove_timeout,
				     data, sess);
		eloop_register_timeout(10, 0,
				       radius_server_session_remove_timeout,
				       data, sess);
	}

	return 0;
}
コード例 #2
0
/**
 * radius_client_send - Send a RADIUS request
 * @radius: RADIUS client context from radius_client_init()
 * @msg: RADIUS message to be sent
 * @msg_type: Message type (RADIUS_AUTH, RADIUS_ACCT, RADIUS_ACCT_INTERIM)
 * @addr: MAC address of the device related to this message or %NULL
 * Returns: 0 on success, -1 on failure
 *
 * This function is used to transmit a RADIUS authentication (RADIUS_AUTH) or
 * accounting request (RADIUS_ACCT or RADIUS_ACCT_INTERIM). The only difference
 * between accounting and interim accounting messages is that the interim
 * message will not be retransmitted. Instead, a callback is used to indicate
 * that the transmission failed for the specific station @addr so that a new
 * interim accounting update message can be generated with up-to-date session
 * data instead of trying to resend old information.
 *
 * The message is added on the retransmission queue and will be retransmitted
 * automatically until a response is received or maximum number of retries
 * (RADIUS_CLIENT_MAX_RETRIES) is reached. No such retries are used with
 * RADIUS_ACCT_INTERIM, i.e., such a pending message is removed from the queue
 * automatically on transmission failure.
 *
 * The related device MAC address can be used to identify pending messages that
 * can be removed with radius_client_flush_auth().
 */
int radius_client_send(struct radius_client_data *radius,
		       struct radius_msg *msg, RadiusType msg_type,
		       const u8 *addr)
{
	struct hostapd_radius_servers *conf = radius->conf;
	const u8 *shared_secret;
	size_t shared_secret_len;
	char *name;
	int s, res;
	struct wpabuf *buf;

	if (msg_type == RADIUS_ACCT || msg_type == RADIUS_ACCT_INTERIM) {
		if (conf->acct_server && radius->acct_sock < 0)
			radius_client_init_acct(radius);

		if (conf->acct_server == NULL || radius->acct_sock < 0 ||
		    conf->acct_server->shared_secret == NULL) {
			hostapd_logger(radius->ctx, NULL,
				       HOSTAPD_MODULE_RADIUS,
				       HOSTAPD_LEVEL_INFO,
				       "No accounting server configured");
			return -1;
		}
		shared_secret = conf->acct_server->shared_secret;
		shared_secret_len = conf->acct_server->shared_secret_len;
		radius_msg_finish_acct(msg, shared_secret, shared_secret_len);
		name = "accounting";
		s = radius->acct_sock;
		conf->acct_server->requests++;
	} else {
		if (conf->auth_server && radius->auth_sock < 0)
			radius_client_init_auth(radius);

		if (conf->auth_server == NULL || radius->auth_sock < 0 ||
		    conf->auth_server->shared_secret == NULL) {
			hostapd_logger(radius->ctx, NULL,
				       HOSTAPD_MODULE_RADIUS,
				       HOSTAPD_LEVEL_INFO,
				       "No authentication server configured");
			return -1;
		}
		shared_secret = conf->auth_server->shared_secret;
		shared_secret_len = conf->auth_server->shared_secret_len;
		radius_msg_finish(msg, shared_secret, shared_secret_len);
		name = "authentication";
		s = radius->auth_sock;
		conf->auth_server->requests++;
	}

	hostapd_logger(radius->ctx, NULL, HOSTAPD_MODULE_RADIUS,
		       HOSTAPD_LEVEL_DEBUG, "Sending RADIUS message to %s "
		       "server", name);
	if (conf->msg_dumps)
		radius_msg_dump(msg);

	buf = radius_msg_get_buf(msg);
	res = send(s, wpabuf_head(buf), wpabuf_len(buf), 0);
	if (res < 0)
		radius_client_handle_send_error(radius, s, msg_type);

	radius_client_list_add(radius, msg, msg_type, shared_secret,
			       shared_secret_len, addr);

	return 0;
}
コード例 #3
0
static void radius_client_receive(int sock, void *eloop_ctx, void *sock_ctx)
{
	struct radius_client_data *radius = eloop_ctx;
	struct hostapd_radius_servers *conf = radius->conf;
	RadiusType msg_type = (RadiusType) sock_ctx;
	int len, roundtrip;
	unsigned char buf[3000];
	struct radius_msg *msg;
	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;
	}

	len = recv(sock, buf, sizeof(buf), MSG_DONTWAIT);
	if (len < 0) {
		wpa_printf(MSG_INFO, "recv[RADIUS]: %s", strerror(errno));
		return;
	}
	hostapd_logger(radius->ctx, NULL, HOSTAPD_MODULE_RADIUS,
		       HOSTAPD_LEVEL_DEBUG, "Received %d bytes from RADIUS "
		       "server", len);
	if (len == sizeof(buf)) {
		wpa_printf(MSG_INFO, "RADIUS: Possibly too long UDP frame for our buffer - dropping it");
		return;
	}

	msg = radius_msg_parse(buf, len);
	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, "Received RADIUS message");
	if (conf->msg_dumps)
		radius_msg_dump(msg);

	switch (hdr->code) {
	case RADIUS_CODE_ACCESS_ACCEPT:
		rconf->access_accepts++;
		break;
	case RADIUS_CODE_ACCESS_REJECT:
		rconf->access_rejects++;
		break;
	case RADIUS_CODE_ACCESS_CHALLENGE:
		rconf->access_challenges++;
		break;
	case RADIUS_CODE_ACCOUNTING_RESPONSE:
		rconf->responses++;
		break;
	}

	prev_req = NULL;
	req = 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_type == RADIUS_ACCT_INTERIM &&
		      msg_type == RADIUS_ACCT)) &&
		    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, round trip time %d.%02d sec",
		       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;
	radius->num_msgs--;

	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);
			/* continue */
		case RADIUS_RX_QUEUED:
			radius_client_msg_free(req);
			return;
		case RADIUS_RX_INVALID_AUTHENTICATOR:
			invalid_authenticator++;
			/* continue */
		case RADIUS_RX_UNKNOWN:
			/* continue with next handler */
			break;
		}
	}

	if (invalid_authenticator)
		rconf->bad_authenticators++;
	else
		rconf->unknown_types++;
	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);
}
コード例 #4
0
static int radius_client_retransmit(struct radius_client_data *radius,
				    struct radius_msg_list *entry,
				    os_time_t now)
{
	struct hostapd_radius_servers *conf = radius->conf;
	int s;
	struct wpabuf *buf;
	size_t prev_num_msgs;
	u8 *acct_delay_time;
	size_t acct_delay_time_len;

	if (entry->msg_type == RADIUS_ACCT ||
	    entry->msg_type == RADIUS_ACCT_INTERIM) {
		if (radius->acct_sock < 0)
			radius_client_init_acct(radius);
		if (radius->acct_sock < 0 && conf->num_acct_servers > 1) {
			prev_num_msgs = radius->num_msgs;
			radius_client_acct_failover(radius);
			if (prev_num_msgs != radius->num_msgs)
				return 0;
		}
		s = radius->acct_sock;
		if (entry->attempts == 0)
			conf->acct_server->requests++;
		else {
			conf->acct_server->timeouts++;
			conf->acct_server->retransmissions++;
		}
	} else {
		if (radius->auth_sock < 0)
			radius_client_init_auth(radius);
		if (radius->auth_sock < 0 && conf->num_auth_servers > 1) {
			prev_num_msgs = radius->num_msgs;
			radius_client_auth_failover(radius);
			if (prev_num_msgs != radius->num_msgs)
				return 0;
		}
		s = radius->auth_sock;
		if (entry->attempts == 0)
			conf->auth_server->requests++;
		else {
			conf->auth_server->timeouts++;
			conf->auth_server->retransmissions++;
		}
	}

	if (entry->msg_type == RADIUS_ACCT_INTERIM) {
		wpa_printf(MSG_DEBUG,
			   "RADIUS: Failed to transmit interim accounting update to "
			   MACSTR " - drop message and request a new update",
			   MAC2STR(entry->addr));
		if (radius->interim_error_cb)
			radius->interim_error_cb(entry->addr,
						 radius->interim_error_cb_ctx);
		return 1;
	}

	if (s < 0) {
		wpa_printf(MSG_INFO,
			   "RADIUS: No valid socket for retransmission");
		return 1;
	}

	if (entry->msg_type == RADIUS_ACCT &&
	    radius_msg_get_attr_ptr(entry->msg, RADIUS_ATTR_ACCT_DELAY_TIME,
				    &acct_delay_time, &acct_delay_time_len,
				    NULL) == 0 &&
	    acct_delay_time_len == 4) {
		struct radius_hdr *hdr;
		u32 delay_time;

		/*
		 * Need to assign a new identifier since attribute contents
		 * changes.
		 */
		hdr = radius_msg_get_hdr(entry->msg);
		hdr->identifier = radius_client_get_id(radius);

		/* Update Acct-Delay-Time to show wait time in queue */
		delay_time = now - entry->first_try;
		WPA_PUT_BE32(acct_delay_time, delay_time);

		wpa_printf(MSG_DEBUG,
			   "RADIUS: Updated Acct-Delay-Time to %u for retransmission",
			   delay_time);
		radius_msg_finish_acct(entry->msg, entry->shared_secret,
				       entry->shared_secret_len);
		if (radius->conf->msg_dumps)
			radius_msg_dump(entry->msg);
	}

	/* retransmit; remove entry if too many attempts */
	entry->attempts++;
	hostapd_logger(radius->ctx, entry->addr, HOSTAPD_MODULE_RADIUS,
		       HOSTAPD_LEVEL_DEBUG, "Resending RADIUS message (id=%d)",
		       radius_msg_get_hdr(entry->msg)->identifier);

	os_get_reltime(&entry->last_attempt);
	buf = radius_msg_get_buf(entry->msg);
	if (send(s, wpabuf_head(buf), wpabuf_len(buf), 0) < 0) {
		if (radius_client_handle_send_error(radius, s, entry->msg_type)
		    > 0)
			return 0;
	}

	entry->next_try = now + entry->next_wait;
	entry->next_wait *= 2;
	if (entry->next_wait > RADIUS_CLIENT_MAX_WAIT)
		entry->next_wait = RADIUS_CLIENT_MAX_WAIT;
	if (entry->attempts >= RADIUS_CLIENT_MAX_RETRIES) {
		wpa_printf(MSG_INFO, "RADIUS: Removing un-ACKed message due to too many failed retransmit attempts");
		return 1;
	}

	return 0;
}
コード例 #5
0
static void radius_das_receive(int sock, void *eloop_ctx, void *sock_ctx)
{
	struct radius_das_data *das = eloop_ctx;
	u8 buf[1500];
	union {
		struct sockaddr_storage ss;
		struct sockaddr_in sin;
#ifdef CONFIG_IPV6
		struct sockaddr_in6 sin6;
#endif /* CONFIG_IPV6 */
	} from;
	char abuf[50];
	int from_port = 0;
	socklen_t fromlen;
	int len;
	struct radius_msg *msg, *reply = NULL;
	struct radius_hdr *hdr;
	struct wpabuf *rbuf;
	u32 val;
	int res;
	struct os_time now;

	fromlen = sizeof(from);
	len = recvfrom(sock, buf, sizeof(buf), 0,
		       (struct sockaddr *) &from.ss, &fromlen);
	if (len < 0) {
		wpa_printf(MSG_ERROR, "DAS: recvfrom: %s", strerror(errno));
		return;
	}

	os_strlcpy(abuf, inet_ntoa(from.sin.sin_addr), sizeof(abuf));
	from_port = ntohs(from.sin.sin_port);

	wpa_printf(MSG_DEBUG, "DAS: Received %d bytes from %s:%d",
		   len, abuf, from_port);
	if (das->client_addr.u.v4.s_addr != from.sin.sin_addr.s_addr) {
		wpa_printf(MSG_DEBUG, "DAS: Drop message from unknown client");
		return;
	}

	msg = radius_msg_parse(buf, len);
	if (msg == NULL) {
		wpa_printf(MSG_DEBUG, "DAS: Parsing incoming RADIUS packet "
			   "from %s:%d failed", abuf, from_port);
		return;
	}

	if (wpa_debug_level <= MSG_MSGDUMP)
		radius_msg_dump(msg);

	if (radius_msg_verify_das_req(msg, das->shared_secret,
				       das->shared_secret_len)) {
		wpa_printf(MSG_DEBUG, "DAS: Invalid authenticator in packet "
			   "from %s:%d - drop", abuf, from_port);
		goto fail;
	}

	os_get_time(&now);
	res = radius_msg_get_attr(msg, RADIUS_ATTR_EVENT_TIMESTAMP,
				  (u8 *) &val, 4);
	if (res == 4) {
		u32 timestamp = ntohl(val);
		if (abs(now.sec - timestamp) > das->time_window) {
			wpa_printf(MSG_DEBUG, "DAS: Unacceptable "
				   "Event-Timestamp (%u; local time %u) in "
				   "packet from %s:%d - drop",
				   timestamp, (unsigned int) now.sec,
				   abuf, from_port);
			goto fail;
		}
	} else if (das->require_event_timestamp) {
		wpa_printf(MSG_DEBUG, "DAS: Missing Event-Timestamp in packet "
			   "from %s:%d - drop", abuf, from_port);
		goto fail;
	}

	hdr = radius_msg_get_hdr(msg);

	switch (hdr->code) {
	case RADIUS_CODE_DISCONNECT_REQUEST:
		reply = radius_das_disconnect(das, msg, abuf, from_port);
		break;
	case RADIUS_CODE_COA_REQUEST:
		/* TODO */
		reply = radius_msg_new(RADIUS_CODE_COA_NAK,
				       hdr->identifier);
		if (reply == NULL)
			break;

		/* Unsupported Service */
		radius_msg_add_attr_int32(reply, RADIUS_ATTR_ERROR_CAUSE, 405);
		break;
	default:
		wpa_printf(MSG_DEBUG, "DAS: Unexpected RADIUS code %u in "
			   "packet from %s:%d",
			   hdr->code, abuf, from_port);
	}

	if (reply) {
		wpa_printf(MSG_DEBUG, "DAS: Reply to %s:%d", abuf, from_port);

		if (!radius_msg_add_attr_int32(reply,
					       RADIUS_ATTR_EVENT_TIMESTAMP,
					       now.sec)) {
			wpa_printf(MSG_DEBUG, "DAS: Failed to add "
				   "Event-Timestamp attribute");
		}

		if (radius_msg_finish_das_resp(reply, das->shared_secret,
					       das->shared_secret_len, hdr) <
		    0) {
			wpa_printf(MSG_DEBUG, "DAS: Failed to add "
				   "Message-Authenticator attribute");
		}

		if (wpa_debug_level <= MSG_MSGDUMP)
			radius_msg_dump(reply);

		rbuf = radius_msg_get_buf(reply);
		res = sendto(das->sock, wpabuf_head(rbuf),
			     wpabuf_len(rbuf), 0,
			     (struct sockaddr *) &from.ss, fromlen);
		if (res < 0) {
			wpa_printf(MSG_ERROR, "DAS: sendto(to %s:%d): %s",
				   abuf, from_port, strerror(errno));
		}
	}

fail:
	radius_msg_free(msg);
	radius_msg_free(reply);
}
コード例 #6
0
static void radius_server_receive_auth(int sock, void *eloop_ctx,
				       void *sock_ctx)
{
	struct radius_server_data *data = eloop_ctx;
	u8 *buf = NULL;
	struct sockaddr_in from;
	socklen_t fromlen;
	int len;
	struct radius_client *client;
	struct radius_msg *msg = NULL;

	buf = malloc(RADIUS_MAX_MSG_LEN);
	if (buf == NULL) {
		goto fail;
	}

	fromlen = sizeof(from);
	len = recvfrom(sock, buf, RADIUS_MAX_MSG_LEN, 0,
		       (struct sockaddr *) &from, &fromlen);
	if (len < 0) {
		perror("recvfrom[radius_server]");
		goto fail;
	}

	RADIUS_DEBUG("Received %d bytes from %s:%d",
		     len, inet_ntoa(from.sin_addr), ntohs(from.sin_port));
	RADIUS_DUMP("Received data", buf, len);

	client = radius_server_get_client(data, &from.sin_addr);
	if (client == NULL) {
		RADIUS_DEBUG("Unknown client %s - packet ignored",
			     inet_ntoa(from.sin_addr));
		goto fail;
	}

	msg = radius_msg_parse(buf, len);
	if (msg == NULL) {
		RADIUS_DEBUG("Parsing incoming RADIUS frame failed");
		goto fail;
	}

	free(buf);
	buf = NULL;

	if (wpa_debug_level <= MSG_MSGDUMP) {
		radius_msg_dump(msg);
	}

	if (msg->hdr->code != RADIUS_CODE_ACCESS_REQUEST) {
		RADIUS_DEBUG("Unexpected RADIUS code %d", msg->hdr->code);
		goto fail;
	}

	if (radius_msg_verify_msg_auth(msg, (u8 *) client->shared_secret,
				       client->shared_secret_len, NULL)) {
		RADIUS_DEBUG("Invalid Message-Authenticator from %s",
			     inet_ntoa(from.sin_addr));
		goto fail;
	}

	radius_server_request(data, msg, &from, client);

fail:
	if (msg) {
		radius_msg_free(msg);
		free(msg);
	}
	free(buf);
}
コード例 #7
0
static int radius_server_request(struct radius_server_data *data,
				 struct radius_msg *msg,
				 struct sockaddr_in *from,
				 struct radius_client *client)
{
	u8 *eap = NULL;
	size_t eap_len;
	int res, state_included;
	u8 statebuf[4], resp_id;
	unsigned int state;
	struct radius_session *sess;
	struct radius_msg *reply;
	struct eap_hdr *hdr;

	/* TODO: Implement duplicate packet processing */

	res = radius_msg_get_attr(msg, RADIUS_ATTR_STATE, statebuf,
				  sizeof(statebuf));
	state_included = res >= 0;
	if (res == sizeof(statebuf)) {
		state = (statebuf[0] << 24) | (statebuf[1] << 16) |
			(statebuf[2] << 8) | statebuf[3];
		sess = radius_server_get_session(client, state);
	} else {
		sess = NULL;
	}

	if (sess) {
		RADIUS_DEBUG("Request for session 0x%x", sess->sess_id);
	} else if (state_included) {
		RADIUS_DEBUG("State attribute included but no session found");
		radius_server_reject(data, client, msg, from);
		return -1;
	} else {
		sess = radius_server_get_new_session(data, client, msg);
		if (sess == NULL) {
			RADIUS_DEBUG("Could not create a new session");
			return -1;
		}
	}

	eap = radius_msg_get_eap(msg, &eap_len);
	if (eap == NULL) {
		RADIUS_DEBUG("No EAP-Message in RADIUS packet from %s",
			     inet_ntoa(from->sin_addr));
		return -1;
	}

	RADIUS_DUMP("Received EAP data", eap, eap_len);
	if (eap_len >= sizeof(*hdr)) {
		hdr = (struct eap_hdr *) eap;
		resp_id = hdr->identifier;
	} else {
		resp_id = 0;
	}

	eap_set_eapRespData(sess->eap, eap, eap_len);
	free(eap);
	eap = NULL;
	sess->eapResp = TRUE;
	eap_sm_step(sess->eap);

	if (sess->eapReqData) {
		RADIUS_DUMP("EAP data from the state machine",
			    sess->eapReqData, sess->eapReqDataLen);
	} else if (sess->eapFail) {
		RADIUS_DEBUG("No EAP data from the state machine, but eapFail "
			     "set - generate EAP-Failure");
		hdr = malloc(sizeof(*hdr));
		if (hdr) {
			memset(hdr, 0, sizeof(*hdr));
			hdr->identifier = resp_id;
			hdr->length = htons(sizeof(*hdr));
			sess->eapReqData = (u8 *) hdr;
			sess->eapReqDataLen = sizeof(*hdr);
		}
	} else {
		RADIUS_DEBUG("No EAP data from the state machine - ignore this"
			     " Access-Request silently (assuming it was a "
			     "duplicate)");
		return -1;
	}

	reply = radius_server_encapsulate_eap(data, client, sess, msg);

	free(sess->eapReqData);
	sess->eapReqData = NULL;
	sess->eapReqDataLen = 0;

	if (reply) {
		RADIUS_DEBUG("Reply to %s:%d", inet_ntoa(from->sin_addr),
			     ntohs(from->sin_port));
		if (wpa_debug_level <= MSG_MSGDUMP) {
			radius_msg_dump(reply);
		}

		res = sendto(data->auth_sock, reply->buf, reply->buf_used, 0,
			     (struct sockaddr *) from, sizeof(*from));
		if (res < 0) {
			perror("sendto[RADIUS SRV]");
		}
		radius_msg_free(reply);
		free(reply);
	}

	if (sess->eapSuccess || sess->eapFail) {
		RADIUS_DEBUG("Removing completed session 0x%x", sess->sess_id);
		radius_server_session_remove(data, sess);
	}

	return 0;
}
コード例 #8
0
ファイル: radius_client.c プロジェクト: OPSF/uClinux
static void radius_client_receive(int sock, void *eloop_ctx, void *sock_ctx)
{
	struct wpa_supplicant *wpa_s = (struct wpa_supplicant *) eloop_ctx;
	RadiusType msg_type = (RadiusType) sock_ctx;
	int len, i;
	unsigned char buf[3000];
	struct radius_msg *msg;
	struct radius_rx_handler *handlers;
	size_t num_handlers;
	struct radius_msg_list *req, *prev_req;

	len = recv(sock, buf, sizeof(buf), 0);
	if (len < 0) {
		perror("recv[RADIUS]");
		return;
	}
	HOSTAPD_DEBUG(HOSTAPD_DEBUG_MINIMAL,
		      "Received %d bytes from RADIUS server\n", len);
	if (len == sizeof(buf)) {
		printf("Possibly too long UDP frame for our buffer - "
		       "dropping it\n");
		return;
	}

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

	HOSTAPD_DEBUG(HOSTAPD_DEBUG_MINIMAL,
		      "Received RADIUS message\n");
	if (HOSTAPD_DEBUG_COND(HOSTAPD_DEBUG_MSGDUMPS))
		radius_msg_dump(msg);

	if (msg_type == RADIUS_ACCT) {
		handlers = wpa_s->radius->acct_handlers;
		num_handlers = wpa_s->radius->num_acct_handlers;
	} else {
		handlers = wpa_s->radius->auth_handlers;
		num_handlers = wpa_s->radius->num_auth_handlers;
	}

	prev_req = NULL;
	req = wpa_s->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_type == RADIUS_ACCT_INTERIM &&
		      msg_type == RADIUS_ACCT)) &&
		    req->msg->hdr->identifier == msg->hdr->identifier)
			break;

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

	if (req == NULL) {
		HOSTAPD_DEBUG(HOSTAPD_DEBUG_MINIMAL,
			      "No matching RADIUS request found (type=%d "
			      "id=%d) - dropping packet\n",
			      msg_type, msg->hdr->identifier);
		goto fail;
	}

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

	for (i = 0; i < num_handlers; i++) {
		RadiusRxResult res;
		res = handlers[i].handler(wpa_s, 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;
		}
	}

	printf("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);
}