diff options
author | sam <sam@FreeBSD.org> | 2005-06-13 16:43:14 +0000 |
---|---|---|
committer | sam <sam@FreeBSD.org> | 2005-06-13 16:43:14 +0000 |
commit | 848adee197364f7b5192e973348cebe5eb5c5915 (patch) | |
tree | f2b19ba38e49651630fab6d9c1aab4448257f39e /contrib/wpa_supplicant | |
parent | 381a0db2e319ad49128676b4c6cd91d2f88426b8 (diff) | |
parent | b6ecc83f22365fb67ec8b0b70bfcc56f12c76086 (diff) | |
download | FreeBSD-src-848adee197364f7b5192e973348cebe5eb5c5915.zip FreeBSD-src-848adee197364f7b5192e973348cebe5eb5c5915.tar.gz |
This commit was generated by cvs2svn to compensate for changes in r147338,
which included commits to RCS files with non-trunk default branches.
Diffstat (limited to 'contrib/wpa_supplicant')
-rw-r--r-- | contrib/wpa_supplicant/ChangeLog | 23 | ||||
-rw-r--r-- | contrib/wpa_supplicant/README | 4 | ||||
-rw-r--r-- | contrib/wpa_supplicant/config.c | 10 | ||||
-rw-r--r-- | contrib/wpa_supplicant/ctrl_iface.c | 15 | ||||
-rw-r--r-- | contrib/wpa_supplicant/eap.c | 14 | ||||
-rw-r--r-- | contrib/wpa_supplicant/eap_mschapv2.c | 11 | ||||
-rw-r--r-- | contrib/wpa_supplicant/eap_peap.c | 38 | ||||
-rw-r--r-- | contrib/wpa_supplicant/eap_tls_common.c | 11 | ||||
-rw-r--r-- | contrib/wpa_supplicant/eap_ttls.c | 12 | ||||
-rw-r--r-- | contrib/wpa_supplicant/eapol_sm.c | 3 | ||||
-rw-r--r-- | contrib/wpa_supplicant/ms_funcs.c | 4 | ||||
-rw-r--r-- | contrib/wpa_supplicant/radius.c | 1125 | ||||
-rw-r--r-- | contrib/wpa_supplicant/radius.h | 224 | ||||
-rw-r--r-- | contrib/wpa_supplicant/tls_openssl.c | 9 | ||||
-rw-r--r-- | contrib/wpa_supplicant/version.h | 2 | ||||
-rw-r--r-- | contrib/wpa_supplicant/wpa.c | 16 | ||||
-rw-r--r-- | contrib/wpa_supplicant/wpa_supplicant.c | 59 | ||||
-rw-r--r-- | contrib/wpa_supplicant/wpa_supplicant_i.h | 3 |
18 files changed, 1546 insertions, 37 deletions
diff --git a/contrib/wpa_supplicant/ChangeLog b/contrib/wpa_supplicant/ChangeLog index 5709858..09d5b61 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 7b5f547..bab25d5 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/config.c b/contrib/wpa_supplicant/config.c index 241c755..26307cf 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 e418811..25cf0db 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 a76b942..267907c 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 a39a5d3..35c391c 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 27f0793..8ca8ab2 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 20b1418..a56538c 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 b639fcd..733f136 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 93f9a54..1424b7d 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 9c50185..590b589 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 0000000..5fd323d --- /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 0000000..318e0ad --- /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 097b1c8..4e6ea53 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 d0a1a86..b030f34 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 5d4ce73..c70f556 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_supplicant.c b/contrib/wpa_supplicant/wpa_supplicant.c index 10f1212..e88b465 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 3883393..508fe09 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, |