Example #1
0
static void ieee802_1x_get_keys(struct eapol_test_data *e,
				struct radius_msg *msg, struct radius_msg *req,
				const u8 *shared_secret,
				size_t shared_secret_len)
{
	struct radius_ms_mppe_keys *keys;
	u8 *buf;
	size_t len;

	keys = radius_msg_get_ms_keys(msg, req, shared_secret,
				      shared_secret_len);
	if (keys && keys->send == NULL && keys->recv == NULL) {
		os_free(keys);
		keys = radius_msg_get_cisco_keys(msg, req, shared_secret,
						 shared_secret_len);
	}

	if (keys) {
		if (keys->send) {
			wpa_hexdump(MSG_DEBUG, "MS-MPPE-Send-Key (sign)",
				    keys->send, keys->send_len);
		}
		if (keys->recv) {
			wpa_hexdump(MSG_DEBUG, "MS-MPPE-Recv-Key (crypt)",
				    keys->recv, keys->recv_len);
			e->authenticator_pmk_len =
				keys->recv_len > PMK_LEN ? PMK_LEN :
				keys->recv_len;
			os_memcpy(e->authenticator_pmk, keys->recv,
				  e->authenticator_pmk_len);
			if (e->authenticator_pmk_len == 16 && keys->send &&
			    keys->send_len == 16) {
				/* MS-CHAP-v2 derives 16 octet keys */
				wpa_printf(MSG_DEBUG, "Use MS-MPPE-Send-Key "
					   "to extend PMK to 32 octets");
				os_memcpy(e->authenticator_pmk +
					  e->authenticator_pmk_len,
					  keys->send, keys->send_len);
				e->authenticator_pmk_len += keys->send_len;
			}
		}

		os_free(keys->send);
		os_free(keys->recv);
		os_free(keys);
	}

	if (radius_msg_get_attr_ptr(msg, RADIUS_ATTR_EAP_KEY_NAME, &buf, &len,
				    NULL) == 0) {
		os_memcpy(e->authenticator_eap_key_name, buf, len);
		e->authenticator_eap_key_name_len = len;
	} else {
		e->authenticator_eap_key_name_len = 0;
	}
}
Example #2
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;
}
Example #3
0
/**
 * hostapd_acl_recv_radius - Process incoming RADIUS Authentication messages
 * @msg: RADIUS response message
 * @req: RADIUS request message
 * @shared_secret: RADIUS shared secret
 * @shared_secret_len: Length of shared_secret in octets
 * @data: Context data (struct hostapd_data *)
 * Returns: RADIUS_RX_PROCESSED if RADIUS message was a reply to ACL query (and
 * was processed here) or RADIUS_RX_UNKNOWN if not.
 */
