Пример #1
0
static void
toss_sta(nas_t *nas, nas_sta_t *sta, int reason, int driver_signal)
{
	nas_sta_t *sta_list;
	uint hash;
#ifdef BCMDBG
	char eabuf[ETHER_ADDR_STR_LEN];
#endif
	if (sta == NULL) {
		dbg(nas, "called with NULL STA ponter");
		return;
	}
	/* If this is because of a driver message, telling the driver again
	 * is unnecessary (and could loop).
	 */
	if (!driver_signal) {
		dbg(nas, "deauthenticating %s", ether_etoa((uchar *)&sta->ea, eabuf));
		nas_deauthenticate(nas, &sta->ea, reason);
	}
	/* Be careful not to leak timer descriptors. */
	wpa_stop_retx(sta);
	dbg(nas, "cleanup STA %s", ether_etoa((uchar *)&sta->ea, eabuf));
	/* Remove this one from its hashed list. */
	hash = pae_hash(&sta->ea);
	sta_list = nas->sta_hashed[hash];

	if (sta_list == sta) {
		/* It was the head, so its next is the new head. */
		nas->sta_hashed[hash] = sta->next;

	} else {
		/* Find the one that points to it and change the pointer. */
		while ((sta_list != NULL) && (sta_list->next != sta))
			sta_list = sta_list->next;
		if (sta_list == NULL) {
			dbg(nas, "sta %s not in hash list",
			    ether_etoa((uchar *)&sta->ea, eabuf));
		} else {
			sta_list->next = sta->next;
		}
	}

	sta->used = FALSE;
	return;
}
Пример #2
0
/* Proxy EAP packet from PAE to RADIUS server */
void
radius_forward(nas_t *nas, nas_sta_t *sta, eap_header_t *eap)
{
	radius_header_t *request;

	unsigned char buf[16], *ptr;
	long val;
	int left;

	/* Allocate packet */
	if (!(request = malloc(RADIUS_MAX_LEN))) {
		perror("malloc");
		return;
	}

	/* Fill header */
	request->code = RADIUS_ACCESS_REQUEST;
	request->id = sta - nas->sta;
	request->length = htons(RADIUS_HEADER_LEN);

	/* Fill Request Authenticator */
	nas_rand128(request->vector);

	/* Fill attributes */

	/* User Name */
	if (sta->pae.radius.username.data && sta->pae.radius.username.length)
		radius_add(request, RD_TP_USER_NAME, sta->pae.radius.username.data,
		           sta->pae.radius.username.length);
	/* NAS IP Address */
	radius_add(request, RD_TP_NAS_IP_ADDRESS, (unsigned char *) &nas->client.sin_addr,
	           sizeof(nas->client.sin_addr));
	/* Called Station Id */

	snprintf((char *)buf, sizeof(buf), "%02x%02x%02x%02x%02x%02x",
	         ((unsigned char *) &nas->ea)[0], ((unsigned char *) &nas->ea)[1],
	         ((unsigned char *) &nas->ea)[2],
	         ((unsigned char *) &nas->ea)[3], ((unsigned char *) &nas->ea)[4],
	         ((unsigned char *) &nas->ea)[5]);

	radius_add(request, RD_TP_CALLED_STATION_ID, buf, strlen((char *)buf));
	/* Calling Station Id */
	snprintf((char *)buf, sizeof(buf), "%02x%02x%02x%02x%02x%02x",
	         ((unsigned char *) &sta->ea)[0], ((unsigned char *) &sta->ea)[1],
	         ((unsigned char *) &sta->ea)[2],
	         ((unsigned char *) &sta->ea)[3], ((unsigned char *) &sta->ea)[4],
	         ((unsigned char *) &sta->ea)[5]);
	radius_add(request, RD_TP_CALLING_STATION_ID, buf, strlen((char *)buf));
	/* NAS identifier */
	if (strlen(nas->nas_id))
		radius_add(request, RD_TP_NAS_IDENTIFIER, (unsigned char *)nas->nas_id,
		           strlen(nas->nas_id));
	else {
		snprintf((char *)buf, sizeof(buf), "%02x%02x%02x%02x%02x%02x",
		         ((unsigned char *) &nas->ea)[0], ((unsigned char *) &nas->ea)[1],
		         ((unsigned char *) &nas->ea)[2],
		         ((unsigned char *) &nas->ea)[3], ((unsigned char *) &nas->ea)[4],
		         ((unsigned char *) &nas->ea)[5]);
		radius_add(request, RD_TP_NAS_IDENTIFIER, buf, strlen((char *)buf));
	}
	/* NAS Port */
	val = htonl((long) pae_hash(&sta->ea));
	radius_add(request, RD_TP_NAS_PORT, (unsigned char *) &val, sizeof(val));
	val = htonl(1400);
	radius_add(request, RD_TP_FRAMED_MTU, (unsigned char *) &val,
	           sizeof(val));
	/* State */
	if (sta->pae.radius.state.data && sta->pae.radius.state.length) {
		radius_add(request, RD_TP_STATE, sta->pae.radius.state.data,
		           sta->pae.radius.state.length);
		free(sta->pae.radius.state.data);
		sta->pae.radius.state.data = NULL;
		sta->pae.radius.state.length = 0;
	}
	/* NAS Port Type */
	val = htonl((long) nas->type);
	radius_add(request, RD_TP_NAS_PORT_TYPE, (unsigned char *) &val, 4);
	/* EAP Message(s) */
	if (eap) {
		for (left = ntohs(eap->length); left > 0; left -= 253) {
			radius_add(request, RD_TP_EAP_MESSAGE,
			           (unsigned char *) eap + ntohs(eap->length) - left,
			           left <= 253 ? left : 253);
		}
	}
	/* Message Authenticator */
	memset(buf, 0, 16);
	radius_add(request, RD_TP_MESSAGE_AUTHENTICATOR, buf, 16);
	ptr = (unsigned char *) request + ntohs(request->length) - 16;
	/* Calculate HMAC-MD5 checksum with null signature */
	hmac_md5((unsigned char *) request, ntohs(request->length),
	         nas->secret.data, nas->secret.length, ptr);

	/* Send packet */
	if (NAS_RADIUS_SEND_PACKET(nas, request, ntohs(request->length)) < 0) {
		perror(inet_ntoa(nas->server.sin_addr));
		free(request);
		request = NULL;
	}

	/* Save original request packet */
	if (sta->pae.radius.request)
		free(sta->pae.radius.request);
	sta->pae.radius.request = request;
}
Пример #3
0
/*
 * Search for or create a STA struct.
 * If `enter' is not set, do not create it when one is not found.
 */
