aboutsummaryrefslogtreecommitdiff
path: root/contrib
diff options
context:
space:
mode:
authorSam Leffler <sam@FreeBSD.org>2005-06-13 16:43:14 +0000
committerSam Leffler <sam@FreeBSD.org>2005-06-13 16:43:14 +0000
commit1c3c13af99c093e214b6190bf51b030ad0db21e3 (patch)
tree7f2665d52ef063d679023d8971f394c7a8715809 /contrib
parent4df0b3fb129875b3e2219c512ae8223fc8d2398c (diff)
downloadsrc-1c3c13af99c093e214b6190bf51b030ad0db21e3.tar.gz
src-1c3c13af99c093e214b6190bf51b030ad0db21e3.zip
stripped down import of wpa_supplicant v0.3.9
Approved by: re (dwhite)
Notes
Notes: svn path=/vendor/wpa_supplicant/dist/; revision=147338
Diffstat (limited to 'contrib')
-rw-r--r--contrib/wpa_supplicant/ChangeLog23
-rw-r--r--contrib/wpa_supplicant/README4
-rw-r--r--contrib/wpa_supplicant/common.h4
-rw-r--r--contrib/wpa_supplicant/config.c10
-rw-r--r--contrib/wpa_supplicant/ctrl_iface.c15
-rw-r--r--contrib/wpa_supplicant/eap.c14
-rw-r--r--contrib/wpa_supplicant/eap_mschapv2.c11
-rw-r--r--contrib/wpa_supplicant/eap_peap.c38
-rw-r--r--contrib/wpa_supplicant/eap_tls_common.c11
-rw-r--r--contrib/wpa_supplicant/eap_ttls.c12
-rw-r--r--contrib/wpa_supplicant/eapol_sm.c3
-rw-r--r--contrib/wpa_supplicant/ms_funcs.c4
-rw-r--r--contrib/wpa_supplicant/radius.c1125
-rw-r--r--contrib/wpa_supplicant/radius.h224
-rw-r--r--contrib/wpa_supplicant/tls_openssl.c9
-rw-r--r--contrib/wpa_supplicant/version.h2
-rw-r--r--contrib/wpa_supplicant/wpa.c16
-rw-r--r--contrib/wpa_supplicant/wpa_ctrl.c9
-rw-r--r--contrib/wpa_supplicant/wpa_supplicant.c59
-rw-r--r--contrib/wpa_supplicant/wpa_supplicant_i.h3
20 files changed, 1554 insertions, 42 deletions
diff --git a/contrib/wpa_supplicant/ChangeLog b/contrib/wpa_supplicant/ChangeLog
index 57098581aee3..09d5b6121551 100644
--- a/contrib/wpa_supplicant/ChangeLog
+++ b/contrib/wpa_supplicant/ChangeLog
@@ -1,5 +1,28 @@
ChangeLog for wpa_supplicant
+2005-06-10 - v0.3.9
+ * modified the EAP workaround that accepts EAP-Success with incorrect
+ Identifier to be even less strict about verification in order to
+ interoperate with some authentication servers
+ * fixed RSN IE in 4-Way Handshake message 2/4 for the case where
+ Authenticator rejects PMKSA caching attempt and the driver is not
+ using assoc_info events
+ * fixed a possible double free in EAP-TTLS fast-reauthentication when
+ identity or password is entered through control interface
+ * added -P<pid file> argument for wpa_supplicant to write the current
+ process id into a file
+ * driver_madwifi: fixed association in plaintext mode
+ * driver_madwifi: added preliminary support for compiling against 'BSD'
+ branch of madwifi CVS tree
+ * added EAP workaround for PEAPv1 session resumption: allow outer,
+ i.e., not tunneled, EAP-Success to terminate session since; this can
+ be disabled with eap_workaround=0
+ * driver_ipw: updated driver structures to match with ipw2200-1.0.4
+ (note: ipw2100-1.1.0 is likely to require an update to work with
+ this)
+ * driver_broadcom: fixed couple of memory leaks in scan result
+ processing
+
2005-02-13 - v0.3.8
* fixed EAPOL-Key validation to drop packets with invalid Key Data
Length; such frames could have crashed wpa_supplicant due to buffer
diff --git a/contrib/wpa_supplicant/README b/contrib/wpa_supplicant/README
index 7b5f5476a160..bab25d586725 100644
--- a/contrib/wpa_supplicant/README
+++ b/contrib/wpa_supplicant/README
@@ -6,9 +6,7 @@ contributors
All Rights Reserved.
This program is dual-licensed under both the GPL version 2 and BSD
-license. Either license may be used at your option. Please note that
-some of the driver interface implementations (driver_*.c) may be
-licensed under a different license.
+license. Either license may be used at your option.
diff --git a/contrib/wpa_supplicant/common.h b/contrib/wpa_supplicant/common.h
index aa6429c76b96..0f154e901bff 100644
--- a/contrib/wpa_supplicant/common.h
+++ b/contrib/wpa_supplicant/common.h
@@ -8,8 +8,12 @@
#ifdef __FreeBSD__
#include <sys/types.h>
#include <sys/endian.h>
+#define __BYTE_ORDER _BYTE_ORDER
+#define __LITTLE_ENDIAN _LITTLE_ENDIAN
+#define __BIG_ENDIAN _BIG_ENDIAN
#define bswap_16 bswap16
#define bswap_32 bswap32
+#define bswap_64 bswap64
#endif
#ifdef CONFIG_NATIVE_WINDOWS
diff --git a/contrib/wpa_supplicant/config.c b/contrib/wpa_supplicant/config.c
index 241c75565f88..26307cf3f80b 100644
--- a/contrib/wpa_supplicant/config.c
+++ b/contrib/wpa_supplicant/config.c
@@ -245,7 +245,7 @@ static int wpa_config_parse_proto(struct parse_data *data, int line,
return -1;
start = buf;
- while (start != '\0') {
+ while (*start != '\0') {
while (*start == ' ' || *start == '\t')
start++;
if (*start == '\0')
@@ -295,7 +295,7 @@ static int wpa_config_parse_key_mgmt(struct parse_data *data, int line,
return -1;
start = buf;
- while (start != '\0') {
+ while (*start != '\0') {
while (*start == ' ' || *start == '\t')
start++;
if (*start == '\0')
@@ -349,7 +349,7 @@ static int wpa_config_parse_cipher(int line, const char *value)
return -1;
start = buf;
- while (start != '\0') {
+ while (*start != '\0') {
while (*start == ' ' || *start == '\t')
start++;
if (*start == '\0')
@@ -441,7 +441,7 @@ static int wpa_config_parse_auth_alg(struct parse_data *data, int line,
return -1;
start = buf;
- while (start != '\0') {
+ while (*start != '\0') {
while (*start == ' ' || *start == '\t')
start++;
if (*start == '\0')
@@ -494,7 +494,7 @@ static int wpa_config_parse_eap(struct parse_data *data, int line,
return -1;
start = buf;
- while (start != '\0') {
+ while (*start != '\0') {
while (*start == ' ' || *start == '\t')
start++;
if (*start == '\0')
diff --git a/contrib/wpa_supplicant/ctrl_iface.c b/contrib/wpa_supplicant/ctrl_iface.c
index e41881104ede..25cf0dbcbde7 100644
--- a/contrib/wpa_supplicant/ctrl_iface.c
+++ b/contrib/wpa_supplicant/ctrl_iface.c
@@ -248,8 +248,9 @@ static int wpa_supplicant_ctrl_iface_ctrl_rsp(struct wpa_supplicant *wpa_s,
return -1;
*pos++ = '\0';
id = atoi(id_pos);
- wpa_printf(MSG_DEBUG, "CTRL_IFACE: field=%s id=%d value='%s'",
- rsp, id, pos);
+ wpa_printf(MSG_DEBUG, "CTRL_IFACE: field=%s id=%d", rsp, id);
+ wpa_hexdump_ascii_key(MSG_DEBUG, "CTRL_IFACE: value",
+ (u8 *) pos, strlen(pos));
ssid = wpa_s->conf->ssid;
while (ssid) {
@@ -606,6 +607,16 @@ void wpa_supplicant_ctrl_iface_deinit(struct wpa_supplicant *wpa_s)
if (wpa_s->ctrl_sock > -1) {
char *fname;
eloop_unregister_read_sock(wpa_s->ctrl_sock);
+ if (wpa_s->ctrl_dst) {
+ /*
+ * Wait a second before closing the control socket if
+ * there are any attached monitors in order to allow
+ * them to receive any pending messages.
+ */
+ wpa_printf(MSG_DEBUG, "CTRL_IFACE wait for attached "
+ "monitors to receive messages");
+ sleep(1);
+ }
close(wpa_s->ctrl_sock);
wpa_s->ctrl_sock = -1;
fname = wpa_supplicant_ctrl_iface_path(wpa_s);
diff --git a/contrib/wpa_supplicant/eap.c b/contrib/wpa_supplicant/eap.c
index a76b942464e8..267907c27fe0 100644
--- a/contrib/wpa_supplicant/eap.c
+++ b/contrib/wpa_supplicant/eap.c
@@ -458,19 +458,27 @@ SM_STATE(EAP, FAILURE)
static int eap_success_workaround(struct eap_sm *sm, int reqId, int lastId)
{
- /* At least Microsoft IAS and Meetinghouse Aegis seem to be sending
+ /*
+ * At least Microsoft IAS and Meetinghouse Aegis seem to be sending
* EAP-Success/Failure with lastId + 1 even though RFC 3748 and
* draft-ietf-eap-statemachine-05.pdf require that reqId == lastId.
+ * In addition, it looks like Ringmaster v2.1.2.0 would be using
+ * lastId + 2 in EAP-Success.
+ *
* Accept this kind of Id if EAP workarounds are enabled. These are
* unauthenticated plaintext messages, so this should have minimal
- * security implications (bit easier to fake EAP-Success/Failure). */
- if (sm->workaround && reqId == ((lastId + 1) & 0xff)) {
+ * security implications (bit easier to fake EAP-Success/Failure).
+ */
+ if (sm->workaround && (reqId == ((lastId + 1) & 0xff) ||
+ reqId == ((lastId + 2) & 0xff))) {
wpa_printf(MSG_DEBUG, "EAP: Workaround for unexpected "
"identifier field in EAP Success: "
"reqId=%d lastId=%d (these are supposed to be "
"same)", reqId, lastId);
return 1;
}
+ wpa_printf(MSG_DEBUG, "EAP: EAP-Success Id mismatch - reqId=%d "
+ "lastId=%d", reqId, lastId);
return 0;
}
diff --git a/contrib/wpa_supplicant/eap_mschapv2.c b/contrib/wpa_supplicant/eap_mschapv2.c
index a39a5d330a78..35c391c63c48 100644
--- a/contrib/wpa_supplicant/eap_mschapv2.c
+++ b/contrib/wpa_supplicant/eap_mschapv2.c
@@ -126,8 +126,8 @@ static u8 * eap_mschapv2_challenge(struct eap_sm *sm,
{
struct wpa_ssid *config = eap_get_config(sm);
u8 *challenge, *peer_challenge, *username, *pos;
- int challenge_len, i, ms_len;
- size_t len, username_len;
+ int i, ms_len;
+ size_t len, challenge_len, username_len;
struct eap_mschapv2_hdr *resp;
u8 password_hash[16], password_hash_hash[16];
@@ -155,10 +155,12 @@ static u8 * eap_mschapv2_challenge(struct eap_sm *sm,
return NULL;
}
- if (len - challenge_len - 10 < 0) {
+ if (len < 10 || len - 10 < challenge_len) {
wpa_printf(MSG_INFO, "EAP-MSCHAPV2: Too short challenge"
" packet: len=%lu challenge_len=%d",
(unsigned long) len, challenge_len);
+ ret->ignore = TRUE;
+ return NULL;
}
challenge = pos;
@@ -469,7 +471,8 @@ static u8 * eap_mschapv2_process(struct eap_sm *sm, void *priv,
req = (struct eap_mschapv2_hdr *) reqData;
len = be_to_host16(req->length);
- if (len < sizeof(*req) + 2 || req->type != EAP_TYPE_MSCHAPV2) {
+ if (len < sizeof(*req) + 2 || req->type != EAP_TYPE_MSCHAPV2 ||
+ len > reqDataLen) {
wpa_printf(MSG_INFO, "EAP-MSCHAPV2: Invalid frame");
ret->ignore = TRUE;
return NULL;
diff --git a/contrib/wpa_supplicant/eap_peap.c b/contrib/wpa_supplicant/eap_peap.c
index 27f0793cb8c1..8ca8ab260321 100644
--- a/contrib/wpa_supplicant/eap_peap.c
+++ b/contrib/wpa_supplicant/eap_peap.c
@@ -380,6 +380,12 @@ static int eap_peap_decrypt(struct eap_sm *sm,
if (data->pending_phase2_req) {
wpa_printf(MSG_DEBUG, "EAP-PEAP: Pending Phase 2 request - "
"skip decryption and use old data");
+ /* Clear TLS reassembly state. */
+ free(data->ssl.tls_in);
+ data->ssl.tls_in = NULL;
+ data->ssl.tls_in_len = 0;
+ data->ssl.tls_in_left = 0;
+ data->ssl.tls_in_total = 0;
in_decrypted = data->pending_phase2_req;
data->pending_phase2_req = NULL;
len_decrypted = data->pending_phase2_req_len;
@@ -391,6 +397,19 @@ static int eap_peap_decrypt(struct eap_sm *sm,
if (res < 0 || res == 1)
return res;
+ if (in_len == 0 && sm->workaround && data->phase2_success) {
+ /*
+ * Cisco ACS seems to be using TLS ACK to terminate
+ * EAP-PEAPv0/GTC. Try to reply with TLS ACK.
+ */
+ wpa_printf(MSG_DEBUG, "EAP-PEAP: Received TLS ACK, but "
+ "expected data - acknowledge with TLS ACK since "
+ "Phase 2 has been completed");
+ ret->decision = DECISION_COND_SUCC;
+ ret->methodState = METHOD_DONE;
+ return 1;
+ }
+
buf_len = in_len;
if (data->ssl.tls_in_total > buf_len)
buf_len = data->ssl.tls_in_total;
@@ -713,6 +732,25 @@ static u8 * eap_peap_process(struct eap_sm *sm, void *priv,
wpa_printf(MSG_DEBUG, "EAP-PEAP: Failed to "
"derive key");
}
+
+ if (sm->workaround && data->peap_version == 1 &&
+ data->resuming) {
+ /*
+ * At least one RADIUS server (Aegis v1.1.6;
+ * but not v1.1.4) seems to be terminating
+ * PEAPv1 session resumption with outer
+ * EAP-Success. This does not seem to follow
+ * draft-josefsson-pppext-eap-tls-eap-05.txt
+ * section 4.2, so only allow this if EAP
+ * workarounds are enabled.
+ */
+ wpa_printf(MSG_DEBUG, "EAP-PEAP: Workaround - "
+ "allow outer EAP-Success to "
+ "terminate PEAPv1 resumption");
+ ret->decision = DECISION_COND_SUCC;
+ data->phase2_success = 1;
+ }
+
data->resuming = 0;
}
}
diff --git a/contrib/wpa_supplicant/eap_tls_common.c b/contrib/wpa_supplicant/eap_tls_common.c
index 20b141846790..a56538c8aa65 100644
--- a/contrib/wpa_supplicant/eap_tls_common.c
+++ b/contrib/wpa_supplicant/eap_tls_common.c
@@ -160,6 +160,17 @@ int eap_tls_data_reassemble(struct eap_sm *sm, struct eap_ssl_data *data,
u8 *buf;
if (data->tls_in_left > *in_len || data->tls_in) {
+ if (data->tls_in_len + *in_len == 0) {
+ free(data->tls_in);
+ data->tls_in = NULL;
+ data->tls_in_len = 0;
+ wpa_printf(MSG_WARNING, "SSL: Invalid reassembly "
+ "state: tls_in_left=%d tls_in_len=%d "
+ "*in_len=%d",
+ data->tls_in_left, data->tls_in_len,
+ *in_len);
+ return -1;
+ }
buf = realloc(data->tls_in, data->tls_in_len + *in_len);
if (buf == NULL) {
free(data->tls_in);
diff --git a/contrib/wpa_supplicant/eap_ttls.c b/contrib/wpa_supplicant/eap_ttls.c
index b639fcd54dc8..733f136997e4 100644
--- a/contrib/wpa_supplicant/eap_ttls.c
+++ b/contrib/wpa_supplicant/eap_ttls.c
@@ -194,7 +194,7 @@ static int eap_ttls_encrypt(struct eap_sm *sm, struct eap_ttls_data *data,
* add TLS Message Length field, if the frame is fragmented. */
resp = malloc(sizeof(struct eap_hdr) + 2 + data->ssl.tls_out_limit);
if (resp == NULL)
- return 0;
+ return -1;
resp->code = EAP_CODE_RESPONSE;
resp->identifier = id;
@@ -210,7 +210,7 @@ static int eap_ttls_encrypt(struct eap_sm *sm, struct eap_ttls_data *data,
wpa_printf(MSG_INFO, "EAP-TTLS: Failed to encrypt Phase 2 "
"data");
free(resp);
- return 0;
+ return -1;
}
*out_len = sizeof(struct eap_hdr) + 2 + res;
@@ -265,6 +265,7 @@ static int eap_ttls_avp_encapsulate(u8 **resp, size_t *resp_len, u32 avp_code,
avp = malloc(sizeof(struct ttls_avp) + *resp_len + 4);
if (avp == NULL) {
free(*resp);
+ *resp = NULL;
*resp_len = 0;
return -1;
}
@@ -782,6 +783,13 @@ static int eap_ttls_decrypt(struct eap_sm *sm, struct eap_ttls_data *data,
if (data->pending_phase2_req) {
wpa_printf(MSG_DEBUG, "EAP-TTLS: Pending Phase 2 request - "
"skip decryption and use old data");
+ /* Clear TLS reassembly state. */
+ free(data->ssl.tls_in);
+ data->ssl.tls_in = NULL;
+ data->ssl.tls_in_len = 0;
+ data->ssl.tls_in_left = 0;
+ data->ssl.tls_in_total = 0;
+
in_decrypted = data->pending_phase2_req;
data->pending_phase2_req = NULL;
len_decrypted = data->pending_phase2_req_len;
diff --git a/contrib/wpa_supplicant/eapol_sm.c b/contrib/wpa_supplicant/eapol_sm.c
index 93f9a54a6c88..1424b7df06d5 100644
--- a/contrib/wpa_supplicant/eapol_sm.c
+++ b/contrib/wpa_supplicant/eapol_sm.c
@@ -194,9 +194,8 @@ static void eapol_port_timers_tick(void *eloop_ctx, void *timeout_ctx)
"heldWhile=%d startWhen=%d idleWhile=%d",
sm->authWhile, sm->heldWhile, sm->startWhen, sm->idleWhile);
- eapol_sm_step(sm);
-
eloop_register_timeout(1, 0, eapol_port_timers_tick, eloop_ctx, sm);
+ eapol_sm_step(sm);
}
diff --git a/contrib/wpa_supplicant/ms_funcs.c b/contrib/wpa_supplicant/ms_funcs.c
index 9c50185ca1d9..590b58949d74 100644
--- a/contrib/wpa_supplicant/ms_funcs.c
+++ b/contrib/wpa_supplicant/ms_funcs.c
@@ -158,12 +158,14 @@ void get_master_key(const u8 *password_hash_hash, const u8 *nt_response,
};
const unsigned char *addr[3];
const size_t len[3] = { 16, 24, sizeof(magic1) };
+ u8 hash[SHA1_MAC_LEN];
addr[0] = password_hash_hash;
addr[1] = nt_response;
addr[2] = magic1;
- sha1_vector(3, addr, len, master_key);
+ sha1_vector(3, addr, len, hash);
+ memcpy(master_key, hash, 16);
}
diff --git a/contrib/wpa_supplicant/radius.c b/contrib/wpa_supplicant/radius.c
new file mode 100644
index 000000000000..5fd323d65c85
--- /dev/null
+++ b/contrib/wpa_supplicant/radius.c
@@ -0,0 +1,1125 @@
+/*
+ * Host AP (software wireless LAN access point) user space daemon for
+ * Host AP kernel driver / RADIUS client
+ * Copyright (c) 2002-2005, Jouni Malinen <jkmaline@cc.hut.fi>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * Alternatively, this software may be distributed under the terms of BSD
+ * license.
+ *
+ * See README and COPYING for more details.
+ */
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <unistd.h>
+#include <netinet/in.h>
+#include <string.h>
+#include <sys/ioctl.h>
+#include <signal.h>
+#include <sys/time.h>
+#include <sys/socket.h>
+#include <arpa/inet.h>
+
+
+#include "common.h"
+#include "radius.h"
+#include "md5.h"
+
+
+struct radius_msg *radius_msg_new(u8 code, u8 identifier)
+{
+ struct radius_msg *msg;
+
+ msg = (struct radius_msg *) malloc(sizeof(*msg));
+ if (msg == NULL)
+ return NULL;
+
+ if (radius_msg_initialize(msg, RADIUS_DEFAULT_MSG_SIZE)) {
+ free(msg);
+ return NULL;
+ }
+
+ radius_msg_set_hdr(msg, code, identifier);
+
+ return msg;
+}
+
+
+int radius_msg_initialize(struct radius_msg *msg, size_t init_len)
+{
+ if (msg == NULL || init_len < sizeof(struct radius_hdr))
+ return -1;
+
+ memset(msg, 0, sizeof(*msg));
+ msg->buf = (unsigned char *) malloc(init_len);
+ if (msg->buf == NULL)
+ return -1;
+ memset(msg->buf, 0, init_len);
+
+ msg->buf_size = init_len;
+ msg->hdr = (struct radius_hdr *) msg->buf;
+ msg->buf_used = sizeof(*msg->hdr);
+
+ msg->attrs = (struct radius_attr_hdr **)
+ malloc(RADIUS_DEFAULT_ATTR_COUNT * sizeof(*msg->attrs));
+ if (msg->attrs == NULL) {
+ free(msg->buf);
+ msg->buf = NULL;
+ msg->hdr = NULL;
+ return -1;
+ }
+
+ msg->attr_size = RADIUS_DEFAULT_ATTR_COUNT;
+ msg->attr_used = 0;
+
+ return 0;
+}
+
+
+void radius_msg_set_hdr(struct radius_msg *msg, u8 code, u8 identifier)
+{
+ msg->hdr->code = code;
+ msg->hdr->identifier = identifier;
+}
+
+
+void radius_msg_free(struct radius_msg *msg)
+{
+ if (msg->buf != NULL) {
+ free(msg->buf);
+ msg->buf = NULL;
+ msg->hdr = NULL;
+ }
+ msg->buf_size = msg->buf_used = 0;
+
+ if (msg->attrs != NULL) {
+ free(msg->attrs);
+ msg->attrs = NULL;
+ }
+ msg->attr_size = msg->attr_used = 0;
+}
+
+
+static const char *radius_code_string(u8 code)
+{
+ switch (code) {
+ case RADIUS_CODE_ACCESS_REQUEST: return "Access-Request";
+ case RADIUS_CODE_ACCESS_ACCEPT: return "Access-Accept";
+ case RADIUS_CODE_ACCESS_REJECT: return "Access-Reject";
+ case RADIUS_CODE_ACCOUNTING_REQUEST: return "Accounting-Request";
+ case RADIUS_CODE_ACCOUNTING_RESPONSE: return "Accounting-Response";
+ case RADIUS_CODE_ACCESS_CHALLENGE: return "Access-Challenge";
+ case RADIUS_CODE_STATUS_SERVER: return "Status-Server";
+ case RADIUS_CODE_STATUS_CLIENT: return "Status-Client";
+ case RADIUS_CODE_RESERVED: return "Reserved";
+ default: return "?Unknown?";
+ }
+}
+
+
+struct radius_attr_type {
+ u8 type;
+ char *name;
+ enum { RADIUS_ATTR_UNDIST, RADIUS_ATTR_TEXT, RADIUS_ATTR_IP,
+ RADIUS_ATTR_HEXDUMP, RADIUS_ATTR_INT32 } data_type;
+};
+
+static struct radius_attr_type radius_attrs[] =
+{
+ { RADIUS_ATTR_USER_NAME, "User-Name", RADIUS_ATTR_TEXT },
+ { RADIUS_ATTR_USER_PASSWORD, "User-Password", RADIUS_ATTR_UNDIST },
+ { RADIUS_ATTR_NAS_IP_ADDRESS, "NAS-IP-Address", RADIUS_ATTR_IP },
+ { RADIUS_ATTR_NAS_PORT, "NAS-Port", RADIUS_ATTR_INT32 },
+ { RADIUS_ATTR_FRAMED_MTU, "Framed-MTU", RADIUS_ATTR_INT32 },
+ { RADIUS_ATTR_STATE, "State", RADIUS_ATTR_UNDIST },
+ { RADIUS_ATTR_CLASS, "Class", RADIUS_ATTR_UNDIST },
+ { RADIUS_ATTR_VENDOR_SPECIFIC, "Vendor-Specific", RADIUS_ATTR_UNDIST },
+ { RADIUS_ATTR_SESSION_TIMEOUT, "Session-Timeout", RADIUS_ATTR_INT32 },
+ { RADIUS_ATTR_IDLE_TIMEOUT, "Idle-Timeout", RADIUS_ATTR_INT32 },
+ { RADIUS_ATTR_TERMINATION_ACTION, "Termination-Action",
+ RADIUS_ATTR_INT32 },
+ { RADIUS_ATTR_CALLED_STATION_ID, "Called-Station-Id",
+ RADIUS_ATTR_TEXT },
+ { RADIUS_ATTR_CALLING_STATION_ID, "Calling-Station-Id",
+ RADIUS_ATTR_TEXT },
+ { RADIUS_ATTR_NAS_IDENTIFIER, "NAS-Identifier", RADIUS_ATTR_TEXT },
+ { RADIUS_ATTR_ACCT_STATUS_TYPE, "Acct-Status-Type",
+ RADIUS_ATTR_INT32 },
+ { RADIUS_ATTR_ACCT_DELAY_TIME, "Acct-Delay-Time", RADIUS_ATTR_INT32 },
+ { RADIUS_ATTR_ACCT_INPUT_OCTETS, "Acct-Input-Octets",
+ RADIUS_ATTR_INT32 },
+ { RADIUS_ATTR_ACCT_OUTPUT_OCTETS, "Acct-Output-Octets",
+ RADIUS_ATTR_INT32 },
+ { RADIUS_ATTR_ACCT_SESSION_ID, "Acct-Session-Id", RADIUS_ATTR_TEXT },
+ { RADIUS_ATTR_ACCT_AUTHENTIC, "Acct-Authentic", RADIUS_ATTR_INT32 },
+ { RADIUS_ATTR_ACCT_SESSION_TIME, "Acct-Session-Time",
+ RADIUS_ATTR_INT32 },
+ { RADIUS_ATTR_ACCT_INPUT_PACKETS, "Acct-Input-Packets",
+ RADIUS_ATTR_INT32 },
+ { RADIUS_ATTR_ACCT_OUTPUT_PACKETS, "Acct-Output-Packets",
+ RADIUS_ATTR_INT32 },
+ { RADIUS_ATTR_ACCT_TERMINATE_CAUSE, "Acct-Terminate-Cause",
+ RADIUS_ATTR_INT32 },
+ { RADIUS_ATTR_ACCT_MULTI_SESSION_ID, "Acct-Multi-Session-Id",
+ RADIUS_ATTR_TEXT },
+ { RADIUS_ATTR_ACCT_LINK_COUNT, "Acct-Link-Count", RADIUS_ATTR_INT32 },
+ { RADIUS_ATTR_ACCT_INPUT_GIGAWORDS, "Acct-Input-Gigawords",
+ RADIUS_ATTR_INT32 },
+ { RADIUS_ATTR_ACCT_OUTPUT_GIGAWORDS, "Acct-Output-Gigawords",
+ RADIUS_ATTR_INT32 },
+ { RADIUS_ATTR_EVENT_TIMESTAMP, "Event-Timestamp",
+ RADIUS_ATTR_INT32 },
+ { RADIUS_ATTR_NAS_PORT_TYPE, "NAS-Port-Type", RADIUS_ATTR_INT32 },
+ { RADIUS_ATTR_CONNECT_INFO, "Connect-Info", RADIUS_ATTR_TEXT },
+ { RADIUS_ATTR_EAP_MESSAGE, "EAP-Message", RADIUS_ATTR_UNDIST },
+ { RADIUS_ATTR_MESSAGE_AUTHENTICATOR, "Message-Authenticator",
+ RADIUS_ATTR_UNDIST },
+ { RADIUS_ATTR_ACCT_INTERIM_INTERVAL, "Acct-Interim-Interval",
+ RADIUS_ATTR_INT32 }
+
+};
+#define RADIUS_ATTRS (sizeof(radius_attrs) / sizeof(radius_attrs[0]))
+
+
+static struct radius_attr_type *radius_get_attr_type(u8 type)
+{
+ int i;
+
+ for (i = 0; i < RADIUS_ATTRS; i++) {
+ if (type == radius_attrs[i].type)
+ return &radius_attrs[i];
+ }
+
+ return NULL;
+}
+
+
+static void radius_msg_dump_attr(struct radius_attr_hdr *hdr)
+{
+ struct radius_attr_type *attr;
+ int i, len;
+ unsigned char *pos;
+
+ attr = radius_get_attr_type(hdr->type);
+
+ printf(" Attribute %d (%s) length=%d\n",
+ hdr->type, attr ? attr->name : "?Unknown?", hdr->length);
+
+ if (attr == NULL)
+ return;
+
+ len = hdr->length - sizeof(struct radius_attr_hdr);
+ pos = (unsigned char *) (hdr + 1);
+
+ switch (attr->data_type) {
+ case RADIUS_ATTR_TEXT:
+ printf(" Value: '");
+ for (i = 0; i < len; i++)
+ print_char(pos[i]);
+ printf("'\n");
+ break;
+
+ case RADIUS_ATTR_IP:
+ if (len == 4) {
+ struct in_addr *addr = (struct in_addr *) pos;
+ printf(" Value: %s\n", inet_ntoa(*addr));
+ } else
+ printf(" Invalid IP address length %d\n", len);
+ break;
+
+ case RADIUS_ATTR_HEXDUMP:
+ case RADIUS_ATTR_UNDIST:
+ printf(" Value:");
+ for (i = 0; i < len; i++)
+ printf(" %02x", pos[i]);
+ printf("\n");
+ break;
+
+ case RADIUS_ATTR_INT32:
+ if (len == 4) {
+ u32 *val = (u32 *) pos;
+ printf(" Value: %d\n", ntohl(*val));
+ } else
+ printf(" Invalid INT32 length %d\n", len);
+ break;
+
+ default:
+ break;
+ }
+}
+
+
+void radius_msg_dump(struct radius_msg *msg)
+{
+ int i;
+
+ printf("RADIUS message: code=%d (%s) identifier=%d length=%d\n",
+ msg->hdr->code, radius_code_string(msg->hdr->code),
+ msg->hdr->identifier, ntohs(msg->hdr->length));
+
+ for (i = 0; i < msg->attr_used; i++) {
+ radius_msg_dump_attr(msg->attrs[i]);
+ }
+}
+
+
+int radius_msg_finish(struct radius_msg *msg, u8 *secret, size_t secret_len)
+{
+ if (secret) {
+ u8 auth[MD5_MAC_LEN];
+ struct radius_attr_hdr *attr;
+
+ memset(auth, 0, MD5_MAC_LEN);
+ attr = radius_msg_add_attr(msg,
+ RADIUS_ATTR_MESSAGE_AUTHENTICATOR,
+ auth, MD5_MAC_LEN);
+ if (attr == NULL) {
+ printf("WARNING: Could not add "
+ "Message-Authenticator\n");
+ return -1;
+ }
+ msg->hdr->length = htons(msg->buf_used);
+ hmac_md5(secret, secret_len, msg->buf, msg->buf_used,
+ (u8 *) (attr + 1));
+ } else
+ msg->hdr->length = htons(msg->buf_used);
+
+ if (msg->buf_used > 0xffff) {
+ printf("WARNING: too long RADIUS message (%lu)\n",
+ (unsigned long) msg->buf_used);
+ return -1;
+ }
+ return 0;
+}
+
+
+int radius_msg_finish_srv(struct radius_msg *msg, const u8 *secret,
+ size_t secret_len, const u8 *req_authenticator)
+{
+ u8 auth[MD5_MAC_LEN];
+ struct radius_attr_hdr *attr;
+ MD5_CTX context;
+
+ memset(auth, 0, MD5_MAC_LEN);
+ attr = radius_msg_add_attr(msg, RADIUS_ATTR_MESSAGE_AUTHENTICATOR,
+ auth, MD5_MAC_LEN);
+ if (attr == NULL) {
+ printf("WARNING: Could not add Message-Authenticator\n");
+ return -1;
+ }
+ msg->hdr->length = htons(msg->buf_used);
+ memcpy(msg->hdr->authenticator, req_authenticator,
+ sizeof(msg->hdr->authenticator));
+ hmac_md5(secret, secret_len, msg->buf, msg->buf_used,
+ (u8 *) (attr + 1));
+
+ /* ResponseAuth = MD5(Code+ID+Length+RequestAuth+Attributes+Secret) */
+ MD5Init(&context);
+ MD5Update(&context, (u8 *) msg->hdr, 1 + 1 + 2);
+ MD5Update(&context, req_authenticator, MD5_MAC_LEN);
+ MD5Update(&context, (u8 *) (msg->hdr + 1),
+ msg->buf_used - sizeof(*msg->hdr));
+ MD5Update(&context, secret, secret_len);
+ MD5Final(msg->hdr->authenticator, &context);
+
+ if (msg->buf_used > 0xffff) {
+ printf("WARNING: too long RADIUS message (%lu)\n",
+ (unsigned long) msg->buf_used);
+ return -1;
+ }
+ return 0;
+}
+
+
+void radius_msg_finish_acct(struct radius_msg *msg, u8 *secret,
+ size_t secret_len)
+{
+ MD5_CTX context;
+
+ msg->hdr->length = htons(msg->buf_used);
+ memset(msg->hdr->authenticator, 0, MD5_MAC_LEN);
+ MD5Init(&context);
+ MD5Update(&context, msg->buf, msg->buf_used);
+ MD5Update(&context, secret, secret_len);
+ MD5Final(msg->hdr->authenticator, &context);
+
+ if (msg->buf_used > 0xffff) {
+ printf("WARNING: too long RADIUS messages (%lu)\n",
+ (unsigned long) msg->buf_used);
+ }
+}
+
+
+static int radius_msg_add_attr_to_array(struct radius_msg *msg,
+ struct radius_attr_hdr *attr)
+{
+ if (msg->attr_used >= msg->attr_size) {
+ struct radius_attr_hdr **nattrs;
+ int nlen = msg->attr_size * 2;
+
+ nattrs = (struct radius_attr_hdr **)
+ realloc(msg->attrs, nlen * sizeof(*msg->attrs));
+
+ if (nattrs == NULL)
+ return -1;
+
+ msg->attrs = nattrs;
+ msg->attr_size = nlen;
+ }
+
+ msg->attrs[msg->attr_used++] = attr;
+
+ return 0;
+}
+
+
+struct radius_attr_hdr *radius_msg_add_attr(struct radius_msg *msg, u8 type,
+ u8 *data, size_t data_len)
+{
+ size_t buf_needed;
+ struct radius_attr_hdr *attr;
+
+ if (data_len > RADIUS_MAX_ATTR_LEN) {
+ printf("radius_msg_add_attr: too long attribute (%lu bytes)\n",
+ (unsigned long) data_len);
+ return NULL;
+ }
+
+ buf_needed = msg->buf_used + sizeof(*attr) + data_len;
+
+ if (msg->buf_size < buf_needed) {
+ /* allocate more space for message buffer */
+ unsigned char *nbuf;
+ int nlen = msg->buf_size;
+ int diff, i;
+
+ while (nlen < buf_needed)
+ nlen *= 2;
+ nbuf = (unsigned char *) realloc(msg->buf, nlen);
+ if (nbuf == NULL)
+ return NULL;
+ diff = nbuf - msg->buf;
+ msg->buf = nbuf;
+ msg->hdr = (struct radius_hdr *) msg->buf;
+ /* adjust attr pointers to match with the new buffer */
+ for (i = 0; i < msg->attr_used; i++)
+ msg->attrs[i] = (struct radius_attr_hdr *)
+ (((u8 *) msg->attrs[i]) + diff);
+ memset(msg->buf + msg->buf_size, 0, nlen - msg->buf_size);
+ msg->buf_size = nlen;
+ }
+
+ attr = (struct radius_attr_hdr *) (msg->buf + msg->buf_used);
+ attr->type = type;
+ attr->length = sizeof(*attr) + data_len;
+ if (data_len > 0)
+ memcpy(attr + 1, data, data_len);
+
+ msg->buf_used += sizeof(*attr) + data_len;
+
+ if (radius_msg_add_attr_to_array(msg, attr))
+ return NULL;
+
+ return attr;
+}
+
+
+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) {
+ printf("Invalid RADIUS message length\n");
+ return NULL;
+ }
+
+ if (msg_len < len) {
+ printf("Ignored %lu extra bytes after RADIUS message\n",
+ (unsigned long) 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;
+}
+
+
+int radius_msg_add_eap(struct radius_msg *msg, u8 *data, size_t data_len)
+{
+ u8 *pos = data;
+ size_t left = data_len;
+
+ while (left > 0) {
+ int len;
+ if (left > RADIUS_MAX_ATTR_LEN)
+ len = RADIUS_MAX_ATTR_LEN;
+ else
+ len = left;
+
+ if (!radius_msg_add_attr(msg, RADIUS_ATTR_EAP_MESSAGE,
+ pos, len))
+ return 0;
+
+ pos += len;
+ left -= len;
+ }
+
+ return 1;
+}
+
+
+u8 *radius_msg_get_eap(struct radius_msg *msg, size_t *eap_len)
+{
+ u8 *eap, *pos;
+ size_t len;
+ int i;
+
+ if (msg == NULL)
+ return NULL;
+
+ len = 0;
+ for (i = 0; i < msg->attr_used; i++) {
+ if (msg->attrs[i]->type == RADIUS_ATTR_EAP_MESSAGE)
+ len += msg->attrs[i]->length -
+ sizeof(struct radius_attr_hdr);
+ }
+
+ if (len == 0)
+ return NULL;
+
+ eap = malloc(len);
+ if (eap == NULL)
+ return NULL;
+
+ pos = eap;
+ for (i = 0; i < msg->attr_used; i++) {
+ if (msg->attrs[i]->type == RADIUS_ATTR_EAP_MESSAGE) {
+ struct radius_attr_hdr *attr = msg->attrs[i];
+ int flen = attr->length - sizeof(*attr);
+ memcpy(pos, attr + 1, flen);
+ pos += flen;
+ }
+ }
+
+ if (eap_len)
+ *eap_len = len;
+
+ return eap;
+}
+
+
+int radius_msg_verify_msg_auth(struct radius_msg *msg, const u8 *secret,
+ size_t secret_len, const u8 *req_auth)
+{
+ u8 auth[MD5_MAC_LEN], orig[MD5_MAC_LEN];
+ u8 orig_authenticator[16];
+ struct radius_attr_hdr *attr = NULL;
+ int i;
+
+ for (i = 0; i < msg->attr_used; i++) {
+ if (msg->attrs[i]->type == RADIUS_ATTR_MESSAGE_AUTHENTICATOR) {
+ if (attr != NULL) {
+ printf("Multiple Message-Authenticator "
+ "attributes in RADIUS message\n");
+ return 1;
+ }
+ attr = msg->attrs[i];
+ }
+ }
+
+ if (attr == NULL) {
+ printf("No Message-Authenticator attribute found\n");
+ return 1;
+ }
+
+ memcpy(orig, attr + 1, MD5_MAC_LEN);
+ memset(attr + 1, 0, MD5_MAC_LEN);
+ if (req_auth) {
+ memcpy(orig_authenticator, msg->hdr->authenticator,
+ sizeof(orig_authenticator));
+ memcpy(msg->hdr->authenticator, req_auth,
+ sizeof(msg->hdr->authenticator));
+ }
+ hmac_md5(secret, secret_len, msg->buf, msg->buf_used, auth);
+ memcpy(attr + 1, orig, MD5_MAC_LEN);
+ if (req_auth) {
+ memcpy(msg->hdr->authenticator, orig_authenticator,
+ sizeof(orig_authenticator));
+ }
+
+ if (memcmp(orig, auth, MD5_MAC_LEN) != 0) {
+ printf("Invalid Message-Authenticator!\n");
+ return 1;
+ }
+
+ return 0;
+}
+
+
+int radius_msg_verify(struct radius_msg *msg, u8 *secret, size_t secret_len,
+ struct radius_msg *sent_msg)
+{
+ MD5_CTX context;
+ u8 hash[MD5_MAC_LEN];
+
+ if (sent_msg == NULL) {
+ printf("No matching Access-Request message found\n");
+ return 1;
+ }
+
+ if (radius_msg_verify_msg_auth(msg, secret, secret_len,
+ sent_msg->hdr->authenticator)) {
+ return 1;
+ }
+
+ /* ResponseAuth = MD5(Code+ID+Length+RequestAuth+Attributes+Secret) */
+ MD5Init(&context);
+ MD5Update(&context, (u8 *) msg->hdr, 1 + 1 + 2);
+ MD5Update(&context, sent_msg->hdr->authenticator, MD5_MAC_LEN);
+ MD5Update(&context, (u8 *) (msg->hdr + 1),
+ msg->buf_used - sizeof(*msg->hdr));
+ MD5Update(&context, secret, secret_len);
+ MD5Final(hash, &context);
+ if (memcmp(hash, msg->hdr->authenticator, MD5_MAC_LEN) != 0) {
+ printf("Response Authenticator invalid!\n");
+ return 1;
+ }
+
+ return 0;
+
+}
+
+
+int radius_msg_verify_acct(struct radius_msg *msg, u8 *secret,
+ size_t secret_len, struct radius_msg *sent_msg)
+{
+ MD5_CTX context;
+ u8 hash[MD5_MAC_LEN];
+
+ MD5Init(&context);
+ MD5Update(&context, msg->buf, 4);
+ MD5Update(&context, sent_msg->hdr->authenticator, MD5_MAC_LEN);
+ if (msg->buf_used > sizeof(struct radius_hdr))
+ MD5Update(&context, msg->buf + sizeof(struct radius_hdr),
+ msg->buf_used - sizeof(struct radius_hdr));
+ MD5Update(&context, secret, secret_len);
+ MD5Final(hash, &context);
+ if (memcmp(hash, msg->hdr->authenticator, MD5_MAC_LEN) != 0) {
+ printf("Response Authenticator invalid!\n");
+ return 1;
+ }
+
+ return 0;
+}
+
+
+int radius_msg_copy_attr(struct radius_msg *dst, struct radius_msg *src,
+ u8 type)
+{
+ struct radius_attr_hdr *attr = NULL;
+ int i;
+
+ for (i = 0; i < src->attr_used; i++) {
+ if (src->attrs[i]->type == type) {
+ attr = src->attrs[i];
+ break;
+ }
+ }
+
+ if (attr == NULL)
+ return 0;
+
+ if (!radius_msg_add_attr(dst, type, (u8 *) (attr + 1),
+ attr->length - sizeof(*attr)))
+ return -1;
+
+ return 1;
+}
+
+
+/* Create Request Authenticator. The value should be unique over the lifetime
+ * of the shared secret between authenticator and authentication server.
+ * Use one-way MD5 hash calculated from current timestamp and some data given
+ * by the caller. */
+void radius_msg_make_authenticator(struct radius_msg *msg,
+ u8 *data, size_t len)
+{
+ struct timeval tv;
+ MD5_CTX context;
+ long int l;
+
+ gettimeofday(&tv, NULL);
+ l = random();
+ MD5Init(&context);
+ MD5Update(&context, (u8 *) &tv, sizeof(tv));
+ MD5Update(&context, data, len);
+ MD5Update(&context, (u8 *) &l, sizeof(l));
+ MD5Final(msg->hdr->authenticator, &context);
+}
+
+
+/* Get Vendor-specific RADIUS Attribute from a parsed RADIUS message.
+ * Returns the Attribute payload and sets alen to indicate the length of the
+ * payload if a vendor attribute with subtype is found, otherwise returns NULL.
+ * The returned payload is allocated with malloc() and caller must free it.
+ */
+static u8 *radius_msg_get_vendor_attr(struct radius_msg *msg, u32 vendor,
+ u8 subtype, size_t *alen)
+{
+ u8 *data, *pos;
+ int i;
+ size_t len;
+
+ if (msg == NULL)
+ return NULL;
+
+ for (i = 0; i < msg->attr_used; i++) {
+ struct radius_attr_hdr *attr = msg->attrs[i];
+ int left;
+ u32 vendor_id;
+ struct radius_attr_vendor *vhdr;
+
+ if (attr->type != RADIUS_ATTR_VENDOR_SPECIFIC)
+ continue;
+
+ left = attr->length - sizeof(*attr);
+ if (left < 4)
+ continue;
+
+ pos = (u8 *) (attr + 1);
+
+ memcpy(&vendor_id, pos, 4);
+ pos += 4;
+ left -= 4;
+
+ if (ntohl(vendor_id) != vendor)
+ continue;
+
+ while (left >= sizeof(*vhdr)) {
+ vhdr = (struct radius_attr_vendor *) pos;
+ if (vhdr->vendor_length > left ||
+ vhdr->vendor_length < sizeof(*vhdr)) {
+ left = 0;
+ break;
+ }
+ if (vhdr->vendor_type != subtype) {
+ pos += vhdr->vendor_length;
+ left -= vhdr->vendor_length;
+ continue;
+ }
+
+ len = vhdr->vendor_length - sizeof(*vhdr);
+ data = malloc(len);
+ if (data == NULL)
+ return NULL;
+ memcpy(data, pos + sizeof(*vhdr), len);
+ if (alen)
+ *alen = len;
+ return data;
+ }
+ }
+
+ return NULL;
+}
+
+
+static u8 * decrypt_ms_key(const u8 *key, size_t len,
+ const u8 *req_authenticator,
+ const u8 *secret, size_t secret_len, size_t *reslen)
+{
+ u8 *plain, *ppos, *res;
+ const u8 *pos;
+ size_t left, plen;
+ u8 hash[MD5_MAC_LEN];
+ MD5_CTX context;
+ int i, first = 1;
+
+ /* key: 16-bit salt followed by encrypted key info */
+
+ if (len < 2 + 16)
+ return NULL;
+
+ pos = key + 2;
+ left = len - 2;
+ if (left % 16) {
+ printf("Invalid ms key len %lu\n", (unsigned long) left);
+ return NULL;
+ }
+
+ plen = left;
+ ppos = plain = malloc(plen);
+ if (plain == NULL)
+ return NULL;
+
+ while (left > 0) {
+ /* b(1) = MD5(Secret + Request-Authenticator + Salt)
+ * b(i) = MD5(Secret + c(i - 1)) for i > 1 */
+
+ MD5Init(&context);
+ MD5Update(&context, secret, secret_len);
+ if (first) {
+ MD5Update(&context, req_authenticator, MD5_MAC_LEN);
+ MD5Update(&context, key, 2); /* Salt */
+ first = 0;
+ } else
+ MD5Update(&context, pos - MD5_MAC_LEN, MD5_MAC_LEN);
+ MD5Final(hash, &context);
+
+ for (i = 0; i < MD5_MAC_LEN; i++)
+ *ppos++ = *pos++ ^ hash[i];
+ left -= MD5_MAC_LEN;
+ }
+
+ if (plain[0] > plen - 1) {
+ printf("Failed to decrypt MPPE key\n");
+ free(plain);
+ return NULL;
+ }
+
+ res = malloc(plain[0]);
+ if (res == NULL) {
+ free(plain);
+ return NULL;
+ }
+ memcpy(res, plain + 1, plain[0]);
+ if (reslen)
+ *reslen = plain[0];
+ free(plain);
+ return res;
+}
+
+
+static void encrypt_ms_key(const u8 *key, size_t key_len, u16 salt,
+ const u8 *req_authenticator,
+ const u8 *secret, size_t secret_len,
+ u8 *ebuf, size_t *elen)
+{
+ int i, len, first = 1;
+ u8 hash[MD5_MAC_LEN], saltbuf[2], *pos;
+ MD5_CTX context;
+
+ saltbuf[0] = salt >> 8;
+ saltbuf[1] = salt;
+
+ len = 1 + key_len;
+ if (len & 0x0f) {
+ len = (len & 0xf0) + 16;
+ }
+ memset(ebuf, 0, len);
+ ebuf[0] = key_len;
+ memcpy(ebuf + 1, key, key_len);
+
+ *elen = len;
+
+ pos = ebuf;
+ while (len > 0) {
+ /* b(1) = MD5(Secret + Request-Authenticator + Salt)
+ * b(i) = MD5(Secret + c(i - 1)) for i > 1 */
+ MD5Init(&context);
+ MD5Update(&context, secret, secret_len);
+ if (first) {
+ MD5Update(&context, req_authenticator, MD5_MAC_LEN);
+ MD5Update(&context, saltbuf, sizeof(saltbuf));
+ first = 0;
+ } else {
+ MD5Update(&context, pos - MD5_MAC_LEN, MD5_MAC_LEN);
+ }
+ MD5Final(hash, &context);
+
+ for (i = 0; i < MD5_MAC_LEN; i++)
+ *pos++ ^= hash[i];
+
+ len -= MD5_MAC_LEN;
+ }
+}
+
+
+struct radius_ms_mppe_keys *
+radius_msg_get_ms_keys(struct radius_msg *msg, struct radius_msg *sent_msg,
+ u8 *secret, size_t secret_len)
+{
+ u8 *key;
+ size_t keylen;
+ struct radius_ms_mppe_keys *keys;
+
+ if (msg == NULL || sent_msg == NULL)
+ return NULL;
+
+ keys = (struct radius_ms_mppe_keys *) malloc(sizeof(*keys));
+ if (keys == NULL)
+ return NULL;
+
+ memset(keys, 0, sizeof(*keys));
+
+ key = radius_msg_get_vendor_attr(msg, RADIUS_VENDOR_ID_MICROSOFT,
+ RADIUS_VENDOR_ATTR_MS_MPPE_SEND_KEY,
+ &keylen);
+ if (key) {
+ keys->send = decrypt_ms_key(key, keylen,
+ sent_msg->hdr->authenticator,
+ secret, secret_len,
+ &keys->send_len);
+ free(key);
+ }
+
+ key = radius_msg_get_vendor_attr(msg, RADIUS_VENDOR_ID_MICROSOFT,
+ RADIUS_VENDOR_ATTR_MS_MPPE_RECV_KEY,
+ &keylen);
+ if (key) {
+ keys->recv = decrypt_ms_key(key, keylen,
+ sent_msg->hdr->authenticator,
+ secret, secret_len,
+ &keys->recv_len);
+ free(key);
+ }
+
+ return keys;
+}
+
+
+struct radius_ms_mppe_keys *
+radius_msg_get_cisco_keys(struct radius_msg *msg, struct radius_msg *sent_msg,
+ u8 *secret, size_t secret_len)
+{
+ u8 *key;
+ size_t keylen;
+ struct radius_ms_mppe_keys *keys;
+
+ if (msg == NULL || sent_msg == NULL)
+ return NULL;
+
+ keys = (struct radius_ms_mppe_keys *) malloc(sizeof(*keys));
+ if (keys == NULL)
+ return NULL;
+
+ memset(keys, 0, sizeof(*keys));
+
+ key = radius_msg_get_vendor_attr(msg, RADIUS_VENDOR_ID_CISCO,
+ RADIUS_CISCO_AV_PAIR, &keylen);
+ if (key && keylen == 51 && memcmp(key, "leap:session-key=", 17) == 0) {
+ keys->recv = decrypt_ms_key(key + 17, keylen - 17,
+ sent_msg->hdr->authenticator,
+ secret, secret_len,
+ &keys->recv_len);
+ free(key);
+ }
+
+ return keys;
+}
+
+
+int radius_msg_add_mppe_keys(struct radius_msg *msg,
+ const u8 *req_authenticator,
+ const u8 *secret, size_t secret_len,
+ const u8 *send_key, size_t send_key_len,
+ const u8 *recv_key, size_t recv_key_len)
+{
+ struct radius_attr_hdr *attr;
+ u32 vendor_id = htonl(RADIUS_VENDOR_ID_MICROSOFT);
+ u8 *buf;
+ struct radius_attr_vendor *vhdr;
+ u8 *pos;
+ size_t elen;
+ int hlen;
+ u16 salt;
+
+ hlen = sizeof(vendor_id) + sizeof(*vhdr) + 2;
+
+ /* MS-MPPE-Send-Key */
+ buf = malloc(hlen + send_key_len + 16);
+ if (buf == NULL) {
+ return 0;
+ }
+ pos = buf;
+ memcpy(pos, &vendor_id, sizeof(vendor_id));
+ pos += sizeof(vendor_id);
+ vhdr = (struct radius_attr_vendor *) pos;
+ vhdr->vendor_type = RADIUS_VENDOR_ATTR_MS_MPPE_SEND_KEY;
+ pos = (u8 *) (vhdr + 1);
+ salt = random() | 0x8000;
+ *pos++ = salt >> 8;
+ *pos++ = salt;
+ encrypt_ms_key(send_key, send_key_len, salt, req_authenticator, secret,
+ secret_len, pos, &elen);
+ vhdr->vendor_length = hlen + elen - sizeof(vendor_id);
+
+ attr = radius_msg_add_attr(msg, RADIUS_ATTR_VENDOR_SPECIFIC,
+ buf, hlen + elen);
+ free(buf);
+ if (attr == NULL) {
+ return 0;
+ }
+
+ /* MS-MPPE-Recv-Key */
+ buf = malloc(hlen + send_key_len + 16);
+ if (buf == NULL) {
+ return 0;
+ }
+ pos = buf;
+ memcpy(pos, &vendor_id, sizeof(vendor_id));
+ pos += sizeof(vendor_id);
+ vhdr = (struct radius_attr_vendor *) pos;
+ vhdr->vendor_type = RADIUS_VENDOR_ATTR_MS_MPPE_RECV_KEY;
+ pos = (u8 *) (vhdr + 1);
+ salt ^= 1;
+ *pos++ = salt >> 8;
+ *pos++ = salt;
+ encrypt_ms_key(recv_key, recv_key_len, salt, req_authenticator, secret,
+ secret_len, pos, &elen);
+ vhdr->vendor_length = hlen + elen - sizeof(vendor_id);
+
+ attr = radius_msg_add_attr(msg, RADIUS_ATTR_VENDOR_SPECIFIC,
+ buf, hlen + elen);
+ free(buf);
+ if (attr == NULL) {
+ return 0;
+ }
+
+ return 1;
+}
+
+
+/* Add User-Password attribute to a RADIUS message and encrypt it as specified
+ * in RFC 2865, Chap. 5.2 */
+struct radius_attr_hdr *
+radius_msg_add_attr_user_password(struct radius_msg *msg,
+ u8 *data, size_t data_len,
+ u8 *secret, size_t secret_len)
+{
+ u8 buf[128];
+ int padlen, i, pos;
+ MD5_CTX context;
+ size_t buf_len;
+ u8 hash[16];
+
+ if (data_len > 128)
+ return NULL;
+
+ memcpy(buf, data, data_len);
+ buf_len = data_len;
+
+ padlen = data_len % 16;
+ if (padlen) {
+ padlen = 16 - padlen;
+ memset(buf + data_len, 0, padlen);
+ buf_len += padlen;
+ }
+
+ MD5Init(&context);
+ MD5Update(&context, secret, secret_len);
+ MD5Update(&context, msg->hdr->authenticator, 16);
+ MD5Final(hash, &context);
+
+ for (i = 0; i < 16; i++)
+ buf[i] ^= hash[i];
+ pos = 16;
+
+ while (pos < buf_len) {
+ MD5Init(&context);
+ MD5Update(&context, secret, secret_len);
+ MD5Update(&context, &buf[pos - 16], 16);
+ MD5Final(hash, &context);
+
+ for (i = 0; i < 16; i++)
+ buf[pos + i] ^= hash[i];
+
+ pos += 16;
+ }
+
+ return radius_msg_add_attr(msg, RADIUS_ATTR_USER_PASSWORD,
+ buf, buf_len);
+}
+
+
+int radius_msg_get_attr(struct radius_msg *msg, u8 type, u8 *buf, size_t len)
+{
+ int i;
+ struct radius_attr_hdr *attr = NULL;
+ size_t dlen;
+
+ for (i = 0; i < msg->attr_used; i++) {
+ if (msg->attrs[i]->type == type) {
+ attr = msg->attrs[i];
+ break;
+ }
+ }
+
+ if (!attr)
+ return -1;
+
+ dlen = attr->length - sizeof(*attr);
+ if (buf)
+ memcpy(buf, (attr + 1), dlen > len ? len : dlen);
+ return dlen;
+}
+
+
+int radius_msg_get_attr_ptr(struct radius_msg *msg, u8 type, u8 **buf,
+ size_t *len)
+{
+ int i;
+ struct radius_attr_hdr *attr = NULL;
+
+ for (i = 0; i < msg->attr_used; i++) {
+ if (msg->attrs[i]->type == type) {
+ attr = msg->attrs[i];
+ break;
+ }
+ }
+
+ if (!attr)
+ return -1;
+
+ *buf = (u8 *) (attr + 1);
+ *len = attr->length - sizeof(*attr);
+ return 0;
+}
diff --git a/contrib/wpa_supplicant/radius.h b/contrib/wpa_supplicant/radius.h
new file mode 100644
index 000000000000..318e0adecf24
--- /dev/null
+++ b/contrib/wpa_supplicant/radius.h
@@ -0,0 +1,224 @@
+#ifndef RADIUS_H
+#define RADIUS_H
+
+/* RFC 2865 - RADIUS */
+
+struct radius_hdr {
+ u8 code;
+ u8 identifier;
+ u16 length; /* including this header */
+ u8 authenticator[16];
+ /* followed by length-20 octets of attributes */
+} __attribute__ ((packed));
+
+enum { RADIUS_CODE_ACCESS_REQUEST = 1,
+ RADIUS_CODE_ACCESS_ACCEPT = 2,
+ RADIUS_CODE_ACCESS_REJECT = 3,
+ RADIUS_CODE_ACCOUNTING_REQUEST = 4,
+ RADIUS_CODE_ACCOUNTING_RESPONSE = 5,
+ RADIUS_CODE_ACCESS_CHALLENGE = 11,
+ RADIUS_CODE_STATUS_SERVER = 12,
+ RADIUS_CODE_STATUS_CLIENT = 13,
+ RADIUS_CODE_RESERVED = 255
+};
+
+struct radius_attr_hdr {
+ u8 type;
+ u8 length; /* including this header */
+ /* followed by length-2 octets of attribute value */
+} __attribute__ ((packed));
+
+#define RADIUS_MAX_ATTR_LEN (255 - sizeof(struct radius_attr_hdr))
+
+enum { RADIUS_ATTR_USER_NAME = 1,
+ RADIUS_ATTR_USER_PASSWORD = 2,
+ RADIUS_ATTR_NAS_IP_ADDRESS = 4,
+ RADIUS_ATTR_NAS_PORT = 5,
+ RADIUS_ATTR_FRAMED_MTU = 12,
+ RADIUS_ATTR_STATE = 24,
+ RADIUS_ATTR_CLASS = 25,
+ RADIUS_ATTR_VENDOR_SPECIFIC = 26,
+ RADIUS_ATTR_SESSION_TIMEOUT = 27,
+ RADIUS_ATTR_IDLE_TIMEOUT = 28,
+ RADIUS_ATTR_TERMINATION_ACTION = 29,
+ RADIUS_ATTR_CALLED_STATION_ID = 30,
+ RADIUS_ATTR_CALLING_STATION_ID = 31,
+ RADIUS_ATTR_NAS_IDENTIFIER = 32,
+ RADIUS_ATTR_ACCT_STATUS_TYPE = 40,
+ RADIUS_ATTR_ACCT_DELAY_TIME = 41,
+ RADIUS_ATTR_ACCT_INPUT_OCTETS = 42,
+ RADIUS_ATTR_ACCT_OUTPUT_OCTETS = 43,
+ RADIUS_ATTR_ACCT_SESSION_ID = 44,
+ RADIUS_ATTR_ACCT_AUTHENTIC = 45,
+ RADIUS_ATTR_ACCT_SESSION_TIME = 46,
+ RADIUS_ATTR_ACCT_INPUT_PACKETS = 47,
+ RADIUS_ATTR_ACCT_OUTPUT_PACKETS = 48,
+ RADIUS_ATTR_ACCT_TERMINATE_CAUSE = 49,
+ RADIUS_ATTR_ACCT_MULTI_SESSION_ID = 50,
+ RADIUS_ATTR_ACCT_LINK_COUNT = 51,
+ RADIUS_ATTR_ACCT_INPUT_GIGAWORDS = 52,
+ RADIUS_ATTR_ACCT_OUTPUT_GIGAWORDS = 53,
+ RADIUS_ATTR_EVENT_TIMESTAMP = 55,
+ RADIUS_ATTR_NAS_PORT_TYPE = 61,
+ RADIUS_ATTR_CONNECT_INFO = 77,
+ RADIUS_ATTR_EAP_MESSAGE = 79,
+ RADIUS_ATTR_MESSAGE_AUTHENTICATOR = 80,
+ RADIUS_ATTR_ACCT_INTERIM_INTERVAL = 85
+};
+
+
+/* Termination-Action */
+#define RADIUS_TERMINATION_ACTION_DEFAULT 0
+#define RADIUS_TERMINATION_ACTION_RADIUS_REQUEST 1
+
+/* NAS-Port-Type */
+#define RADIUS_NAS_PORT_TYPE_IEEE_802_11 19
+
+/* Acct-Status-Type */
+#define RADIUS_ACCT_STATUS_TYPE_START 1
+#define RADIUS_ACCT_STATUS_TYPE_STOP 2
+#define RADIUS_ACCT_STATUS_TYPE_INTERIM_UPDATE 3
+#define RADIUS_ACCT_STATUS_TYPE_ACCOUNTING_ON 7
+#define RADIUS_ACCT_STATUS_TYPE_ACCOUNTING_OFF 8
+
+/* Acct-Authentic */
+#define RADIUS_ACCT_AUTHENTIC_RADIUS 1
+#define RADIUS_ACCT_AUTHENTIC_LOCAL 2
+#define RADIUS_ACCT_AUTHENTIC_REMOTE 3
+
+/* Acct-Terminate-Cause */
+#define RADIUS_ACCT_TERMINATE_CAUSE_USER_REQUEST 1
+#define RADIUS_ACCT_TERMINATE_CAUSE_LOST_CARRIER 2
+#define RADIUS_ACCT_TERMINATE_CAUSE_LOST_SERVICE 3
+#define RADIUS_ACCT_TERMINATE_CAUSE_IDLE_TIMEOUT 4
+#define RADIUS_ACCT_TERMINATE_CAUSE_SESSION_TIMEOUT 5
+#define RADIUS_ACCT_TERMINATE_CAUSE_ADMIN_RESET 6
+#define RADIUS_ACCT_TERMINATE_CAUSE_ADMIN_REBOOT 7
+#define RADIUS_ACCT_TERMINATE_CAUSE_PORT_ERROR 8
+#define RADIUS_ACCT_TERMINATE_CAUSE_NAS_ERROR 9
+#define RADIUS_ACCT_TERMINATE_CAUSE_NAS_REQUEST 10
+#define RADIUS_ACCT_TERMINATE_CAUSE_NAS_REBOOT 11
+#define RADIUS_ACCT_TERMINATE_CAUSE_PORT_UNNEEDED 12
+#define RADIUS_ACCT_TERMINATE_CAUSE_PORT_PREEMPTED 13
+#define RADIUS_ACCT_TERMINATE_CAUSE_PORT_SUSPENDED 14
+#define RADIUS_ACCT_TERMINATE_CAUSE_SERVICE_UNAVAILABLE 15
+#define RADIUS_ACCT_TERMINATE_CAUSE_CALLBACK 16
+#define RADIUS_ACCT_TERMINATE_CAUSE_USER_ERROR 17
+#define RADIUS_ACCT_TERMINATE_CAUSE_HOST_REQUEST 18
+
+
+struct radius_attr_vendor {
+ u8 vendor_type;
+ u8 vendor_length;
+} __attribute__ ((packed));
+
+#define RADIUS_VENDOR_ID_CISCO 9
+#define RADIUS_CISCO_AV_PAIR 1
+
+/* RFC 2548 - Microsoft Vendor-specific RADIUS Attributes */
+#define RADIUS_VENDOR_ID_MICROSOFT 311
+
+enum { RADIUS_VENDOR_ATTR_MS_MPPE_SEND_KEY = 16,
+ RADIUS_VENDOR_ATTR_MS_MPPE_RECV_KEY = 17
+};
+
+struct radius_ms_mppe_keys {
+ u8 *send;
+ size_t send_len;
+ u8 *recv;
+ size_t recv_len;
+};
+
+
+/* RADIUS message structure for new and parsed messages */
+struct radius_msg {
+ unsigned char *buf;
+ size_t buf_size; /* total size allocated for buf */
+ size_t buf_used; /* bytes used in buf */
+
+ struct radius_hdr *hdr;
+
+ struct radius_attr_hdr **attrs; /* array of pointers to attributes */
+ size_t attr_size; /* total size of the attribute pointer array */
+ size_t attr_used; /* total number of attributes in the array */
+};
+
+
+/* Default size to be allocated for new RADIUS messages */
+#define RADIUS_DEFAULT_MSG_SIZE 1024
+
+/* Default size to be allocated for attribute array */
+#define RADIUS_DEFAULT_ATTR_COUNT 16
+
+
+/* MAC address ASCII format for IEEE 802.1X use
+ * (draft-congdon-radius-8021x-20.txt) */
+#define RADIUS_802_1X_ADDR_FORMAT "%02X-%02X-%02X-%02X-%02X-%02X"
+/* MAC address ASCII format for non-802.1X use */
+#define RADIUS_ADDR_FORMAT "%02x%02x%02x%02x%02x%02x"
+
+struct radius_msg *radius_msg_new(u8 code, u8 identifier);
+int radius_msg_initialize(struct radius_msg *msg, size_t init_len);
+void radius_msg_set_hdr(struct radius_msg *msg, u8 code, u8 identifier);
+void radius_msg_free(struct radius_msg *msg);
+void radius_msg_dump(struct radius_msg *msg);
+int radius_msg_finish(struct radius_msg *msg, u8 *secret, size_t secret_len);
+int radius_msg_finish_srv(struct radius_msg *msg, const u8 *secret,
+ size_t secret_len, const u8 *req_authenticator);
+void radius_msg_finish_acct(struct radius_msg *msg, u8 *secret,
+ size_t secret_len);
+struct radius_attr_hdr *radius_msg_add_attr(struct radius_msg *msg, u8 type,
+ u8 *data, size_t data_len);
+struct radius_msg *radius_msg_parse(const u8 *data, size_t len);
+int radius_msg_add_eap(struct radius_msg *msg, u8 *data, size_t data_len);
+u8 *radius_msg_get_eap(struct radius_msg *msg, size_t *len);
+int radius_msg_verify(struct radius_msg *msg, u8 *secret, size_t secret_len,
+ struct radius_msg *sent_msg);
+int radius_msg_verify_msg_auth(struct radius_msg *msg, const u8 *secret,
+ size_t secret_len, const u8 *req_auth);
+int radius_msg_verify_acct(struct radius_msg *msg, u8 *secret,
+ size_t secret_len, struct radius_msg *sent_msg);
+int radius_msg_copy_attr(struct radius_msg *dst, struct radius_msg *src,
+ u8 type);
+void radius_msg_make_authenticator(struct radius_msg *msg,
+ u8 *data, size_t len);
+struct radius_ms_mppe_keys *
+radius_msg_get_ms_keys(struct radius_msg *msg, struct radius_msg *sent_msg,
+ u8 *secret, size_t secret_len);
+struct radius_ms_mppe_keys *
+radius_msg_get_cisco_keys(struct radius_msg *msg, struct radius_msg *sent_msg,
+ u8 *secret, size_t secret_len);
+int radius_msg_add_mppe_keys(struct radius_msg *msg,
+ const u8 *req_authenticator,
+ const u8 *secret, size_t secret_len,
+ const u8 *send_key, size_t send_key_len,
+ const u8 *recv_key, size_t recv_key_len);
+struct radius_attr_hdr *
+radius_msg_add_attr_user_password(struct radius_msg *msg,
+ u8 *data, size_t data_len,
+ u8 *secret, size_t secret_len);
+int radius_msg_get_attr(struct radius_msg *msg, u8 type, u8 *buf, size_t len);
+
+static inline int radius_msg_add_attr_int32(struct radius_msg *msg, u8 type,
+ u32 value)
+{
+ u32 val = htonl(value);
+ return radius_msg_add_attr(msg, type, (u8 *) &val, 4) != NULL;
+}
+
+static inline int radius_msg_get_attr_int32(struct radius_msg *msg, u8 type,
+ u32 *value)
+{
+ u32 val;
+ int res;
+ res = radius_msg_get_attr(msg, type, (u8 *) &val, 4);
+ if (res != 4)
+ return -1;
+
+ *value = ntohl(val);
+ return 0;
+}
+int radius_msg_get_attr_ptr(struct radius_msg *msg, u8 type, u8 **buf,
+ size_t *len);
+
+#endif /* RADIUS_H */
diff --git a/contrib/wpa_supplicant/tls_openssl.c b/contrib/wpa_supplicant/tls_openssl.c
index 097b1c876e34..4e6ea539209f 100644
--- a/contrib/wpa_supplicant/tls_openssl.c
+++ b/contrib/wpa_supplicant/tls_openssl.c
@@ -489,9 +489,12 @@ int tls_global_private_key(void *_ssl_ctx, const char *private_key,
if (private_key == NULL)
return 0;
- passwd = strdup(private_key_passwd);
- if (passwd == NULL)
- return -1;
+ if (private_key_passwd) {
+ passwd = strdup(private_key_passwd);
+ if (passwd == NULL)
+ return -1;
+ } else
+ passwd = NULL;
SSL_CTX_set_default_passwd_cb(ssl_ctx, tls_passwd_cb);
SSL_CTX_set_default_passwd_cb_userdata(ssl_ctx, passwd);
diff --git a/contrib/wpa_supplicant/version.h b/contrib/wpa_supplicant/version.h
index d0a1a864fe2b..b030f34b94f9 100644
--- a/contrib/wpa_supplicant/version.h
+++ b/contrib/wpa_supplicant/version.h
@@ -1,6 +1,6 @@
#ifndef VERSION_H
#define VERSION_H
-#define VERSION_STR "0.3.8"
+#define VERSION_STR "0.3.9"
#endif /* VERSION_H */
diff --git a/contrib/wpa_supplicant/wpa.c b/contrib/wpa_supplicant/wpa.c
index 5d4ce734fe6c..c70f55652ce0 100644
--- a/contrib/wpa_supplicant/wpa.c
+++ b/contrib/wpa_supplicant/wpa.c
@@ -1035,6 +1035,7 @@ static void wpa_supplicant_process_1_of_4(struct wpa_supplicant *wpa_s,
if (hostapd_get_rand(wpa_s->snonce, WPA_NONCE_LEN)) {
wpa_msg(wpa_s, MSG_WARNING, "WPA: Failed to get "
"random data for SNonce");
+ free(rbuf);
return;
}
wpa_s->renew_snonce = 0;
@@ -1100,6 +1101,7 @@ static void wpa_supplicant_process_1_of_4(struct wpa_supplicant *wpa_s,
wpa_s->cur_pmksa = NULL;
abort_cached = 1;
} else {
+ free(rbuf);
return;
}
}
@@ -1110,6 +1112,7 @@ static void wpa_supplicant_process_1_of_4(struct wpa_supplicant *wpa_s,
"been received from the external IEEE "
"802.1X Supplicant - ignoring WPA "
"EAPOL-Key frame");
+ free(rbuf);
return;
#endif /* CONFIG_XSUPPLICANT_IFACE */
}
@@ -1120,6 +1123,7 @@ static void wpa_supplicant_process_1_of_4(struct wpa_supplicant *wpa_s,
"full EAP authenication");
wpa_eapol_send(wpa_s, IEEE802_1X_TYPE_EAPOL_START,
(u8 *) "", 0);
+ free(rbuf);
return;
}
@@ -1963,8 +1967,9 @@ static void wpa_sm_rx_eapol(struct wpa_supplicant *wpa_s,
if (be_to_host16(key->key_data_length) > extra_len) {
wpa_msg(wpa_s, MSG_INFO, "WPA: Invalid EAPOL-Key frame - "
- "key_data overflow (%d > %d)",
- be_to_host16(key->key_data_length), extra_len);
+ "key_data overflow (%d > %lu)",
+ be_to_host16(key->key_data_length),
+ (unsigned long) extra_len);
return;
}
@@ -2009,6 +2014,12 @@ void wpa_supplicant_rx_eapol(void *ctx, unsigned char *src_addr,
wpa_printf(MSG_DEBUG, "RX EAPOL from " MACSTR, MAC2STR(src_addr));
wpa_hexdump(MSG_MSGDUMP, "RX EAPOL", buf, len);
+ if (wpa_s->key_mgmt == WPA_KEY_MGMT_NONE) {
+ wpa_printf(MSG_DEBUG, "Ignored received EAPOL frame since "
+ "no key management is configured");
+ return;
+ }
+
if (wpa_s->eapol_received == 0) {
/* Timeout for completing IEEE 802.1X and WPA authentication */
wpa_supplicant_req_auth_timeout(
@@ -2252,6 +2263,7 @@ int rsn_preauth_init(struct wpa_supplicant *wpa_s, u8 *dst)
}
memset(ctx, 0, sizeof(*ctx));
ctx->ctx = wpa_s;
+ ctx->msg_ctx = wpa_s;
ctx->preauth = 1;
ctx->cb = rsn_preauth_eapol_cb;
ctx->cb_ctx = wpa_s;
diff --git a/contrib/wpa_supplicant/wpa_ctrl.c b/contrib/wpa_supplicant/wpa_ctrl.c
index 16cef5f83548..631c628efbdc 100644
--- a/contrib/wpa_supplicant/wpa_ctrl.c
+++ b/contrib/wpa_supplicant/wpa_ctrl.c
@@ -91,18 +91,17 @@ struct wpa_ctrl * wpa_ctrl_open(const char *ctrl_path)
snprintf(ctrl->local.sun_path, sizeof(ctrl->local.sun_path),
"/tmp/wpa_ctrl_%d-%d", getpid(), counter++);
if (bind(ctrl->s, (struct sockaddr *) &ctrl->local,
- sizeof(ctrl->local.sun_family) +
- strlen(ctrl->local.sun_path)) < 0) {
+ sizeof(ctrl->local)) < 0) {
close(ctrl->s);
free(ctrl);
return NULL;
}
ctrl->dest.sun_family = AF_UNIX;
- strncpy(ctrl->dest.sun_path, ctrl_path, sizeof(ctrl->dest.sun_path));
+ snprintf(ctrl->dest.sun_path, sizeof(ctrl->dest.sun_path), "%s",
+ ctrl_path);
if (connect(ctrl->s, (struct sockaddr *) &ctrl->dest,
- sizeof(ctrl->dest.sun_family) +
- strlen(ctrl->dest.sun_path)) < 0) {
+ sizeof(ctrl->dest)) < 0) {
close(ctrl->s);
unlink(ctrl->local.sun_path);
free(ctrl);
diff --git a/contrib/wpa_supplicant/wpa_supplicant.c b/contrib/wpa_supplicant/wpa_supplicant.c
index 10f12121471a..e88b46572cfe 100644
--- a/contrib/wpa_supplicant/wpa_supplicant.c
+++ b/contrib/wpa_supplicant/wpa_supplicant.c
@@ -360,18 +360,19 @@ void wpa_supplicant_notify_eapol_done(void *ctx)
}
-static int wpa_blacklisted(struct wpa_supplicant *wpa_s, const u8 *bssid)
+static struct wpa_blacklist *
+wpa_blacklist_get(struct wpa_supplicant *wpa_s, const u8 *bssid)
{
struct wpa_blacklist *e;
e = wpa_s->blacklist;
while (e) {
if (memcmp(e->bssid, bssid, ETH_ALEN) == 0)
- return 1;
+ return e;
e = e->next;
}
- return 0;
+ return NULL;
}
@@ -379,14 +380,21 @@ static int wpa_blacklist_add(struct wpa_supplicant *wpa_s, const u8 *bssid)
{
struct wpa_blacklist *e;
- if (wpa_blacklisted(wpa_s, bssid))
+ e = wpa_blacklist_get(wpa_s, bssid);
+ if (e) {
+ e->count++;
+ wpa_printf(MSG_DEBUG, "BSSID " MACSTR " blacklist count "
+ "incremented to %d",
+ MAC2STR(bssid), e->count);
return 0;
+ }
e = malloc(sizeof(*e));
if (e == NULL)
return -1;
memset(e, 0, sizeof(*e));
memcpy(e->bssid, bssid, ETH_ALEN);
+ e->count = 1;
e->next = wpa_s->blacklist;
wpa_s->blacklist = e;
wpa_printf(MSG_DEBUG, "Added BSSID " MACSTR " into blacklist",
@@ -1341,6 +1349,18 @@ static int wpa_supplicant_set_suites(struct wpa_supplicant *wpa_s,
return -1;
}
wpa_hexdump(MSG_DEBUG, "WPA: Own WPA IE", wpa_ie, *wpa_ie_len);
+ if (wpa_s->assoc_wpa_ie == NULL) {
+ /*
+ * Make a copy of the WPA/RSN IE so that 4-Way Handshake gets
+ * the correct version of the IE even if PMKSA caching is
+ * aborted (which would remove PMKID from IE generation).
+ */
+ wpa_s->assoc_wpa_ie = malloc(*wpa_ie_len);
+ if (wpa_s->assoc_wpa_ie) {
+ memcpy(wpa_s->assoc_wpa_ie, wpa_ie, *wpa_ie_len);
+ wpa_s->assoc_wpa_ie_len = *wpa_ie_len;
+ }
+ }
if (ssid->key_mgmt & WPA_KEY_MGMT_PSK) {
wpa_s->pmk_len = PMK_LEN;
@@ -1651,6 +1671,7 @@ wpa_supplicant_select_bss(struct wpa_supplicant *wpa_s, struct wpa_ssid *group,
struct wpa_ssid *ssid;
struct wpa_scan_result *bss, *selected = NULL;
int i;
+ struct wpa_blacklist *e;
wpa_printf(MSG_DEBUG, "Selecting BSS from priority group %d",
group->priority);
@@ -1666,7 +1687,8 @@ wpa_supplicant_select_bss(struct wpa_supplicant *wpa_s, struct wpa_ssid *group,
wpa_ssid_txt(bss->ssid, bss->ssid_len),
(unsigned long) bss->wpa_ie_len,
(unsigned long) bss->rsn_ie_len);
- if (wpa_blacklisted(wpa_s, bss->bssid)) {
+ if ((e = wpa_blacklist_get(wpa_s, bss->bssid)) &&
+ e->count > 1) {
wpa_printf(MSG_DEBUG, " skip - blacklisted");
continue;
}
@@ -1733,7 +1755,8 @@ wpa_supplicant_select_bss(struct wpa_supplicant *wpa_s, struct wpa_ssid *group,
* allows this. */
for (i = 0; i < num && !selected; i++) {
bss = &results[i];
- if (wpa_blacklisted(wpa_s, bss->bssid)) {
+ if ((e = wpa_blacklist_get(wpa_s, bss->bssid)) &&
+ e->count > 1) {
continue;
}
for (ssid = group; ssid; ssid = ssid->pnext) {
@@ -2088,7 +2111,8 @@ static void usage(void)
"usage:\n"
" wpa_supplicant [-BddehLqqvw] -i<ifname> -c<config file> "
"[-D<driver>] \\\n"
- " [-N -i<ifname> -c<conf> [-D<driver>] ...]\n"
+ " [-P<pid file>] "
+ "[-N -i<ifname> -c<conf> [-D<driver>] ...]\n"
"\n"
"drivers:\n",
wpa_supplicant_version, wpa_supplicant_license);
@@ -2135,6 +2159,7 @@ static struct wpa_supplicant * wpa_supplicant_alloc(void)
if (wpa_s == NULL)
return NULL;
memset(wpa_s, 0, sizeof(*wpa_s));
+ wpa_s->ctrl_sock = -1;
#ifdef CONFIG_XSUPPLICANT_IFACE
wpa_s->dot1x_s = -1;
#endif /* CONFIG_XSUPPLICANT_IFACE */
@@ -2279,6 +2304,7 @@ static void wpa_supplicant_deinit(struct wpa_supplicant *wpa_s)
wpa_drv_set_drop_unencrypted(wpa_s, 0);
wpa_drv_set_countermeasures(wpa_s, 0);
+ wpa_clear_keys(wpa_s, NULL);
wpa_drv_deinit(wpa_s);
}
@@ -2291,6 +2317,7 @@ int main(int argc, char *argv[])
struct wpa_supplicant *head, *wpa_s;
int c;
const char *confname, *driver, *ifname;
+ char *pid_file = NULL;
int daemonize = 0, wait_for_interface = 0, disable_eapol = 0, exitcode;
#ifdef CONFIG_NATIVE_WINDOWS
@@ -2312,7 +2339,7 @@ int main(int argc, char *argv[])
ifname = confname = driver = NULL;
for (;;) {
- c = getopt(argc, argv, "Bc:D:dehi:KLNqtvw");
+ c = getopt(argc, argv, "Bc:D:dehi:KLNP:qtvw");
if (c < 0)
break;
switch (c) {
@@ -2347,6 +2374,9 @@ int main(int argc, char *argv[])
case 'L':
license();
return -1;
+ case 'P':
+ pid_file = rel2abs_path(optarg);
+ break;
case 'q':
wpa_debug_level++;
break;
@@ -2407,6 +2437,14 @@ int main(int argc, char *argv[])
}
}
+ if (pid_file) {
+ FILE *f = fopen(pid_file, "w");
+ if (f) {
+ fprintf(f, "%u\n", getpid());
+ fclose(f);
+ }
+ }
+
eloop_register_signal(SIGINT, wpa_supplicant_terminate, NULL);
eloop_register_signal(SIGTERM, wpa_supplicant_terminate, NULL);
#ifndef CONFIG_NATIVE_WINDOWS
@@ -2431,6 +2469,11 @@ cleanup:
eloop_destroy();
+ if (pid_file) {
+ unlink(pid_file);
+ free(pid_file);
+ }
+
#ifdef CONFIG_NATIVE_WINDOWS
WSACleanup();
#endif /* CONFIG_NATIVE_WINDOWS */
diff --git a/contrib/wpa_supplicant/wpa_supplicant_i.h b/contrib/wpa_supplicant/wpa_supplicant_i.h
index 3883393c8aa6..508fe0912eb3 100644
--- a/contrib/wpa_supplicant/wpa_supplicant_i.h
+++ b/contrib/wpa_supplicant/wpa_supplicant_i.h
@@ -49,6 +49,7 @@ struct wpa_ptk {
struct wpa_blacklist {
struct wpa_blacklist *next;
u8 bssid[ETH_ALEN];
+ int count;
};
@@ -326,7 +327,7 @@ static inline int wpa_drv_set_wpa(struct wpa_supplicant *wpa_s, int enabled)
if (wpa_s->driver->set_wpa) {
return wpa_s->driver->set_wpa(wpa_s->drv_priv, enabled);
}
- return -1;
+ return 0;
}
static inline int wpa_drv_associate(struct wpa_supplicant *wpa_s,