static RadiusRxResult
hostapd_acl_recv_radius(struct radius_msg *msg, struct radius_msg *req,
			const u8 *shared_secret, size_t shared_secret_len,
			void *data)
{
	struct hostapd_data *hapd = data;
	struct hostapd_acl_query_data *query, *prev;
	struct hostapd_cached_radius_acl *cache;
	struct radius_hdr *hdr = radius_msg_get_hdr(msg);

	query = hapd->acl_queries;
	prev = NULL;
	while (query) {
		if (query->radius_id == hdr->identifier)
			break;
		prev = query;
		query = query->next;
	}
	if (query == NULL)
		return RADIUS_RX_UNKNOWN;

	wpa_printf(MSG_DEBUG, "Found matching Access-Request for RADIUS "
		   "message (id=%d)", query->radius_id);

	if (radius_msg_verify(msg, shared_secret, shared_secret_len, req, 0)) {
		wpa_printf(MSG_INFO, "Incoming RADIUS packet did not have "
			   "correct authenticator - dropped\n");
		return RADIUS_RX_INVALID_AUTHENTICATOR;
	}

	if (hdr->code != RADIUS_CODE_ACCESS_ACCEPT &&
	    hdr->code != RADIUS_CODE_ACCESS_REJECT) {
		wpa_printf(MSG_DEBUG, "Unknown RADIUS message code %d to ACL "
			   "query", hdr->code);
		return RADIUS_RX_UNKNOWN;
	}

	/* Insert Accept/Reject info into ACL cache */
	cache = os_zalloc(sizeof(*cache));
	if (cache == NULL) {
		wpa_printf(MSG_DEBUG, "Failed to add ACL cache entry");
		goto done;
	}
	os_get_reltime(&cache->timestamp);
	os_memcpy(cache->addr, query->addr, sizeof(cache->addr));
	if (hdr->code == RADIUS_CODE_ACCESS_ACCEPT) {
		u8 *buf;
		size_t len;

		if (radius_msg_get_attr_int32(msg, RADIUS_ATTR_SESSION_TIMEOUT,
					      &cache->session_timeout) == 0)
			cache->accepted = HOSTAPD_ACL_ACCEPT_TIMEOUT;
		else
			cache->accepted = HOSTAPD_ACL_ACCEPT;

		if (radius_msg_get_attr_int32(
			    msg, RADIUS_ATTR_ACCT_INTERIM_INTERVAL,
			    &cache->acct_interim_interval) == 0 &&
		    cache->acct_interim_interval < 60) {
			wpa_printf(MSG_DEBUG, "Ignored too small "
				   "Acct-Interim-Interval %d for STA " MACSTR,
				   cache->acct_interim_interval,
				   MAC2STR(query->addr));
			cache->acct_interim_interval = 0;
		}

		cache->vlan_id = radius_msg_get_vlanid(msg);

		decode_tunnel_passwords(hapd, shared_secret, shared_secret_len,
					msg, req, cache);

		if (radius_msg_get_attr_ptr(msg, RADIUS_ATTR_USER_NAME,
					    &buf, &len, NULL) == 0) {
			cache->identity = os_zalloc(len + 1);
			if (cache->identity)
				os_memcpy(cache->identity, buf, len);
		}
		if (radius_msg_get_attr_ptr(
			    msg, RADIUS_ATTR_CHARGEABLE_USER_IDENTITY,
			    &buf, &len, NULL) == 0) {
			cache->radius_cui = os_zalloc(len + 1);
			if (cache->radius_cui)
				os_memcpy(cache->radius_cui, buf, len);
		}

		if (hapd->conf->wpa_psk_radius == PSK_RADIUS_REQUIRED &&
		    !cache->psk)
			cache->accepted = HOSTAPD_ACL_REJECT;
	} else
		cache->accepted = HOSTAPD_ACL_REJECT;
	cache->next = hapd->acl_cache;
	hapd->acl_cache = cache;

#ifdef CONFIG_DRIVER_RADIUS_ACL
	hostapd_drv_set_radius_acl_auth(hapd, query->addr, cache->accepted,
					cache->session_timeout);
#else /* CONFIG_DRIVER_RADIUS_ACL */
#ifdef NEED_AP_MLME
	/* Re-send original authentication frame for 802.11 processing */
	wpa_printf(MSG_DEBUG, "Re-sending authentication frame after "
		   "successful RADIUS ACL query");
	ieee802_11_mgmt(hapd, query->auth_msg, query->auth_msg_len, NULL);
#endif /* NEED_AP_MLME */
#endif /* CONFIG_DRIVER_RADIUS_ACL */

 done:
	if (prev == NULL)
		hapd->acl_queries = query->next;
	else
		prev->next = query->next;

	hostapd_acl_query_free(query);

	return RADIUS_RX_PROCESSED;
}
Example #4
0
static struct radius_msg * radius_das_disconnect(struct radius_das_data *das,
						 struct radius_msg *msg,
						 const char *abuf,
						 int from_port)
{
	struct radius_hdr *hdr;
	struct radius_msg *reply;
	u8 allowed[] = {
		RADIUS_ATTR_USER_NAME,
		RADIUS_ATTR_NAS_IP_ADDRESS,
		RADIUS_ATTR_CALLING_STATION_ID,
		RADIUS_ATTR_NAS_IDENTIFIER,
		RADIUS_ATTR_ACCT_SESSION_ID,
		RADIUS_ATTR_ACCT_MULTI_SESSION_ID,
		RADIUS_ATTR_EVENT_TIMESTAMP,
		RADIUS_ATTR_MESSAGE_AUTHENTICATOR,
		RADIUS_ATTR_CHARGEABLE_USER_IDENTITY,
#ifdef CONFIG_IPV6
		RADIUS_ATTR_NAS_IPV6_ADDRESS,
#endif /* CONFIG_IPV6 */
		0
	};
	int error = 405;
	u8 attr;
	enum radius_das_res res;
	struct radius_das_attrs attrs;
	u8 *buf;
	size_t len;
	char tmp[100];
	u8 sta_addr[ETH_ALEN];

	hdr = radius_msg_get_hdr(msg);

	attr = radius_msg_find_unlisted_attr(msg, allowed);
	if (attr) {
		wpa_printf(MSG_INFO, "DAS: Unsupported attribute %u in "
			   "Disconnect-Request from %s:%d", attr,
			   abuf, from_port);
		error = 401;
		goto fail;
	}

	os_memset(&attrs, 0, sizeof(attrs));

	if (radius_msg_get_attr_ptr(msg, RADIUS_ATTR_NAS_IP_ADDRESS,
				    &buf, &len, NULL) == 0) {
		if (len != 4) {
			wpa_printf(MSG_INFO, "DAS: Invalid NAS-IP-Address from %s:%d",
				   abuf, from_port);
			error = 407;
			goto fail;
		}
		attrs.nas_ip_addr = buf;
	}

#ifdef CONFIG_IPV6
	if (radius_msg_get_attr_ptr(msg, RADIUS_ATTR_NAS_IPV6_ADDRESS,
				    &buf, &len, NULL) == 0) {
		if (len != 16) {
			wpa_printf(MSG_INFO, "DAS: Invalid NAS-IPv6-Address from %s:%d",
				   abuf, from_port);
			error = 407;
			goto fail;
		}
		attrs.nas_ipv6_addr = buf;
	}
#endif /* CONFIG_IPV6 */

	if (radius_msg_get_attr_ptr(msg, RADIUS_ATTR_NAS_IDENTIFIER,
				    &buf, &len, NULL) == 0) {
		attrs.nas_identifier = buf;
		attrs.nas_identifier_len = len;
	}

	if (radius_msg_get_attr_ptr(msg, RADIUS_ATTR_CALLING_STATION_ID,
				    &buf, &len, NULL) == 0) {
		if (len >= sizeof(tmp))
			len = sizeof(tmp) - 1;
		os_memcpy(tmp, buf, len);
		tmp[len] = '\0';
		if (hwaddr_aton2(tmp, sta_addr) < 0) {
			wpa_printf(MSG_INFO, "DAS: Invalid Calling-Station-Id "
				   "'%s' from %s:%d", tmp, abuf, from_port);
			error = 407;
			goto fail;
		}
		attrs.sta_addr = sta_addr;
	}

	if (radius_msg_get_attr_ptr(msg, RADIUS_ATTR_USER_NAME,
				    &buf, &len, NULL) == 0) {
		attrs.user_name = buf;
		attrs.user_name_len = len;
	}

	if (radius_msg_get_attr_ptr(msg, RADIUS_ATTR_ACCT_SESSION_ID,
				    &buf, &len, NULL) == 0) {
		attrs.acct_session_id = buf;
		attrs.acct_session_id_len = len;
	}

	if (radius_msg_get_attr_ptr(msg, RADIUS_ATTR_ACCT_MULTI_SESSION_ID,
				    &buf, &len, NULL) == 0) {
		attrs.acct_multi_session_id = buf;
		attrs.acct_multi_session_id_len = len;
	}

	if (radius_msg_get_attr_ptr(msg, RADIUS_ATTR_CHARGEABLE_USER_IDENTITY,
				    &buf, &len, NULL) == 0) {
		attrs.cui = buf;
		attrs.cui_len = len;
	}

	res = das->disconnect(das->ctx, &attrs);
	switch (res) {
	case RADIUS_DAS_NAS_MISMATCH:
		wpa_printf(MSG_INFO, "DAS: NAS mismatch from %s:%d",
			   abuf, from_port);
		error = 403;
		break;
	case RADIUS_DAS_SESSION_NOT_FOUND:
		wpa_printf(MSG_INFO, "DAS: Session not found for request from "
			   "%s:%d", abuf, from_port);
		error = 503;
		break;
	case RADIUS_DAS_MULTI_SESSION_MATCH:
		wpa_printf(MSG_INFO,
			   "DAS: Multiple sessions match for request from %s:%d",
			   abuf, from_port);
		error = 508;
		break;
	case RADIUS_DAS_SUCCESS:
		error = 0;
		break;
	}

fail:
	reply = radius_msg_new(error ? RADIUS_CODE_DISCONNECT_NAK :
			       RADIUS_CODE_DISCONNECT_ACK, hdr->identifier);
	if (reply == NULL)
		return NULL;

	if (error) {
		if (!radius_msg_add_attr_int32(reply, RADIUS_ATTR_ERROR_CAUSE,
					       error)) {
			radius_msg_free(reply);
			return NULL;
		}
	}

	return reply;
}