nas_sta_t *
lookup_sta(nas_t *nas, struct ether_addr *ea, sta_lookup_mode_t mode)
{
	unsigned int hash;
	nas_sta_t *sta;
	time_t now, oldest;

	hash = pae_hash(ea);

	/* Search for entry in the hash table */
	for (sta = nas->sta_hashed[hash];
	     sta && memcmp(&sta->ea, ea, ETHER_ADDR_LEN);
	     sta = sta->next);

	/* One second resolution is probably good enough. */
	(void) time(&now);

	/* Allocate a new entry */
	if (!sta) {
		int i, old_idx = -1;

		/* Don't make an unwanted entry. */
		if (mode == SEARCH_ONLY)
			return NULL;

		oldest = now;
		for (i = 0; i < MAX_SUPPLICANTS; i++) {
			if (!nas->sta[i].used)
				break;
			else if (nas->sta[i].last_use < oldest) {
				oldest = nas->sta[i].last_use;
				old_idx = i;
			}
		}

		if (i < MAX_SUPPLICANTS) {
			sta = &nas->sta[i];
		} else if (old_idx == -1) {
			/* Full up with all the same timestamp?!  Can
			 * this really happen?
			 */
			return NULL;
		} else {
			/* Didn't find one unused, so age out LRU entry. */
			sta = &nas->sta[old_idx];
			toss_sta(nas, sta, DOT11_RC_BUSY, 0);
		}

		if ((sta != NULL) && (sta->pae.radius.request != NULL)) {
			free(sta->pae.radius.request);
		}
		/* Initialize entry */
		memset(sta, 0, (sizeof(nas_sta_t)));
		memcpy(&sta->ea, ea, ETHER_ADDR_LEN);
		sta->used = TRUE;
		sta->nas = nas;
		/* initialize EAPOL version */
		sta->eapol_version = WPA_EAPOL_VERSION;

		/* Initial STA state:
		 * Cheaper and harmless not to distiguish NAS mode.
		 */
		if (nas->flags & NAS_FLAG_AUTHENTICATOR)
			sta->suppl.state = sta->suppl.retry_state = WPA_AUTHENTICATION2;
#ifdef BCMSUPPL
		if (nas->flags & NAS_FLAG_SUPPLICANT)
			sta->suppl.state = sta->suppl.retry_state = WPA_SUP_AUTHENTICATION;
		sta->suppl.pk_state = EAPOL_SUP_PK_UNKNOWN;
#endif
		sta->pae.state = INITIALIZE;

		/* initial mode/wsec/algom. assoc proc will override them */
		if ((nas->mode & RADIUS) && (nas->wsec & WEP_ENABLED)) {
			sta->mode = RADIUS;
			sta->wsec = WEP_ENABLED;
			sta->algo = CRYPTO_ALGO_WEP128;
		}
		else {
			sta->mode = 0;
			sta->wsec = 0;
			sta->algo = 0;
		}
		dbg(nas, "mode %d wsec %d algo %d", sta->mode, sta->wsec, sta->algo);

		/* Add entry to the cache */
		sta->next = nas->sta_hashed[hash];
		nas->sta_hashed[hash] = sta;
		sta->flags = 0;
	}
	sta->last_use = now;
	return sta;
}