diff options
author | Sam Leffler <sam@FreeBSD.org> | 2007-07-11 15:48:36 +0000 |
---|---|---|
committer | Sam Leffler <sam@FreeBSD.org> | 2007-07-11 15:48:36 +0000 |
commit | 7700b89cce864f82dbd9cf54979c59dd06ca9356 (patch) | |
tree | c3da7f33886a852f7dceb74373fbdeec49a48f77 | |
parent | 4e0922e888407f6dd91546a040e26125317fcfd8 (diff) | |
download | src-7700b89cce864f82dbd9cf54979c59dd06ca9356.tar.gz src-7700b89cce864f82dbd9cf54979c59dd06ca9356.zip |
Import of WPA supplicant 0.5.8
Notes
Notes:
svn path=/vendor/wpa_supplicant/dist/; revision=171366
211 files changed, 49687 insertions, 9538 deletions
diff --git a/contrib/wpa_supplicant/COPYING b/contrib/wpa_supplicant/COPYING index 60549be514af..14f5453722a8 100644 --- a/contrib/wpa_supplicant/COPYING +++ b/contrib/wpa_supplicant/COPYING @@ -2,7 +2,7 @@ Version 2, June 1991 Copyright (C) 1989, 1991 Free Software Foundation, Inc. - 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA Everyone is permitted to copy and distribute verbatim copies of this license document, but changing it is not allowed. @@ -305,7 +305,7 @@ the "copyright" line and a pointer to where the full notice is found. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software - Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA Also add information on how to contact you by electronic and paper mail. diff --git a/contrib/wpa_supplicant/ChangeLog b/contrib/wpa_supplicant/ChangeLog index 4ed9e261dfb6..5bf3660a05c9 100644 --- a/contrib/wpa_supplicant/ChangeLog +++ b/contrib/wpa_supplicant/ChangeLog @@ -1,32 +1,334 @@ ChangeLog for wpa_supplicant -2006-02-08 - v0.4.8 +2007-05-28 - v0.5.8 + * updated driver_wext.c to build with the current wireless-dev.git tree + and net/d80211 changes + * updated EAP Generalized Pre-Shared Key (EAP-GPSK) to use the latest + draft (draft-ietf-emu-eap-gpsk-03.txt) + * fixed 'make install' + * fixed EAP-TTLS implementation not to crash on use of freed memory + if TLS library initialization fails + * fixed EAP-AKA Notification processing to allow Notification to be + processed after AKA Challenge response has been sent + +2006-12-31 - v0.5.7 + * updated EAP-SAKE to RFC 4763 and the IANA-allocated EAP type 48 + * updated EAP-PSK to use the IANA-allocated EAP type 47 + * fixed EAP-PAX key derivation + * fixed EAP-PSK bit ordering of the Flags field + * fixed EAP-PEAP/TTLS/FAST to use the correct EAP identifier in + tunnelled identity request (previously, the identifier from the outer + method was used, not the tunnelled identifier which could be + different) + * fixed EAP-TTLS AVP parser processing for too short AVP lengths + * added support for EAP-FAST authentication with inner methods that + generate MSK (e.g., EAP-MSCHAPv2 that was previously only supported + for PAC provisioning) + * fixed dbus ctrl_iface to validate message interface before + dispatching to avoid a possible segfault [Bug 190] + * fixed PeerKey key derivation to use the correct PRF label + * updated Windows binary build to link against OpenSSL 0.9.8d and + added support for EAP-FAST + +2006-11-24 - v0.5.6 + * added experimental, integrated TLSv1 client implementation with the + needed X.509/ASN.1/RSA/bignum processing (this can be enabled by + setting CONFIG_TLS=internal and CONFIG_INTERNAL_LIBTOMMATH=y in + .config); this can be useful, e.g., if the target system does not + have a suitable TLS library and a minimal code size is required + (total size of this internal TLS/crypto code is bit under 50 kB on + x86 and the crypto code is shared by rest of the supplicant so some + of it was already required; TLSv1/X.509/ASN.1/RSA added about 25 kB) + * removed STAKey handshake since PeerKey handshake has replaced it in + IEEE 802.11ma and there are no known deployments of STAKey + * updated EAP Generalized Pre-Shared Key (EAP-GPSK) to use the latest + draft (draft-ietf-emu-eap-gpsk-01.txt) + * added preliminary implementation of IEEE 802.11w/D1.0 (management + frame protection) + (Note: this requires driver support to work properly.) + (Note2: IEEE 802.11w is an unapproved draft and subject to change.) + * fixed Windows named pipes ctrl_iface to not stop listening for + commands if client program opens a named pipe and closes it + immediately without sending a command + * fixed USIM PIN status determination for the case that PIN is not + needed (this allows EAP-AKA to be used with USIM cards that do not + use PIN) + * added support for reading 3G USIM AID from EF_DIR to allow EAP-AKA to + be used with cards that do not support file selection based on + partial AID + * added support for matching the subjectAltName of the authentication + server certificate against multiple name components (e.g., + altsubject_match="DNS:server.example.com;DNS:server2.example.com") + * fixed EAP-SIM/AKA key derivation for re-authentication case (only + affects IEEE 802.1X with dynamic WEP keys) + * changed ctrl_iface network configuration 'get' operations to not + return password/key material; if these fields are requested, "*" + will be returned if the password/key is set, but the value of the + parameter is not exposed + +2006-08-27 - v0.5.5 + * added support for building Windows version with UNICODE defined + (wide-char functions) + * driver_ndis: fixed static WEP configuration to avoid race condition + issues with some NDIS drivers between association and setting WEP + keys + * driver_ndis: added validation for IELength value in scan results to + avoid crashes when using buggy NDIS drivers [Bug 165] + * fixed Release|Win32 target in the Visual Studio project files + (previously, only Debug|Win32 target was set properly) + * changed control interface API call wpa_ctrl_pending() to allow it to + return -1 on error (e.g., connection lost); control interface clients + will need to make sure that they verify that the value is indeed >0 + when determining whether there are pending messages + * added an alternative control interface backend for Windows targets: + Named Pipe (CONFIG_CTRL_IFACE=named_pipe); this is now the default + control interface mechanism for Windows builds (previously, UDP to + localhost was used) + * changed ctrl_interface configuration for UNIX domain sockets: + - deprecated ctrl_interface_group variable (it may be removed in + future versions) + - allow both directory and group be configured with ctrl_interface + in following format: DIR=/var/run/wpa_supplicant GROUP=wheel + - ctrl_interface=/var/run/wpa_supplicant is still supported for the + case when group is not changed + * added support for controlling more than one interface per process in + Windows version + * added a workaround for a case where the AP is using unknown address + (e.g., MAC address of the wired interface) as the source address for + EAPOL-Key frames; previously, that source address was used as the + destination for EAPOL-Key frames and in key derivation; now, BSSID is + used even if the source address does not match with it + (this resolves an interoperability issue with Thomson SpeedTouch 580) + * added a workaround for UDP-based control interface (which was used in + Windows builds before this release) to prevent packets with forged + addresses from being accepted as local control requests + * removed ndis_events.cpp and possibility of using external + ndis_events.exe; C version (ndis_events.c) is fully functional and + there is no desire to maintain two separate versions of this + implementation + * ndis_events: Changed NDIS event notification design to use WMI to + learn the adapter description through Win32_PnPEntity class; this + should fix some cases where the adapter name was not recognized + correctly (e.g., with some USB WLAN adapters, e.g., Ralink RT2500 + USB) [Bug 113] + * fixed selection of the first network in ap_scan=2 mode; previously, + wpa_supplicant could get stuck in SCANNING state when only the first + network for enabled (e.g., after 'wpa_cli select_network 0') + * winsvc: added support for configuring ctrl_interface parameters in + registry (ctrl_interface string value in + HKLM\SOFTWARE\wpa_supplicant\interfaces\0000 key); this new value is + required to enable control interface (previously, this was hardcoded + to be enabled) + * allow wpa_gui subdirectory to be built with both Qt3 and Qt4 + * converted wpa_gui-qt4 subdirectory to use Qt4 specific project format + +2006-06-20 - v0.5.4 + * fixed build with CONFIG_STAKEY=y [Bug 143] + * added support for doing MLME (IEEE 802.11 management frame + processing) in wpa_supplicant when using Devicescape IEEE 802.11 + stack (wireless-dev.git tree) + * added a new network block configuration option, fragment_size, to + configure the maximum EAP fragment size + * driver_ndis: Disable WZC automatically for the selected interface to + avoid conflicts with two programs trying to control the radio; WZC + will be re-enabled (if it was enabled originally) when wpa_supplicant + is terminated + * added an experimental TLSv1 client implementation + (CONFIG_TLS=internal) that can be used instead of an external TLS + library, e.g., to reduce total size requirement on systems that do + not include any TLS library by default (this is not yet complete; + basic functionality is there, but certificate validation is not yet + included) + * added PeerKey handshake implementation for IEEE 802.11e + direct link setup (DLS) to replace STAKey handshake + * fixed WPA PSK update through ctrl_iface for the case where the old + PSK was derived from an ASCII passphrase and the new PSK is set as + a raw PSK (hex string) + * added new configuration option for identifying which network block + was used (id_str in wpa_supplicant.conf; included on + WPA_EVENT_CONNECT monitor event and as WPA_ID_STR environmental + variable in wpa_cli action scripts; in addition WPA_ID variable is + set to the current unique identifier that wpa_supplicant assigned + automatically for the network and that can be used with + GET_NETWORK/SET_NETWORK ctrl_iface commands) + * wpa_cli action script is now called only when the connect/disconnect + status changes or when associating with a different network + * fixed configuration parser not to remove CCMP from group cipher list + if WPA-None (adhoc) is used (pairwise=NONE in that case) + * fixed integrated NDIS events processing not to hang the process due + to a missed change in eloop_win.c API in v0.5.3 [Bug 155] + * added support for EAP Generalized Pre-Shared Key (EAP-GPSK, + draft-clancy-emu-eap-shared-secret-00.txt) + * added Microsoft Visual Studio 2005 solution and project files for + build wpa_supplicant for Windows (see vs2005 subdirectory) + * eloop_win: fixed unregistration of Windows events + * l2_packet_winpcap: fixed a deadlock in deinitializing l2_packet + at the end of RSN pre-authentication and added unregistration of + a Windows event to avoid getting eloop_win stuck with an invalid + handle + * driver_ndis: added support for selecting AP based on BSSID + * added new environmental variable for wpa_cli action scripts: + WPA_CTRL_DIR is the current control interface directory + * driver_ndis: added support for using NDISUIO instead of WinPcap for + OID set/query operations (CONFIG_USE_NDISUIO=y in .config); with new + l2_packet_ndis (CONFIG_L2_PACKET=ndis), this can be used to build + wpa_supplicant without requiring WinPcap; note that using NDISUIO + requires that WZC is disabled (net stop wzcsvc) since NDISUIO allows + only one application to open the device + * changed NDIS driver naming to only include device GUID, e.g., + {7EE3EFE5-C165-472F-986D-F6FBEDFE8C8D}, instead of including WinPcap + specific \Device\NPF_ prefix before the GUID; the prefix is still + allowed for backwards compatibility, but it is not required anymore + when specifying the interface + * driver_ndis: re-initialize driver interface is the adapter is removed + and re-inserted [Bug 159] + * driver_madwifi: fixed TKIP and CCMP sequence number configuration on + big endian hosts [Bug 146] + +2006-04-27 - v0.5.3 + * fixed EAP-GTC response to include correct user identity when run as + phase 2 method of EAP-FAST (i.e., EAP-FAST did not work in v0.5.2) + * driver_ndis: Fixed encryption mode configuration for unencrypted + networks (some NDIS drivers ignored this, but others, e.g., Broadcom, + refused to associate with open networks) [Bug 106] + * driver_ndis: use BSSID OID polling to detect when IBSS network is + formed even when ndis_events code is included since some NDIS drivers + do not generate media connect events in IBSS mode + * config_winreg: allow global ctrl_interface parameter to be configured + in Windows registry + * config_winreg: added support for saving configuration data into + Windows registry + * added support for controlling network device operational state + (dormant/up) for Linux 2.6.17 to improve DHCP processing (see + http://www.flamewarmaster.de/software/dhcpclient/ for a DHCP client + that can use this information) + * driver_wext: added support for WE-21 change to SSID configuration + * driver_wext: fixed privacy configuration for static WEP keys mode + [Bug 140] + * added an optional driver_ops callback for MLME-SETPROTECTION.request + primitive + * added support for EAP-SAKE (no EAP method number allocated yet, so + this is using the same experimental type 255 as EAP-PSK) + * added support for dynamically loading EAP methods (.so files) instead + of requiring them to be statically linked in; this is disabled by + default (see CONFIG_DYNAMIC_EAP_METHODS in defconfig for information + on how to use this) + +2006-03-19 - v0.5.2 + * do not try to use USIM APDUs when initializing PC/SC for SIM card + access for a network that has not enabled EAP-AKA + * fixed EAP phase 2 Nak for EAP-{PEAP,TTLS,FAST} (this was broken in + v0.5.1 due to the new support for expanded EAP types) + * added support for generating EAP Expanded Nak + * try to fetch scan results once before requesting new scan when + starting up in ap_scan=1 mode (this can speed up initial association + a lot with, e.g., madwifi-ng driver) + * added support for receiving EAPOL frames from a Linux bridge + interface (-bbr0 on command line) + * fixed EAPOL re-authentication for sessions that used PMKSA caching + * changed EAP method registration to use a dynamic list of methods + instead of a static list generated at build time + * fixed PMKSA cache deinitialization not to use freed memory when + removing PMKSA entries + * fixed a memory leak in EAP-TTLS re-authentication + * reject WPA/WPA2 message 3/4 if it does not include any valid + WPA/RSN IE + * driver_wext: added fallback to use SIOCSIWENCODE for setting auth_alg + if the driver does not support SIOCSIWAUTH + +2006-01-29 - v0.5.1 + * driver_test: added better support for multiple APs and STAs by using + a directory with sockets that include MAC address for each device in + the name (driver_param=test_dir=/tmp/test) + * added support for EAP expanded type (vendor specific EAP methods) + * added AP_SCAN command into ctrl_iface so that ap_scan configuration + option can be changed if needed + * wpa_cli/wpa_gui: skip non-socket files in control directory when + using UNIX domain sockets; this avoids selecting an incorrect + interface (e.g., a PID file could be in this directory, even though + use of this directory for something else than socket files is not + recommended) + * fixed TLS library deinitialization after RSN pre-authentication not + to disable TLS library for normal authentication + * driver_wext: Remove null-termination from SSID length if the driver + used it; some Linux drivers do this and they were causing problems in + wpa_supplicant not finding matching configuration block. This change + would break a case where the SSID actually ends in '\0', but that is + not likely to happen in real use. + * fixed PMKSA cache processing not to trigger deauthentication if the + current PMKSA cache entry is replaced with a valid new entry + * fixed PC/SC initialization for ap_scan != 1 modes (this fixes + EAP-SIM and EAP-AKA with real SIM/USIM card when using ap_scan=0 or + ap_scan=2) + +2005-12-18 - v0.5.0 (beginning of 0.5.x development releases) + * added experimental STAKey handshake implementation for IEEE 802.11e + direct link setup (DLS); note: this is disabled by default in both + build and runtime configuration (can be enabled with CONFIG_STAKEY=y + and stakey=1) + * fixed EAP-SIM and EAP-AKA pseudonym and fast re-authentication to + decrypt AT_ENCR_DATA attributes correctly + * fixed EAP-AKA to allow resynchronization within the same session + * made code closer to ANSI C89 standard to make it easier to port to + other C libraries and compilers + * started moving operating system or C library specific functions into + wrapper functions defined in os.h and implemented in os_*.c to make + code more portable + * wpa_supplicant can now be built with Microsoft Visual C++ + (e.g., with the freely available Toolkit 2003 version or Visual + C++ 2005 Express Edition and Platform SDK); see nmake.mak for an + example makefile for nmake + * added support for using Windows registry for command line parameters + (CONFIG_MAIN=main_winsvc) and configuration data + (CONFIG_BACKEND=winreg); see win_example.reg for an example registry + contents; this version can be run both as a Windows service and as a + normal application; 'wpasvc.exe app' to start as applicant, + 'wpasvc.exe reg <full path to wpasvc.exe>' to register a service, + 'net start wpasvc' to start the service, 'wpasvc.exe unreg' to + unregister a service + * made it possible to link ndis_events.exe functionality into + wpa_supplicant.exe by defining CONFIG_NDIS_EVENTS_INTEGRATED + * added better support for multiple control interface backends + (CONFIG_CTRL_IFACE option); currently, 'unix' and 'udp' are supported * fixed PC/SC code to use correct length for GSM AUTH command buffer and to not use pioRecvPci with SCardTransmit() calls; these were not causing visible problems with pcsc-lite, but Windows Winscard.dll refused the previously used parameters; this fixes EAP-SIM and EAP-AKA authentication using SIM/USIM card under Windows + * added new event loop implementation for Windows using + WaitForMultipleObject() instead of select() in order to allow waiting + for non-socket objects; this can be selected with + CONFIG_ELOOP=eloop_win in .config + * added support for selecting l2_packet implementation in .config + (CONFIG_L2_PACKET; following options are available now: linux, pcap, + winpcap, freebsd, none) + * added new l2_packet implementation for WinPcap + (CONFIG_L2_PACKET=winpcap) that uses a separate receive thread to + reduce latency in EAPOL receive processing from about 100 ms to about + 3 ms * added support for EAP-FAST key derivation using other ciphers than RC4-128-SHA for authentication and AES128-SHA for provisioning - * fixed EAP-SIM and EAP-AKA pseudonym and fast re-authentication to - decrypt AT_ENCR_DATA attributes correctly * added support for configuring CA certificate as DER file and as a configuration blob * fixed private key configuration as configuration blob and added support for using PKCS#12 as a blob - * fixed cygwin build + * tls_gnutls: added support for using PKCS#12 files; added support for + session resumption * added support for loading trusted CA certificates from Windows certificate store: ca_cert="cert_store://<name>", where <name> is likely CA (Intermediate CA certificates) or ROOT (root certificates) - * fixed TLS library deinitialization after RSN pre-authentication not - to disable TLS library for normal authentication - * fixed PMKSA cache processing not to trigger deauthentication if the - current PMKSA cache entry is replaced with a valid new entry - * fixed PC/SC initialization for ap_scan != 1 modes (this fixes - EAP-SIM and EAP-AKA with real SIM/USIM card when using ap_scan=0 or - ap_scan=2) - * do not try to use USIM APDUs when initializing PC/SC for SIM card - access for a network that has not enabled EAP-AKA + * added C version of ndis_events.cpp and made it possible to build this + with MinGW so that CONFIG_NDIS_EVENTS_INTEGRATED can be used more + easily on cross-compilation builds + * added wpasvc.exe into Windows binary release; this is an alternative + version of wpa_supplicant.exe with configuration backend using + Windows registry and with the entry point designed to run as a + Windows service + * integrated ndis_events.exe functionality into wpa_supplicant.exe and + wpasvc.exe and removed this additional tool from the Windows binary + release since it is not needed anymore + * load winscard.dll functions dynamically when building with MinGW + since MinGW does not yet include winscard library 2005-11-20 - v0.4.7 (beginning of 0.4.x stable releases) * l2_packet_pcap: fixed wired IEEE 802.1X authentication with libpcap diff --git a/contrib/wpa_supplicant/FREEBSD-Xlist b/contrib/wpa_supplicant/FREEBSD-Xlist index d2f169790480..d9522be08a91 100644 --- a/contrib/wpa_supplicant/FREEBSD-Xlist +++ b/contrib/wpa_supplicant/FREEBSD-Xlist @@ -7,16 +7,27 @@ driver_bsd.c driver_hostap.c driver_ipw.c driver_madwifi.c -driver_ndis.c -driver_ndis.h -driver_ndis_.c driver_ndiswrapper.c +driver_ndis_.c driver_prism54.c driver_test.c driver_wext.c driver_wext.h -l2_packet.c +l2_packet_freebsd.c +l2_packet_linux.c +l2_packet_ndis.c +l2_packet_none.c +l2_packet_pcap.c +l2_packet_winpcap.c +main_none.c +main_winmain.c +main_winsvc.c +ndis_events.c ndis_events.cpp +nmake.mk +os_win32.c priv_netlink.h +vs2005 +win_example.reg win_if_list.c wireless_copy.h diff --git a/contrib/wpa_supplicant/FREEBSD-upgrade b/contrib/wpa_supplicant/FREEBSD-upgrade index f8ef0f001379..88a4b1848017 100644 --- a/contrib/wpa_supplicant/FREEBSD-upgrade +++ b/contrib/wpa_supplicant/FREEBSD-upgrade @@ -6,12 +6,12 @@ WPA Supplicant For the import files and directories were pruned by: - tar -X FREEBSD-Xlist -zxf wpa_supplicant-0.3.8.tar.gz + tar -X FREEBSD-Xlist -zxf wpa_supplicant-0.5.8.tar.gz then imported by: - cvs import -m 'Import of WPA supplicant 0.3.8' \ - src/contrib/wpa_supplicant MALINEN v0_3_8 + cvs import -m 'Import of WPA supplicant 0.5.8' \ + src/contrib/wpa_supplicant MALINEN v0_5_8 To make local changes to wpa_supplcaint, simply patch and commit to the main branch (aka HEAD). Never make local changes on the @@ -21,4 +21,4 @@ All local changes should be submitted to Jouni Malinen for inclusion in the next vendor release. sam@FreeBSD.org -4-June-2005 +11-July-2007 diff --git a/contrib/wpa_supplicant/Makefile b/contrib/wpa_supplicant/Makefile index d8fd3edda01c..f29eb693a7e3 100644 --- a/contrib/wpa_supplicant/Makefile +++ b/contrib/wpa_supplicant/Makefile @@ -11,7 +11,7 @@ CFLAGS += -I. -I../utils -I../hostapd ALL=wpa_supplicant wpa_passphrase wpa_cli -all: verify_config $(ALL) +all: verify_config $(ALL) dynamic_eap_methods verify_config: @if [ ! -r .config ]; then \ @@ -36,13 +36,36 @@ install: all for i in $(ALL); do cp $$i $(DESTDIR)/usr/local/sbin/$$i; done OBJS = config.o \ - eloop.o common.o md5.o \ - rc4.o sha1.o -OBJS_p = wpa_passphrase.o sha1.o md5.o + common.o md5.o md4.o \ + rc4.o sha1.o des.o +OBJS_p = wpa_passphrase.o sha1.o md5.o md4.o \ + common.o des.o OBJS_c = wpa_cli.o wpa_ctrl.o -include .config +ifndef CONFIG_OS +ifdef CONFIG_NATIVE_WINDOWS +CONFIG_OS=win32 +else +CONFIG_OS=unix +endif +endif + +ifeq ($(CONFIG_OS), internal) +CFLAGS += -DOS_NO_C_LIB_DEFINES +endif + +OBJS += os_$(CONFIG_OS).o +OBJS_p += os_$(CONFIG_OS).o +OBJS_c += os_$(CONFIG_OS).o + +ifndef CONFIG_ELOOP +CONFIG_ELOOP=eloop +endif +OBJS += $(CONFIG_ELOOP).o + + ifdef CONFIG_EAPOL_TEST CFLAGS += -Werror -DEAPOL_TEST endif @@ -56,6 +79,14 @@ OBJS += config_file.o base64.o CFLAGS += -DCONFIG_BACKEND_FILE endif +ifeq ($(CONFIG_BACKEND), winreg) +OBJS += config_winreg.o +endif + +ifeq ($(CONFIG_BACKEND), none) +OBJS += config_none.o +endif + ifdef CONFIG_DRIVER_HOSTAP CFLAGS += -DCONFIG_DRIVER_HOSTAP OBJS_d += driver_hostap.o @@ -111,15 +142,21 @@ endif ifdef CONFIG_DRIVER_BSD CFLAGS += -DCONFIG_DRIVER_BSD OBJS_d += driver_bsd.o -CONFIG_DNET_PCAP=y -CONFIG_L2_FREEBSD=y +ifndef CONFIG_L2_PACKET +CONFIG_L2_PACKET=freebsd +endif endif ifdef CONFIG_DRIVER_NDIS CFLAGS += -DCONFIG_DRIVER_NDIS OBJS_d += driver_ndis.o driver_ndis_.o -CONFIG_DNET_PCAP=y +ifndef CONFIG_L2_PACKET +CONFIG_L2_PACKET=pcap +endif CONFIG_WINPCAP=y +ifdef CONFIG_USE_NDISUIO +CFLAGS += -DCONFIG_USE_NDISUIO +endif endif ifdef CONFIG_DRIVER_WIRED @@ -132,116 +169,176 @@ CFLAGS += -DCONFIG_DRIVER_TEST OBJS_d += driver_test.o endif -ifdef CONFIG_DNET_PCAP -CFLAGS += -DUSE_DNET_PCAP +ifndef CONFIG_L2_PACKET +CONFIG_L2_PACKET=linux +endif + +OBJS += l2_packet_$(CONFIG_L2_PACKET).o + +ifeq ($(CONFIG_L2_PACKET), pcap) ifdef CONFIG_WINPCAP -OBJS += l2_packet_pcap.o CFLAGS += -DCONFIG_WINPCAP LIBS += -lwpcap -lpacket LIBS_w += -lwpcap else -ifdef CONFIG_L2_FREEBSD -OBJS += l2_packet_freebsd.o -LIBS += -lpcap -else -OBJS += l2_packet_pcap.o LIBS += -ldnet -lpcap endif endif -else -OBJS += l2_packet_linux.o + +ifeq ($(CONFIG_L2_PACKET), winpcap) +LIBS += -lwpcap -lpacket +LIBS_w += -lwpcap +endif + +ifeq ($(CONFIG_L2_PACKET), freebsd) +LIBS += -lpcap endif ifdef CONFIG_EAP_TLS # EAP-TLS +ifeq ($(CONFIG_EAP_TLS), dyn) +CFLAGS += -DEAP_TLS_DYNAMIC +EAPDYN += eap_tls.so +else CFLAGS += -DEAP_TLS OBJS += eap_tls.o +endif TLS_FUNCS=y CONFIG_IEEE8021X_EAPOL=y endif ifdef CONFIG_EAP_PEAP # EAP-PEAP +ifeq ($(CONFIG_EAP_PEAP), dyn) +CFLAGS += -DEAP_PEAP_DYNAMIC +EAPDYN += eap_peap.so +else CFLAGS += -DEAP_PEAP OBJS += eap_peap.o +endif TLS_FUNCS=y -CONFIG_EAP_MSCHAPV2=y CONFIG_IEEE8021X_EAPOL=y CONFIG_EAP_TLV=y endif ifdef CONFIG_EAP_TTLS # EAP-TTLS +ifeq ($(CONFIG_EAP_TTLS), dyn) +CFLAGS += -DEAP_TTLS_DYNAMIC +EAPDYN += eap_ttls.so +else CFLAGS += -DEAP_TTLS OBJS += eap_ttls.o +endif MS_FUNCS=y TLS_FUNCS=y -CONFIG_EAP_MD5=y CONFIG_IEEE8021X_EAPOL=y endif ifdef CONFIG_EAP_MD5 -# EAP-MD5 (also used by EAP-TTLS) +# EAP-MD5 +ifeq ($(CONFIG_EAP_MD5), dyn) +CFLAGS += -DEAP_MD5_DYNAMIC +EAPDYN += eap_md5.so +else CFLAGS += -DEAP_MD5 OBJS += eap_md5.o +endif CONFIG_IEEE8021X_EAPOL=y endif # backwards compatibility for old spelling ifdef CONFIG_MSCHAPV2 +ifndef CONFIG_EAP_MSCHAPV2 CONFIG_EAP_MSCHAPV2=y endif +endif ifdef CONFIG_EAP_MSCHAPV2 -# EAP-MSCHAPv2 (also used by EAP-PEAP) +# EAP-MSCHAPv2 +ifeq ($(CONFIG_EAP_MSCHAPV2), dyn) +CFLAGS += -DEAP_MSCHAPv2_DYNAMIC +EAPDYN += eap_mschapv2.so +else CFLAGS += -DEAP_MSCHAPv2 OBJS += eap_mschapv2.o +endif MS_FUNCS=y CONFIG_IEEE8021X_EAPOL=y endif ifdef CONFIG_EAP_GTC -# EAP-GTC (also used by EAP-PEAP) +# EAP-GTC +ifeq ($(CONFIG_EAP_GTC), dyn) +CFLAGS += -DEAP_GTC_DYNAMIC +EAPDYN += eap_gtc.so +else CFLAGS += -DEAP_GTC OBJS += eap_gtc.o +endif CONFIG_IEEE8021X_EAPOL=y endif ifdef CONFIG_EAP_OTP # EAP-OTP +ifeq ($(CONFIG_EAP_OTP), dyn) +CFLAGS += -DEAP_OTP_DYNAMIC +EAPDYN += eap_otp.so +else CFLAGS += -DEAP_OTP OBJS += eap_otp.o +endif CONFIG_IEEE8021X_EAPOL=y endif ifdef CONFIG_EAP_SIM # EAP-SIM +ifeq ($(CONFIG_EAP_SIM), dyn) +CFLAGS += -DEAP_SIM_DYNAMIC +EAPDYN += eap_sim.so +else CFLAGS += -DEAP_SIM OBJS += eap_sim.o +endif CONFIG_IEEE8021X_EAPOL=y CONFIG_EAP_SIM_COMMON=y endif ifdef CONFIG_EAP_LEAP # EAP-LEAP +ifeq ($(CONFIG_EAP_LEAP), dyn) +CFLAGS += -DEAP_LEAP_DYNAMIC +EAPDYN += eap_leap.so +else CFLAGS += -DEAP_LEAP OBJS += eap_leap.o +endif MS_FUNCS=y CONFIG_IEEE8021X_EAPOL=y endif ifdef CONFIG_EAP_PSK # EAP-PSK +ifeq ($(CONFIG_EAP_PSK), dyn) +CFLAGS += -DEAP_PSK_DYNAMIC +EAPDYN += eap_psk.so +else CFLAGS += -DEAP_PSK OBJS += eap_psk.o eap_psk_common.o +endif CONFIG_IEEE8021X_EAPOL=y NEED_AES=y endif ifdef CONFIG_EAP_AKA # EAP-AKA +ifeq ($(CONFIG_EAP_AKA), dyn) +CFLAGS += -DEAP_AKA_DYNAMIC +EAPDYN += eap_aka.so +else CFLAGS += -DEAP_AKA OBJS += eap_aka.o +endif CONFIG_IEEE8021X_EAPOL=y CONFIG_EAP_SIM_COMMON=y endif @@ -259,22 +356,75 @@ endif ifdef CONFIG_EAP_FAST # EAP-FAST +ifeq ($(CONFIG_EAP_FAST), dyn) +CFLAGS += -DEAP_FAST_DYNAMIC +EAPDYN += eap_fast.so +else CFLAGS += -DEAP_FAST OBJS += eap_fast.o +endif TLS_FUNCS=y endif ifdef CONFIG_EAP_PAX # EAP-PAX +ifeq ($(CONFIG_EAP_PAX), dyn) +CFLAGS += -DEAP_PAX_DYNAMIC +EAPDYN += eap_pax.so +else CFLAGS += -DEAP_PAX OBJS += eap_pax.o eap_pax_common.o +endif +CONFIG_IEEE8021X_EAPOL=y +endif + +ifdef CONFIG_EAP_SAKE +# EAP-SAKE +ifeq ($(CONFIG_EAP_SAKE), dyn) +CFLAGS += -DEAP_SAKE_DYNAMIC +EAPDYN += eap_sake.so +else +CFLAGS += -DEAP_SAKE +OBJS += eap_sake.o eap_sake_common.o +endif +CONFIG_IEEE8021X_EAPOL=y +endif + +ifdef CONFIG_EAP_GPSK +# EAP-GPSK +ifeq ($(CONFIG_EAP_GPSK), dyn) +CFLAGS += -DEAP_GPSK_DYNAMIC +EAPDYN += eap_gpsk.so +else +CFLAGS += -DEAP_GPSK +OBJS += eap_gpsk.o eap_gpsk_common.o +endif +CONFIG_IEEE8021X_EAPOL=y +ifdef CONFIG_EAP_GPSK_SHA256 +CFLAGS += -DEAP_GPSK_SHA256 +NEED_SHA256=y +endif +endif + +ifdef CONFIG_EAP_VENDOR_TEST +ifeq ($(CONFIG_EAP_VENDOR_TEST), dyn) +CFLAGS += -DEAP_VENDOR_TEST_DYNAMIC +EAPDYN += eap_vendor_test.so +else +CFLAGS += -DEAP_VENDOR_TEST +OBJS += eap_vendor_test.o +endif CONFIG_IEEE8021X_EAPOL=y endif ifdef CONFIG_IEEE8021X_EAPOL # IEEE 802.1X/EAPOL state machines (e.g., for RADIUS authentication) CFLAGS += -DIEEE8021X_EAPOL -OBJS += eapol_sm.o eap.o +OBJS += eapol_sm.o eap.o eap_methods.o +ifdef CONFIG_DYNAMIC_EAP_METHODS +CFLAGS += -DCONFIG_DYNAMIC_EAP_METHODS +LIBS += -ldl -rdynamic +endif endif ifdef CONFIG_PCSC @@ -282,18 +432,38 @@ ifdef CONFIG_PCSC CFLAGS += -DPCSC_FUNCS -I/usr/include/PCSC OBJS += pcsc_funcs.o # -lpthread may not be needed depending on how pcsc-lite was configured +ifdef CONFIG_NATIVE_WINDOWS +#Once MinGW gets support for WinScard, -lwinscard could be used instead of the +#dynamic symbol loading that is now used in pcsc_funcs.c +#LIBS += -lwinscard +else LIBS += -lpcsclite -lpthread endif +endif ifndef CONFIG_TLS CONFIG_TLS=openssl endif +ifeq ($(CONFIG_TLS), internal) +ifndef CONFIG_CRYPTO +CONFIG_CRYPTO=internal +endif +endif +ifeq ($(CONFIG_CRYPTO), libtomcrypt) +CFLAGS += -DCONFIG_INTERNAL_X509 +endif +ifeq ($(CONFIG_CRYPTO), internal) +CFLAGS += -DCONFIG_INTERNAL_X509 +endif + + ifdef TLS_FUNCS # Shared TLS functions (needed for EAP_TLS, EAP_PEAP, EAP_TTLS, and EAP_FAST) CFLAGS += -DEAP_TLS_FUNCS OBJS += eap_tls_common.o ifeq ($(CONFIG_TLS), openssl) +CFLAGS += -DEAP_TLS_OPENSSL OBJS += tls_openssl.o LIBS += -lssl -lcrypto LIBS_p += -lcrypto @@ -302,16 +472,45 @@ ifeq ($(CONFIG_TLS), gnutls) OBJS += tls_gnutls.o LIBS += -lgnutls -lgcrypt -lgpg-error LIBS_p += -lgcrypt +ifdef CONFIG_GNUTLS_EXTRA +CFLAGS += -DCONFIG_GNUTLS_EXTRA +LIBS += -lgnutls-extra +endif endif ifeq ($(CONFIG_TLS), schannel) OBJS += tls_schannel.o -# Using OpenSSL for crypto at the moment; to be replaced -LIBS += -lcrypto -LIBS_p += -lcrypto +endif +ifeq ($(CONFIG_TLS), internal) +OBJS += tls_internal.o tlsv1_common.o tlsv1_client.o asn1.o x509v3.o +OBJS_p += asn1.o rc4.o aes_wrap.o +ifneq ($(CONFIG_BACKEND), file) +OBJS += base64.o +endif +CFLAGS += -DCONFIG_TLS_INTERNAL +ifeq ($(CONFIG_CRYPTO), internal) +ifdef CONFIG_INTERNAL_LIBTOMMATH +CFLAGS += -DCONFIG_INTERNAL_LIBTOMMATH +else +LIBS += -ltommath +LIBS_p += -ltommath +endif +endif +ifeq ($(CONFIG_CRYPTO), libtomcrypt) +LIBS += -ltomcrypt -ltfm +LIBS_p += -ltomcrypt -ltfm +endif +endif +ifeq ($(CONFIG_TLS), none) +OBJS += tls_none.o +CFLAGS += -DEAP_TLS_NONE +CONFIG_INTERNAL_AES=y +CONFIG_INTERNAL_SHA1=y +CONFIG_INTERNAL_MD5=y +CONFIG_INTERNAL_SHA256=y endif ifdef CONFIG_SMARTCARD ifndef CONFIG_NATIVE_WINDOWS -ifndef CONFIG_L2_FREEBSD +ifneq ($(CONFIG_L2_PACKET), freebsd) LIBS += -ldl endif endif @@ -345,24 +544,85 @@ LIBS += -lgcrypt LIBS_p += -lgcrypt endif ifeq ($(CONFIG_TLS), schannel) -# Using OpenSSL for crypto at the moment; to be replaced -LIBS += -lcrypto -LIBS_p += -lcrypto +endif +ifeq ($(CONFIG_TLS), internal) +ifeq ($(CONFIG_CRYPTO), libtomcrypt) +LIBS += -ltomcrypt -ltfm +LIBS_p += -ltomcrypt -ltfm +endif endif endif ifeq ($(CONFIG_TLS), openssl) OBJS += crypto.o OBJS_p += crypto.o +CONFIG_INTERNAL_SHA256=y endif ifeq ($(CONFIG_TLS), gnutls) OBJS += crypto_gnutls.o OBJS_p += crypto_gnutls.o +CONFIG_INTERNAL_SHA256=y endif ifeq ($(CONFIG_TLS), schannel) -# Using OpenSSL for crypto at the moment; to be replaced -OBJS += crypto.o -OBJS_p += crypto.o +OBJS += crypto_cryptoapi.o +OBJS_p += crypto_cryptoapi.o +CONFIG_INTERNAL_SHA256=y +endif +ifeq ($(CONFIG_TLS), internal) +ifeq ($(CONFIG_CRYPTO), libtomcrypt) +OBJS += crypto_libtomcrypt.o +OBJS_p += crypto_libtomcrypt.o +CONFIG_INTERNAL_SHA256=y +endif +ifeq ($(CONFIG_CRYPTO), internal) +OBJS += crypto_internal.o rsa.o bignum.o +OBJS_p += crypto_internal.o rsa.o bignum.o +CFLAGS += -DCONFIG_CRYPTO_INTERNAL +CONFIG_INTERNAL_AES=y +CONFIG_INTERNAL_DES=y +CONFIG_INTERNAL_SHA1=y +CONFIG_INTERNAL_MD4=y +CONFIG_INTERNAL_MD5=y +CONFIG_INTERNAL_SHA256=y +endif +ifeq ($(CONFIG_CRYPTO), cryptoapi) +OBJS += crypto_cryptoapi.o +OBJS_p += crypto_cryptoapi.o +CFLAGS += -DCONFIG_CRYPTO_CRYPTOAPI +CONFIG_INTERNAL_SHA256=y +endif +endif +ifeq ($(CONFIG_TLS), none) +OBJS += crypto_none.o +OBJS_p += crypto_none.o +CONFIG_INTERNAL_SHA256=y +endif +else +CONFIG_INTERNAL_AES=y +CONFIG_INTERNAL_SHA1=y +CONFIG_INTERNAL_MD5=y +endif + +ifdef CONFIG_INTERNAL_AES +CFLAGS += -DINTERNAL_AES +endif +ifdef CONFIG_INTERNAL_SHA1 +CFLAGS += -DINTERNAL_SHA1 +endif +ifdef CONFIG_INTERNAL_SHA256 +CFLAGS += -DINTERNAL_SHA256 endif +ifdef CONFIG_INTERNAL_MD5 +CFLAGS += -DINTERNAL_MD5 +endif +ifdef CONFIG_INTERNAL_MD4 +CFLAGS += -DINTERNAL_MD4 +endif +ifdef CONFIG_INTERNAL_DES +CFLAGS += -DINTERNAL_DES +endif + +ifdef NEED_SHA256 +OBJS += sha256.o endif ifdef CONFIG_WIRELESS_EXTENSION @@ -371,8 +631,31 @@ OBJS_d += driver_wext.o endif ifdef CONFIG_CTRL_IFACE +ifeq ($(CONFIG_CTRL_IFACE), y) +ifdef CONFIG_NATIVE_WINDOWS +CONFIG_CTRL_IFACE=named_pipe +else +CONFIG_CTRL_IFACE=unix +endif +endif CFLAGS += -DCONFIG_CTRL_IFACE -OBJS += ctrl_iface.o +ifeq ($(CONFIG_CTRL_IFACE), unix) +CFLAGS += -DCONFIG_CTRL_IFACE_UNIX +endif +ifeq ($(CONFIG_CTRL_IFACE), udp) +CFLAGS += -DCONFIG_CTRL_IFACE_UDP +endif +ifeq ($(CONFIG_CTRL_IFACE), named_pipe) +CFLAGS += -DCONFIG_CTRL_IFACE_NAMED_PIPE +endif +OBJS += ctrl_iface.o ctrl_iface_$(CONFIG_CTRL_IFACE).o +endif + +ifdef CONFIG_CTRL_IFACE_DBUS +CFLAGS += -DCONFIG_CTRL_IFACE_DBUS -DDBUS_API_SUBJECT_TO_CHANGE +OBJS += ctrl_iface_dbus.o ctrl_iface_dbus_handlers.o dbus_dict_helpers.o +LIBS += `pkg-config --libs dbus-1` +CFLAGS += `pkg-config --cflags dbus-1` endif ifdef CONFIG_READLINE @@ -381,13 +664,20 @@ LIBS_c += -lncurses -lreadline endif ifdef CONFIG_NATIVE_WINDOWS -CFLAGS += -DCONFIG_NATIVE_WINDOWS -DCONFIG_CTRL_IFACE_UDP +CFLAGS += -DCONFIG_NATIVE_WINDOWS LIBS += -lws2_32 -lgdi32 -lcrypt32 LIBS_c += -lws2_32 +LIBS_p += -lws2_32 +ifeq ($(CONFIG_CRYPTO), cryptoapi) +LIBS_p += -lcrypt32 +endif endif ifdef CONFIG_NO_STDOUT_DEBUG CFLAGS += -DCONFIG_NO_STDOUT_DEBUG +ifndef CONFIG_CTRL_IFACE +CFLAGS += -DCONFIG_NO_WPA_MSG +endif endif ifdef CONFIG_IPV6 @@ -395,53 +685,117 @@ ifdef CONFIG_IPV6 CFLAGS += -DCONFIG_IPV6 endif +ifdef CONFIG_PEERKEY +CFLAGS += -DCONFIG_PEERKEY +endif + +ifdef CONFIG_IEEE80211W +CFLAGS += -DCONFIG_IEEE80211W +NEED_SHA256=y +endif + ifndef CONFIG_NO_WPA -OBJS += wpa.o preauth.o +OBJS += wpa.o preauth.o pmksa_cache.o NEED_AES=y else -CFLAGS += -DCONFIG_NO_WPA +CFLAGS += -DCONFIG_NO_WPA -DCONFIG_NO_WPA2 +endif + +ifdef CONFIG_NO_WPA2 +CFLAGS += -DCONFIG_NO_WPA2 +endif + +ifdef CONFIG_NO_AES_EXTRAS +CFLAGS += -DCONFIG_NO_AES_WRAP +CFLAGS += -DCONFIG_NO_AES_CTR -DCONFIG_NO_AES_OMAC1 +CFLAGS += -DCONFIG_NO_AES_EAX -DCONFIG_NO_AES_CBC endif ifdef NEED_AES OBJS += aes_wrap.o endif +ifdef CONFIG_CLIENT_MLME +OBJS += mlme.o +CFLAGS += -DCONFIG_CLIENT_MLME +endif + +ifndef CONFIG_MAIN +CONFIG_MAIN=main +endif + OBJS += wpa_supplicant.o events.o OBJS_t := $(OBJS) eapol_test.o radius.o radius_client.o OBJS_t2 := $(OBJS) preauth_test.o -OBJS += main.o drivers.o $(OBJS_d) +OBJS += $(CONFIG_MAIN).o drivers.o $(OBJS_d) + +ifdef CONFIG_NDIS_EVENTS_INTEGRATED +CFLAGS += -DCONFIG_NDIS_EVENTS_INTEGRATED +OBJS += ndis_events.o +EXTRALIBS += -loleaut32 -lole32 -luuid +ifdef PLATFORMSDKLIB +EXTRALIBS += $(PLATFORMSDKLIB)/WbemUuid.Lib +else +EXTRALIBS += WbemUuid.Lib +endif +endif + +ifndef LDO +LDO=$(CC) +endif + +dynamic_eap_methods: $(EAPDYN) wpa_supplicant: .config $(OBJS) - $(CC) -o wpa_supplicant $(OBJS) $(LIBS) + $(LDO) $(LDFLAGS) -o wpa_supplicant $(OBJS) $(LIBS) $(EXTRALIBS) eapol_test: .config $(OBJS_t) - $(CC) -o eapol_test $(OBJS_t) $(LIBS) + $(LDO) $(LDFLAGS) -o eapol_test $(OBJS_t) $(LIBS) preauth_test: .config $(OBJS_t2) - $(CC) -o preauth_test $(OBJS_t2) $(LIBS) + $(LDO) $(LDFLAGS) -o preauth_test $(OBJS_t2) $(LIBS) wpa_passphrase: $(OBJS_p) - $(CC) -o wpa_passphrase $(OBJS_p) $(LIBS_p) + $(LDO) $(LDFLAGS) -o wpa_passphrase $(OBJS_p) $(LIBS_p) wpa_cli: $(OBJS_c) - $(CC) -o wpa_cli $(OBJS_c) $(LIBS_c) + $(LDO) $(LDFLAGS) -o wpa_cli $(OBJS_c) $(LIBS_c) + +OBJSa=asn1_test.o asn1.o x509v3.o common.o os_unix.o \ + crypto_$(CONFIG_CRYPTO).o md5.o sha1.o \ + rc4.o des.o aes_wrap.o \ + bignum.o rsa.o +asn1_test: $(OBJSa) + $(LDO) $(LDFLAGS) -o asn1_test $(OBJSa) + +OBJSx=tests/test_x509v3.o asn1.o x509v3.o \ + common.o os_unix.o \ + crypto_$(CONFIG_CRYPTO).o \ + md5.o sha1.o \ + rc4.o des.o aes_wrap.o \ + bignum.o rsa.o +test_x509v3: $(OBJSx) + $(LDO) $(LDFLAGS) -o test_x509v3 $(OBJSx) win_if_list: win_if_list.c - $(CC) -o $@ win_if_list.c $(CFLAGS) $(LIBS_w) - -# parameters for Microsoft Visual C++ Toolkit 2003 compiler -CL=cl -CLDIR=C:\Program Files\Microsoft Visual C++ Toolkit 2003 -PSDKDIR=C:\Program Files\Microsoft Platform SDK for Windows XP SP2 -CLFLAGS=-O -CLLIBS=wbemuuid.lib libcmt.lib kernel32.lib uuid.lib ole32.lib oleaut32.lib \ - ws2_32.lib - -ndis_events: ndis_events.cpp - INCLUDE="$(CLDIR)\include;$(PSDKDIR)\Include" \ - LIB="$(CLDIR)\lib;$(PSDKDIR)\Lib" \ - $(CL) $(CLFLAGS) -o ndis_events.exe ndis_events.cpp \ - /link -nodefaultlib $(CLLIBS) + $(LDO) $(LDFLAGS) -o $@ win_if_list.c $(CFLAGS) $(LIBS_w) + +eap_psk.so: eap_psk.c eap_psk_common.c + $(CC) -o $@ $(CFLAGS) -shared -rdynamic -fPIC $^ \ + -Deap_peer_psk_register=eap_peer_method_dynamic_init + +eap_pax.so: eap_pax.c eap_pax_common.c + $(CC) -o $@ $(CFLAGS) -shared -rdynamic -fPIC $^ \ + -Deap_peer_pax_register=eap_peer_method_dynamic_init + +eap_sake.so: eap_sake.c eap_sake_common.c + $(CC) -o $@ $(CFLAGS) -shared -rdynamic -fPIC $^ \ + -Deap_peer_sake_register=eap_peer_method_dynamic_init + +%.so: %.c + $(CC) -o $@ $(CFLAGS) -shared -rdynamic -fPIC $< \ + -D$(*:eap_%=eap_peer_%)_register=eap_peer_method_dynamic_init + wpa_supplicant.exe: wpa_supplicant mv -f $< $@ @@ -465,39 +819,55 @@ wpa_gui/Makefile: wpa_gui: wpa_gui/Makefile $(MAKE) -C wpa_gui -TEST_SRC_MS_FUNCS = ms_funcs.c crypto.c sha1.c md5.c -test-ms_funcs: $(TEST_SRC_MS_FUNCS) - $(CC) -o test-ms_funcs -Wall -Werror $(TEST_SRC_MS_FUNCS) \ - -DTEST_MAIN_MS_FUNCS -lcrypto -I../hostapd -I. +TEST_MS_FUNCS_OBJS = crypto.o sha1.o md5.o \ + os_unix.o rc4.o tests/test_ms_funcs.o +test-ms_funcs: $(TEST_MS_FUNCS_OBJS) + $(LDO) $(LDFLAGS) -o $@ $(TEST_MS_FUNCS_OBJS) $(LIBS) -lcrypto ./test-ms_funcs rm test-ms_funcs -TEST_SRC_SHA1 = sha1.c -test-sha1: $(TEST_SRC_SHA1) - $(CC) -o test-sha1 -Wall -Werror $(TEST_SRC_SHA1) \ - -DTEST_MAIN -I../hostad -I. +TEST_SHA1_OBJS = sha1.o md5.o tests/test_sha1.o #crypto.o +test-sha1: $(TEST_SHA1_OBJS) + $(LDO) $(LDFLAGS) -o $@ $(TEST_SHA1_OBJS) $(LIBS) ./test-sha1 rm test-sha1 -TEST_SRC_AES_WRAP = aes_wrap.c -test-aes_wrap: $(TEST_SRC_AES_WRAP) - $(CC) -o test-aes_wrap -Wall -Werror $(TEST_SRC_AES_WRAP) \ - -DTEST_MAIN -I../hostad -I. - ./test-aes_wrap - rm test-aes_wrap - -TEST_SRC_EAP_SIM_COMMON = eap_sim_common.c sha1.c md5.c \ - aes_wrap.c common.c -test-eap_sim_common: $(TEST_SRC_EAP_SIM_COMMON) - $(CC) -o test-eap_sim_common -Wall -Werror $(TEST_SRC_EAP_SIM_COMMON) \ - -DTEST_MAIN_EAP_SIM_COMMON -I../hostapd -I. +TEST_SHA256_OBJS = sha256.o md5.o tests/test_sha256.o crypto.o +test-sha256: $(TEST_SHA256_OBJS) + $(LDO) $(LDFLAGS) -o $@ $(TEST_SHA256_OBJS) $(LIBS) + ./test-sha256 + rm test-sha256 + +TEST_AES_OBJS = aes_wrap.o tests/test_aes.o # crypto.o +test-aes: $(TEST_AES_OBJS) + $(LDO) $(LDFLAGS) -o $@ $(TEST_AES_OBJS) $(LIBS) + ./test-aes + rm test-aes + +TEST_EAP_SIM_COMMON_OBJS = sha1.o md5.o \ + aes_wrap.o common.o os_unix.o \ + tests/test_eap_sim_common.o +test-eap_sim_common: $(TEST_EAP_SIM_COMMON_OBJS) + $(LDO) $(LDFLAGS) -o $@ $(TEST_AES_OBJS) $(LIBS) ./test-eap_sim_common rm test-eap_sim_common -tests: test-ms_funcs test-sha1 test-aes_wrap test-eap_sim_common +TEST_MD4_OBJS = md4.o tests/test_md4.o #crypto.o +test-md4: $(TEST_MD4_OBJS) + $(LDO) $(LDFLAGS) -o $@ $(TEST_MD4_OBJS) $(LIBS) + ./test-md4 + rm test-md4 + +TEST_MD5_OBJS = md5.o tests/test_md5.o #crypto.o +test-md5: $(TEST_MD5_OBJS) + $(LDO) $(LDFLAGS) -o $@ $(TEST_MD5_OBJS) $(LIBS) + ./test-md5 + rm test-md5 + +tests: test-ms_funcs test-sha1 test-aes test-eap_sim_common test-md4 test-md5 clean: - rm -f core *~ *.o *.d $(ALL) $(WINALL) + rm -f core *~ *.o *.d eap_*.so $(ALL) $(WINALL) %.eps: %.fig fig2dev -L eps $*.fig $*.eps diff --git a/contrib/wpa_supplicant/README b/contrib/wpa_supplicant/README index 831756b12c25..be0757420efd 100644 --- a/contrib/wpa_supplicant/README +++ b/contrib/wpa_supplicant/README @@ -1,8 +1,7 @@ WPA Supplicant ============== -Copyright (c) 2003-2006, Jouni Malinen <jkmaline@cc.hut.fi> and -contributors +Copyright (c) 2003-2007, Jouni Malinen <j@w1.fi> and contributors All Rights Reserved. This program is dual-licensed under both the GPL version 2 and BSD @@ -26,13 +25,13 @@ GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software -Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA (this copy of the license is in COPYING file) -Alternatively, this software may be distributed under the terms of BSD -license: +Alternatively, this software may be distributed, used, and modified +under the terms of BSD license: Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are @@ -90,6 +89,8 @@ Supported WPA/IEEE 802.11i features: * EAP-AKA * EAP-PSK * EAP-PAX + * EAP-SAKE + * EAP-GPSK * LEAP (note: requires special support from the driver for IEEE 802.11 authentication) (following methods are supported, but since they do not generate keying @@ -103,6 +104,20 @@ Supported WPA/IEEE 802.11i features: * pre-authentication * PMKSA caching +Supported TLS/crypto libraries: +- OpenSSL (default) +- GnuTLS + +Internal TLS/crypto implementation (optional): +- can be used in place of an external TLS/crypto library +- TLSv1 +- X.509 certificate processing +- PKCS #1 +- ASN.1 +- RSA +- bignum +- minimal size (ca. 50 kB binary, parts of which are already needed for WPA; + TLSv1/X.509/ASN.1/RSA/bignum parts are about 25 kB on x86) Requirements @@ -114,6 +129,14 @@ Current hardware/software requirements: - NetBSD-current - Microsoft Windows with WinPcap (at least WinXP, may work with other versions) - drivers: + Linux drivers that support WPA/WPA2 configuration with the generic + Linux wireless extensions (WE-18 or newer). Even though there are + number of driver specific interface included in wpa_supplicant, please + note that Linux drivers are moving to use generic wireless extensions + and driver_wext (-Dwext on wpa_supplicant command line) should be the + default option to start with before falling back to driver specific + interface. + Host AP driver for Prism2/2.5/3 (development snapshot/v0.2.x) (http://hostap.epitest.fi/) Driver need to be set in Managed mode ('iwconfig wlan0 mode managed'). @@ -191,18 +214,27 @@ Optional libraries for layer2 packet processing: These libraries are _not_ used in the default Linux build. Instead, internal Linux specific implementation is used. libpcap/libdnet are -more portable and they can be used by adding CONFIG_DNET_PCAP=y into +more portable and they can be used by adding CONFIG_L2_PACKET=pcap into .config. They may also be selected automatically for other operating -systems. +systems. In case of Windows builds, WinPcap is used by default +(CONFIG_L2_PACKET=winpcap). Optional libraries for EAP-TLS, EAP-PEAP, and EAP-TTLS: -- openssl (tested with 0.9.7c and 0.9.7d, assumed to work with most - relatively recent versions; this is likely to be available with most - distributions, http://www.openssl.org/) - -This library is only needed when EAP-TLS, EAP-PEAP, or EAP-TTLS -support is enabled. WPA-PSK mode does not require this or EAPOL/EAP +- OpenSSL (tested with 0.9.7c and 0.9.7d, and 0.9.8 versions; assumed to + work with most relatively recent versions; this is likely to be + available with most distributions, http://www.openssl.org/) +- GnuTLS +- internal TLSv1 implementation + +TLS options for EAP-FAST: +- OpenSSL 0.9.8d _with_ openssl-0.9.8d-tls-extensions.patch applied + (i.e., the default OpenSSL package does not include support for + extensions needed for EAP-FAST) +- internal TLSv1 implementation + +One of these libraries is needed when EAP-TLS, EAP-PEAP, EAP-TTLS, or +EAP-FAST support is enabled. WPA-PSK mode does not require this or EAPOL/EAP implementation. A configuration file, .config, for compilation is needed to enable IEEE 802.1X/EAPOL and EAP methods. Note that EAP-MD5, EAP-GTC, EAP-OTP, and EAP-MSCHAPV2 cannot be used alone with WPA, so @@ -321,8 +353,8 @@ select which parts of it will be included. This is done by creating a build time configuration file, .config, in the wpa_supplicant root directory. Configuration options are text lines using following format: CONFIG_<option>=y. Lines starting with # are considered -comments and are ignored. See defconfig file for example configuration -and list of available option. +comments and are ignored. See defconfig file for an example configuration +and a list of available options and additional notes. The build time configuration can be used to select only the needed features and limit the binary size and requirements for external @@ -332,8 +364,9 @@ methods (e.g., EAP-TLS, EAP-PEAP, ..) are included. Following build time configuration options are used to control IEEE 802.1X/EAPOL and EAP state machines and all EAP methods. Including -TLS, PEAP, or TTLS will require linking wpa_supplicant with openssl -library for TLS implementation. +TLS, PEAP, or TTLS will require linking wpa_supplicant with OpenSSL +library for TLS implementation. Alternatively, GnuTLS or the internal +TLSv1 implementation can be used for TLS functionaly. CONFIG_IEEE8021X_EAPOL=y CONFIG_EAP_MD5=y @@ -346,6 +379,8 @@ CONFIG_EAP_OTP=y CONFIG_EAP_SIM=y CONFIG_EAP_AKA=y CONFIG_EAP_PSK=y +CONFIG_EAP_SAKE=y +CONFIG_EAP_GPSK=y CONFIG_EAP_PAX=y CONFIG_EAP_LEAP=y @@ -355,11 +390,6 @@ authentication algorithm (for EAP-SIM/EAP-AKA). This requires pcsc-lite CONFIG_PCSC=y -Following option can be used to replace the native Linux packet socket -interface with libpcap/libdnet. - -CONFIG_DNET_PCAP=y - Following options can be added to .config to select which driver interfaces are included. Hermes driver interface needs to be downloaded from Agere (see above). CONFIG_WIRELESS_EXTENSION will be used @@ -402,6 +432,8 @@ CONFIG_EAP_OTP=y CONFIG_EAP_SIM=y CONFIG_EAP_AKA=y CONFIG_EAP_PSK=y +CONFIG_EAP_SAKE=y +CONFIG_EAP_GPSK=y CONFIG_EAP_PAX=y CONFIG_EAP_LEAP=y CONFIG_PCSC=y @@ -449,19 +481,30 @@ Command line options -------------------- usage: - wpa_supplicant [-BddehLqqvw] -i<ifname> -c<config file> [-D<driver>] \ - [-N -i<ifname> -c<conf> [-D<driver>] ...] + wpa_supplicant [-BddehLqqvwW] [-P<pid file>] [-g<global ctrl>] \ + -i<ifname> -c<config file> [-C<ctrl>] [-D<driver>] [-p<driver_param>] \ + [-b<br_ifname> [-N -i<ifname> -c<conf> [-C<ctrl>] [-D<driver>] \ + [-p<driver_param>] [-b<br_ifname>] ...] options: + -b = optional bridge interface name -B = run daemon in the background + -c = Configuration file + -C = ctrl_interface parameter (only used if -c is not) + -i = interface name -d = increase debugging verbosity (-dd even more) + -D = driver name + -g = global ctrl_interface -K = include keys (passwords, etc.) in debug output -t = include timestamp in debug messages -h = show this help text -L = show license (GPL and BSD) + -p = driver parameters + -P = PID file -q = decrease debugging verbosity (-qq even less) -v = show version -w = wait for interface to be added, if needed + -W = wait for a control interface monitor before starting -N = start describing new interface drivers: @@ -473,7 +516,7 @@ drivers: wext = Linux wireless extensions (generic) ndiswrapper = Linux ndiswrapper broadcom = Broadcom wl.o driver - ipw = Intel ipw2100/2200 driver + ipw = Intel ipw2100/2200 driver (old; use wext with Linux 2.6.13 or newer) wired = wpa_supplicant wired Ethernet driver bsd = BSD 802.11 support (Atheros, etc.) ndis = Windows NDIS driver @@ -503,6 +546,13 @@ wpa_supplicant \ -c wpa2.conf -i ath0 -D madwifi +If the interface is added in a Linux bridge (e.g., br0), the bridge +interface needs to be configured to wpa_supplicant in addition to the +main interface: + +wpa_supplicant -cw.conf -Dmadwifi -iath0 -bbr0 + + Configuration file ------------------ @@ -518,7 +568,7 @@ reloading can be triggered with 'wpa_cli reconfigure' command. Configuration file can include one or more network blocks, e.g., one for each used SSID. wpa_supplicant will automatically select the best betwork based on the order of network blocks in the configuration -file, network security level (WPA/WPA2 is prefered), and signal +file, network security level (WPA/WPA2 is preferred), and signal strength. Example configuration files for some common configurations: diff --git a/contrib/wpa_supplicant/aes.c b/contrib/wpa_supplicant/aes.c index ce94778dd62e..1a2459b3e013 100644 --- a/contrib/wpa_supplicant/aes.c +++ b/contrib/wpa_supplicant/aes.c @@ -9,7 +9,7 @@ * cost of reduced throughput (quite small difference on Pentium 4, * 10-25% when using -O1 or -O2 optimization) * - * Copyright (c) 2003-2005, Jouni Malinen <jkmaline@cc.hut.fi> + * Copyright (c) 2003-2005, Jouni Malinen <j@w1.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 @@ -21,6 +21,8 @@ * See README and COPYING for more details. */ +#include "includes.h" + /* * rijndael-alg-fst.c * @@ -1060,7 +1062,7 @@ void * aes_encrypt_init(const u8 *key, size_t len) u32 *rk; if (len != 16) return NULL; - rk = malloc(4 * 44); + rk = os_malloc(4 * 44); if (rk == NULL) return NULL; rijndaelKeySetupEnc(rk, key); @@ -1076,7 +1078,7 @@ void aes_encrypt(void *ctx, const u8 *plain, u8 *crypt) void aes_encrypt_deinit(void *ctx) { - free(ctx); + os_free(ctx); } @@ -1085,7 +1087,7 @@ void * aes_decrypt_init(const u8 *key, size_t len) u32 *rk; if (len != 16) return NULL; - rk = malloc(4 * 44); + rk = os_malloc(4 * 44); if (rk == NULL) return NULL; rijndaelKeySetupDec(rk, key); @@ -1101,5 +1103,5 @@ void aes_decrypt(void *ctx, const u8 *crypt, u8 *plain) void aes_decrypt_deinit(void *ctx) { - free(ctx); + os_free(ctx); } diff --git a/contrib/wpa_supplicant/aes.h b/contrib/wpa_supplicant/aes.h new file mode 100644 index 000000000000..6b9f4147afb1 --- /dev/null +++ b/contrib/wpa_supplicant/aes.h @@ -0,0 +1,25 @@ +/* + * AES functions + * Copyright (c) 2003-2006, Jouni Malinen <j@w1.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. + */ + +#ifndef AES_H +#define AES_H + +void * aes_encrypt_init(const u8 *key, size_t len); +void aes_encrypt(void *ctx, const u8 *plain, u8 *crypt); +void aes_encrypt_deinit(void *ctx); +void * aes_decrypt_init(const u8 *key, size_t len); +void aes_decrypt(void *ctx, const u8 *crypt, u8 *plain); +void aes_decrypt_deinit(void *ctx); + +#endif /* AES_H */ diff --git a/contrib/wpa_supplicant/aes_wrap.c b/contrib/wpa_supplicant/aes_wrap.c index a5925ca2ec47..c52e45af27c5 100644 --- a/contrib/wpa_supplicant/aes_wrap.c +++ b/contrib/wpa_supplicant/aes_wrap.c @@ -7,7 +7,7 @@ * - AES-128 EAX mode encryption/decryption * - AES-128 CBC * - * Copyright (c) 2003-2005, Jouni Malinen <jkmaline@cc.hut.fi> + * Copyright (c) 2003-2005, Jouni Malinen <j@w1.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 @@ -19,17 +19,18 @@ * See README and COPYING for more details. */ -#include <stdlib.h> -#include <stdio.h> -#include <string.h> +#include "includes.h" + #include "common.h" #include "aes_wrap.h" #include "crypto.h" -#ifndef EAP_TLS_FUNCS +#ifdef INTERNAL_AES #include "aes.c" -#endif /* EAP_TLS_FUNCS */ +#endif /* INTERNAL_AES */ + +#ifndef CONFIG_NO_AES_WRAP /** * aes_wrap - Wrap keys with AES Key Wrap Algorithm (128-bit KEK) (RFC3394) @@ -49,8 +50,8 @@ int aes_wrap(const u8 *kek, int n, const u8 *plain, u8 *cipher) r = cipher + 8; /* 1) Initialize variables. */ - memset(a, 0xa6, 8); - memcpy(r, plain, 8 * n); + os_memset(a, 0xa6, 8); + os_memcpy(r, plain, 8 * n); ctx = aes_encrypt_init(kek, 16); if (ctx == NULL) @@ -66,12 +67,12 @@ int aes_wrap(const u8 *kek, int n, const u8 *plain, u8 *cipher) for (j = 0; j <= 5; j++) { r = cipher + 8; for (i = 1; i <= n; i++) { - memcpy(b, a, 8); - memcpy(b + 8, r, 8); + os_memcpy(b, a, 8); + os_memcpy(b + 8, r, 8); aes_encrypt(ctx, b, b); - memcpy(a, b, 8); + os_memcpy(a, b, 8); a[7] ^= n * j + i; - memcpy(r, b + 8, 8); + os_memcpy(r, b + 8, 8); r += 8; } } @@ -86,6 +87,8 @@ int aes_wrap(const u8 *kek, int n, const u8 *plain, u8 *cipher) return 0; } +#endif /* CONFIG_NO_AES_WRAP */ + /** * aes_unwrap - Unwrap key with AES Key Wrap Algorithm (128-bit KEK) (RFC3394) @@ -102,9 +105,9 @@ int aes_unwrap(const u8 *kek, int n, const u8 *cipher, u8 *plain) void *ctx; /* 1) Initialize variables. */ - memcpy(a, cipher, 8); + os_memcpy(a, cipher, 8); r = plain; - memcpy(r, cipher + 8, 8 * n); + os_memcpy(r, cipher + 8, 8 * n); ctx = aes_decrypt_init(kek, 16); if (ctx == NULL) @@ -120,13 +123,13 @@ int aes_unwrap(const u8 *kek, int n, const u8 *cipher, u8 *plain) for (j = 5; j >= 0; j--) { r = plain + (n - 1) * 8; for (i = n; i >= 1; i--) { - memcpy(b, a, 8); + os_memcpy(b, a, 8); b[7] ^= n * j + i; - memcpy(b + 8, r, 8); + os_memcpy(b + 8, r, 8); aes_decrypt(ctx, b, b); - memcpy(a, b, 8); - memcpy(r, b + 8, 8); + os_memcpy(a, b, 8); + os_memcpy(r, b + 8, 8); r -= 8; } } @@ -148,6 +151,8 @@ int aes_unwrap(const u8 *kek, int n, const u8 *cipher, u8 *plain) #define BLOCK_SIZE 16 +#ifndef CONFIG_NO_AES_OMAC1 + static void gf_mulx(u8 *pad) { int i, carry; @@ -162,8 +167,8 @@ static void gf_mulx(u8 *pad) /** - * omac1_aes_128 - One-Key CBC MAC (OMAC1) hash with AES-128 - * @key: Key for the hash operation + * omac1_aes_128 - One-Key CBC MAC (OMAC1) hash with AES-128 (aka AES-CMAC) + * @key: 128-bit key for the hash operation * @data: Data buffer for which a MAC is determined * @data: Length of data buffer in bytes * @mac: Buffer for MAC (128 bits, i.e., 16 bytes) @@ -174,13 +179,12 @@ int omac1_aes_128(const u8 *key, const u8 *data, size_t data_len, u8 *mac) void *ctx; u8 cbc[BLOCK_SIZE], pad[BLOCK_SIZE]; const u8 *pos = data; - int i; - size_t left = data_len; + size_t i, left = data_len; ctx = aes_encrypt_init(key, 16); if (ctx == NULL) return -1; - memset(cbc, 0, BLOCK_SIZE); + os_memset(cbc, 0, BLOCK_SIZE); while (left >= BLOCK_SIZE) { for (i = 0; i < BLOCK_SIZE; i++) @@ -190,7 +194,7 @@ int omac1_aes_128(const u8 *key, const u8 *data, size_t data_len, u8 *mac) left -= BLOCK_SIZE; } - memset(pad, 0, BLOCK_SIZE); + os_memset(pad, 0, BLOCK_SIZE); aes_encrypt(ctx, pad, pad); gf_mulx(pad); @@ -208,6 +212,8 @@ int omac1_aes_128(const u8 *key, const u8 *data, size_t data_len, u8 *mac) return 0; } +#endif /* CONFIG_NO_AES_OMAC1 */ + /** * aes_128_encrypt_block - Perform one AES 128-bit block operation @@ -228,6 +234,8 @@ int aes_128_encrypt_block(const u8 *key, const u8 *in, u8 *out) } +#ifndef CONFIG_NO_AES_CTR + /** * aes_128_ctr_encrypt - AES-128 CTR mode encryption * @key: Key for encryption (16 bytes) @@ -240,7 +248,7 @@ int aes_128_ctr_encrypt(const u8 *key, const u8 *nonce, u8 *data, size_t data_len) { void *ctx; - size_t len, left = data_len; + size_t j, len, left = data_len; int i; u8 *pos = data; u8 counter[BLOCK_SIZE], buf[BLOCK_SIZE]; @@ -248,14 +256,14 @@ int aes_128_ctr_encrypt(const u8 *key, const u8 *nonce, ctx = aes_encrypt_init(key, 16); if (ctx == NULL) return -1; - memcpy(counter, nonce, BLOCK_SIZE); + os_memcpy(counter, nonce, BLOCK_SIZE); while (left > 0) { aes_encrypt(ctx, counter, buf); len = (left < BLOCK_SIZE) ? left : BLOCK_SIZE; - for (i = 0; i < len; i++) - pos[i] ^= buf[i]; + for (j = 0; j < len; j++) + pos[j] ^= buf[j]; pos += len; left -= len; @@ -269,6 +277,10 @@ int aes_128_ctr_encrypt(const u8 *key, const u8 *nonce, return 0; } +#endif /* CONFIG_NO_AES_CTR */ + + +#ifndef CONFIG_NO_AES_EAX /** * aes_128_eax_encrypt - AES-128 EAX mode encryption @@ -299,26 +311,26 @@ int aes_128_eax_encrypt(const u8 *key, const u8 *nonce, size_t nonce_len, buf_len = hdr_len; buf_len += 16; - buf = malloc(buf_len); + buf = os_malloc(buf_len); if (buf == NULL) return -1; - memset(buf, 0, 15); + os_memset(buf, 0, 15); buf[15] = 0; - memcpy(buf + 16, nonce, nonce_len); + os_memcpy(buf + 16, nonce, nonce_len); omac1_aes_128(key, buf, 16 + nonce_len, nonce_mac); buf[15] = 1; - memcpy(buf + 16, hdr, hdr_len); + os_memcpy(buf + 16, hdr, hdr_len); omac1_aes_128(key, buf, 16 + hdr_len, hdr_mac); aes_128_ctr_encrypt(key, nonce_mac, data, data_len); buf[15] = 2; - memcpy(buf + 16, data, data_len); + os_memcpy(buf + 16, data, data_len); omac1_aes_128(key, buf, 16 + data_len, data_mac); - free(buf); + os_free(buf); for (i = 0; i < BLOCK_SIZE; i++) tag[i] = nonce_mac[i] ^ data_mac[i] ^ hdr_mac[i]; @@ -356,25 +368,25 @@ int aes_128_eax_decrypt(const u8 *key, const u8 *nonce, size_t nonce_len, buf_len = hdr_len; buf_len += 16; - buf = malloc(buf_len); + buf = os_malloc(buf_len); if (buf == NULL) return -1; - memset(buf, 0, 15); + os_memset(buf, 0, 15); buf[15] = 0; - memcpy(buf + 16, nonce, nonce_len); + os_memcpy(buf + 16, nonce, nonce_len); omac1_aes_128(key, buf, 16 + nonce_len, nonce_mac); buf[15] = 1; - memcpy(buf + 16, hdr, hdr_len); + os_memcpy(buf + 16, hdr, hdr_len); omac1_aes_128(key, buf, 16 + hdr_len, hdr_mac); buf[15] = 2; - memcpy(buf + 16, data, data_len); + os_memcpy(buf + 16, data, data_len); omac1_aes_128(key, buf, 16 + data_len, data_mac); - free(buf); + os_free(buf); for (i = 0; i < BLOCK_SIZE; i++) { if (tag[i] != (nonce_mac[i] ^ data_mac[i] ^ hdr_mac[i])) @@ -386,6 +398,10 @@ int aes_128_eax_decrypt(const u8 *key, const u8 *nonce, size_t nonce_len, return 0; } +#endif /* CONFIG_NO_AES_EAX */ + + +#ifndef CONFIG_NO_AES_CBC /** * aes_128_cbc_encrypt - AES-128 CBC encryption @@ -405,14 +421,14 @@ int aes_128_cbc_encrypt(const u8 *key, const u8 *iv, u8 *data, size_t data_len) ctx = aes_encrypt_init(key, 16); if (ctx == NULL) return -1; - memcpy(cbc, iv, BLOCK_SIZE); + os_memcpy(cbc, iv, BLOCK_SIZE); blocks = data_len / BLOCK_SIZE; for (i = 0; i < blocks; i++) { for (j = 0; j < BLOCK_SIZE; j++) cbc[j] ^= pos[j]; aes_encrypt(ctx, cbc, cbc); - memcpy(pos, cbc, BLOCK_SIZE); + os_memcpy(pos, cbc, BLOCK_SIZE); pos += BLOCK_SIZE; } aes_encrypt_deinit(ctx); @@ -438,288 +454,19 @@ int aes_128_cbc_decrypt(const u8 *key, const u8 *iv, u8 *data, size_t data_len) ctx = aes_decrypt_init(key, 16); if (ctx == NULL) return -1; - memcpy(cbc, iv, BLOCK_SIZE); + os_memcpy(cbc, iv, BLOCK_SIZE); blocks = data_len / BLOCK_SIZE; for (i = 0; i < blocks; i++) { - memcpy(tmp, pos, BLOCK_SIZE); + os_memcpy(tmp, pos, BLOCK_SIZE); aes_decrypt(ctx, pos, pos); for (j = 0; j < BLOCK_SIZE; j++) pos[j] ^= cbc[j]; - memcpy(cbc, tmp, BLOCK_SIZE); + os_memcpy(cbc, tmp, BLOCK_SIZE); pos += BLOCK_SIZE; } aes_decrypt_deinit(ctx); return 0; } - -#ifdef TEST_MAIN - -#ifdef __i386__ -#define rdtscll(val) \ - __asm__ __volatile__("rdtsc" : "=A" (val)) - -static void test_aes_perf(void) -{ - const int num_iters = 10; - int i; - unsigned int start, end; - u8 key[16], pt[16], ct[16]; - void *ctx; - - printf("keySetupEnc:"); - for (i = 0; i < num_iters; i++) { - rdtscll(start); - ctx = aes_encrypt_init(key, 16); - rdtscll(end); - aes_encrypt_deinit(ctx); - printf(" %d", end - start); - } - printf("\n"); - - printf("Encrypt:"); - ctx = aes_encrypt_init(key, 16); - for (i = 0; i < num_iters; i++) { - rdtscll(start); - aes_encrypt(ctx, pt, ct); - rdtscll(end); - printf(" %d", end - start); - } - aes_encrypt_deinit(ctx); - printf("\n"); -} -#endif /* __i386__ */ - - -static int test_eax(void) -{ - u8 msg[] = { 0xF7, 0xFB }; - u8 key[] = { 0x91, 0x94, 0x5D, 0x3F, 0x4D, 0xCB, 0xEE, 0x0B, - 0xF4, 0x5E, 0xF5, 0x22, 0x55, 0xF0, 0x95, 0xA4 }; - u8 nonce[] = { 0xBE, 0xCA, 0xF0, 0x43, 0xB0, 0xA2, 0x3D, 0x84, - 0x31, 0x94, 0xBA, 0x97, 0x2C, 0x66, 0xDE, 0xBD }; - u8 hdr[] = { 0xFA, 0x3B, 0xFD, 0x48, 0x06, 0xEB, 0x53, 0xFA }; - u8 cipher[] = { 0x19, 0xDD, 0x5C, 0x4C, 0x93, 0x31, 0x04, 0x9D, - 0x0B, 0xDA, 0xB0, 0x27, 0x74, 0x08, 0xF6, 0x79, - 0x67, 0xE5 }; - u8 data[sizeof(msg)], tag[BLOCK_SIZE]; - - memcpy(data, msg, sizeof(msg)); - if (aes_128_eax_encrypt(key, nonce, sizeof(nonce), hdr, sizeof(hdr), - data, sizeof(data), tag)) { - printf("AES-128 EAX mode encryption failed\n"); - return 1; - } - if (memcmp(data, cipher, sizeof(data)) != 0) { - printf("AES-128 EAX mode encryption returned invalid cipher " - "text\n"); - return 1; - } - if (memcmp(tag, cipher + sizeof(data), BLOCK_SIZE) != 0) { - printf("AES-128 EAX mode encryption returned invalid tag\n"); - return 1; - } - - if (aes_128_eax_decrypt(key, nonce, sizeof(nonce), hdr, sizeof(hdr), - data, sizeof(data), tag)) { - printf("AES-128 EAX mode decryption failed\n"); - return 1; - } - if (memcmp(data, msg, sizeof(data)) != 0) { - printf("AES-128 EAX mode decryption returned invalid plain " - "text\n"); - return 1; - } - - return 0; -} - - -static int test_cbc(void) -{ - struct cbc_test_vector { - u8 key[16]; - u8 iv[16]; - u8 plain[32]; - u8 cipher[32]; - size_t len; - } vectors[] = { - { - { 0x06, 0xa9, 0x21, 0x40, 0x36, 0xb8, 0xa1, 0x5b, - 0x51, 0x2e, 0x03, 0xd5, 0x34, 0x12, 0x00, 0x06 }, - { 0x3d, 0xaf, 0xba, 0x42, 0x9d, 0x9e, 0xb4, 0x30, - 0xb4, 0x22, 0xda, 0x80, 0x2c, 0x9f, 0xac, 0x41 }, - "Single block msg", - { 0xe3, 0x53, 0x77, 0x9c, 0x10, 0x79, 0xae, 0xb8, - 0x27, 0x08, 0x94, 0x2d, 0xbe, 0x77, 0x18, 0x1a }, - 16 - }, - { - { 0xc2, 0x86, 0x69, 0x6d, 0x88, 0x7c, 0x9a, 0xa0, - 0x61, 0x1b, 0xbb, 0x3e, 0x20, 0x25, 0xa4, 0x5a }, - { 0x56, 0x2e, 0x17, 0x99, 0x6d, 0x09, 0x3d, 0x28, - 0xdd, 0xb3, 0xba, 0x69, 0x5a, 0x2e, 0x6f, 0x58 }, - { 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, - 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, - 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, - 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f }, - { 0xd2, 0x96, 0xcd, 0x94, 0xc2, 0xcc, 0xcf, 0x8a, - 0x3a, 0x86, 0x30, 0x28, 0xb5, 0xe1, 0xdc, 0x0a, - 0x75, 0x86, 0x60, 0x2d, 0x25, 0x3c, 0xff, 0xf9, - 0x1b, 0x82, 0x66, 0xbe, 0xa6, 0xd6, 0x1a, 0xb1 }, - 32 - } - }; - int i, ret = 0; - u8 *buf; - - for (i = 0; i < sizeof(vectors) / sizeof(vectors[0]); i++) { - struct cbc_test_vector *tv = &vectors[i]; - buf = malloc(tv->len); - if (buf == NULL) { - ret++; - break; - } - memcpy(buf, tv->plain, tv->len); - aes_128_cbc_encrypt(tv->key, tv->iv, buf, tv->len); - if (memcmp(buf, tv->cipher, tv->len) != 0) { - printf("AES-CBC encrypt %d failed\n", i); - ret++; - } - memcpy(buf, tv->cipher, tv->len); - aes_128_cbc_decrypt(tv->key, tv->iv, buf, tv->len); - if (memcmp(buf, tv->plain, tv->len) != 0) { - printf("AES-CBC decrypt %d failed\n", i); - ret++; - } - free(buf); - } - - return ret; -} - - -/* OMAC1 AES-128 test vectors from - * http://csrc.nist.gov/CryptoToolkit/modes/proposedmodes/omac/omac-ad.pdf - */ - -struct omac1_test_vector { - u8 k[16]; - u8 msg[64]; - int msg_len; - u8 tag[16]; -}; - -static struct omac1_test_vector test_vectors[] = -{ - { - { 0x2b, 0x7e, 0x15, 0x16, 0x28, 0xae, 0xd2, 0xa6, - 0xab, 0xf7, 0x15, 0x88, 0x09, 0xcf, 0x4f, 0x3c }, - { }, - 0, - { 0xbb, 0x1d, 0x69, 0x29, 0xe9, 0x59, 0x37, 0x28, - 0x7f, 0xa3, 0x7d, 0x12, 0x9b, 0x75, 0x67, 0x46 } - }, - { - { 0x2b, 0x7e, 0x15, 0x16, 0x28, 0xae, 0xd2, 0xa6, - 0xab, 0xf7, 0x15, 0x88, 0x09, 0xcf, 0x4f, 0x3c }, - { 0x6b, 0xc1, 0xbe, 0xe2, 0x2e, 0x40, 0x9f, 0x96, - 0xe9, 0x3d, 0x7e, 0x11, 0x73, 0x93, 0x17, 0x2a}, - 16, - { 0x07, 0x0a, 0x16, 0xb4, 0x6b, 0x4d, 0x41, 0x44, - 0xf7, 0x9b, 0xdd, 0x9d, 0xd0, 0x4a, 0x28, 0x7c } - }, - { - { 0x2b, 0x7e, 0x15, 0x16, 0x28, 0xae, 0xd2, 0xa6, - 0xab, 0xf7, 0x15, 0x88, 0x09, 0xcf, 0x4f, 0x3c }, - { 0x6b, 0xc1, 0xbe, 0xe2, 0x2e, 0x40, 0x9f, 0x96, - 0xe9, 0x3d, 0x7e, 0x11, 0x73, 0x93, 0x17, 0x2a, - 0xae, 0x2d, 0x8a, 0x57, 0x1e, 0x03, 0xac, 0x9c, - 0x9e, 0xb7, 0x6f, 0xac, 0x45, 0xaf, 0x8e, 0x51, - 0x30, 0xc8, 0x1c, 0x46, 0xa3, 0x5c, 0xe4, 0x11 }, - 40, - { 0xdf, 0xa6, 0x67, 0x47, 0xde, 0x9a, 0xe6, 0x30, - 0x30, 0xca, 0x32, 0x61, 0x14, 0x97, 0xc8, 0x27 } - }, - { - { 0x2b, 0x7e, 0x15, 0x16, 0x28, 0xae, 0xd2, 0xa6, - 0xab, 0xf7, 0x15, 0x88, 0x09, 0xcf, 0x4f, 0x3c }, - { 0x6b, 0xc1, 0xbe, 0xe2, 0x2e, 0x40, 0x9f, 0x96, - 0xe9, 0x3d, 0x7e, 0x11, 0x73, 0x93, 0x17, 0x2a, - 0xae, 0x2d, 0x8a, 0x57, 0x1e, 0x03, 0xac, 0x9c, - 0x9e, 0xb7, 0x6f, 0xac, 0x45, 0xaf, 0x8e, 0x51, - 0x30, 0xc8, 0x1c, 0x46, 0xa3, 0x5c, 0xe4, 0x11, - 0xe5, 0xfb, 0xc1, 0x19, 0x1a, 0x0a, 0x52, 0xef, - 0xf6, 0x9f, 0x24, 0x45, 0xdf, 0x4f, 0x9b, 0x17, - 0xad, 0x2b, 0x41, 0x7b, 0xe6, 0x6c, 0x37, 0x10 }, - 64, - { 0x51, 0xf0, 0xbe, 0xbf, 0x7e, 0x3b, 0x9d, 0x92, - 0xfc, 0x49, 0x74, 0x17, 0x79, 0x36, 0x3c, 0xfe } - }, -}; - - -int main(int argc, char *argv[]) -{ - u8 kek[] = { - 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, - 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f - }; - u8 plain[] = { - 0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, - 0x88, 0x99, 0xaa, 0xbb, 0xcc, 0xdd, 0xee, 0xff - }; - u8 crypt[] = { - 0x1F, 0xA6, 0x8B, 0x0A, 0x81, 0x12, 0xB4, 0x47, - 0xAE, 0xF3, 0x4B, 0xD8, 0xFB, 0x5A, 0x7B, 0x82, - 0x9D, 0x3E, 0x86, 0x23, 0x71, 0xD2, 0xCF, 0xE5 - }; - u8 result[24]; - int ret = 0, i; - struct omac1_test_vector *tv; - - if (aes_wrap(kek, 2, plain, result)) { - printf("AES-WRAP-128-128 reported failure\n"); - ret++; - } - if (memcmp(result, crypt, 24) != 0) { - printf("AES-WRAP-128-128 failed\n"); - ret++; - } - if (aes_unwrap(kek, 2, crypt, result)) { - printf("AES-UNWRAP-128-128 reported failure\n"); - ret++; - } - if (memcmp(result, plain, 16) != 0) { - int i; - printf("AES-UNWRAP-128-128 failed\n"); - ret++; - for (i = 0; i < 16; i++) - printf(" %02x", result[i]); - printf("\n"); - } - -#ifdef __i386__ - test_aes_perf(); -#endif /* __i386__ */ - - for (i = 0; i < sizeof(test_vectors) / sizeof(test_vectors[0]); i++) { - tv = &test_vectors[i]; - omac1_aes_128(tv->k, tv->msg, tv->msg_len, result); - if (memcmp(result, tv->tag, 16) != 0) { - printf("OMAC1-AES-128 test vector %d failed\n", i); - ret++; - } - } - - ret += test_eax(); - - ret += test_cbc(); - - if (ret) - printf("FAILED!\n"); - - return ret; -} -#endif /* TEST_MAIN */ +#endif /* CONFIG_NO_AES_CBC */ diff --git a/contrib/wpa_supplicant/aes_wrap.h b/contrib/wpa_supplicant/aes_wrap.h index cb1a53967761..1bc6971eff8e 100644 --- a/contrib/wpa_supplicant/aes_wrap.h +++ b/contrib/wpa_supplicant/aes_wrap.h @@ -7,7 +7,7 @@ * - AES-128 EAX mode encryption/decryption * - AES-128 CBC * - * Copyright (c) 2003-2005, Jouni Malinen <jkmaline@cc.hut.fi> + * Copyright (c) 2003-2005, Jouni Malinen <j@w1.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 diff --git a/contrib/wpa_supplicant/asn1.c b/contrib/wpa_supplicant/asn1.c new file mode 100644 index 000000000000..ff3db7dc73c0 --- /dev/null +++ b/contrib/wpa_supplicant/asn1.c @@ -0,0 +1,205 @@ +/* + * ASN.1 DER parsing + * Copyright (c) 2006, Jouni Malinen <j@w1.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 "includes.h" + +#include "common.h" + +#ifdef CONFIG_INTERNAL_X509 + +#include "asn1.h" + +int asn1_get_next(const u8 *buf, size_t len, struct asn1_hdr *hdr) +{ + const u8 *pos, *end; + u8 tmp; + + os_memset(hdr, 0, sizeof(*hdr)); + pos = buf; + end = buf + len; + + hdr->identifier = *pos++; + hdr->class = hdr->identifier >> 6; + hdr->constructed = !!(hdr->identifier & (1 << 5)); + + if ((hdr->identifier & 0x1f) == 0x1f) { + hdr->tag = 0; + do { + if (pos >= end) { + wpa_printf(MSG_DEBUG, "ASN.1: Identifier " + "underflow"); + return -1; + } + tmp = *pos++; + wpa_printf(MSG_MSGDUMP, "ASN.1: Extended tag data: " + "0x%02x", tmp); + hdr->tag = (hdr->tag << 7) | (tmp & 0x7f); + } while (tmp & 0x80); + } else + hdr->tag = hdr->identifier & 0x1f; + + tmp = *pos++; + if (tmp & 0x80) { + if (tmp == 0xff) { + wpa_printf(MSG_DEBUG, "ASN.1: Reserved length " + "value 0xff used"); + return -1; + } + tmp &= 0x7f; /* number of subsequent octets */ + hdr->length = 0; + while (tmp--) { + if (pos >= end) { + wpa_printf(MSG_DEBUG, "ASN.1: Length " + "underflow"); + return -1; + } + hdr->length = (hdr->length << 8) | *pos++; + } + } else { + /* Short form - length 0..127 in one octet */ + hdr->length = tmp; + } + + if (pos + hdr->length > end) { + wpa_printf(MSG_DEBUG, "ASN.1: Contents underflow"); + return -1; + } + + hdr->payload = pos; + return 0; +} + + +int asn1_get_oid(const u8 *buf, size_t len, struct asn1_oid *oid, + const u8 **next) +{ + struct asn1_hdr hdr; + const u8 *pos, *end; + unsigned long val; + u8 tmp; + + os_memset(oid, 0, sizeof(*oid)); + + if (asn1_get_next(buf, len, &hdr) < 0 || hdr.length == 0) + return -1; + + if (hdr.class != ASN1_CLASS_UNIVERSAL || hdr.tag != ASN1_TAG_OID) { + wpa_printf(MSG_DEBUG, "ASN.1: Expected OID - found class %d " + "tag 0x%x", hdr.class, hdr.tag); + return -1; + } + + pos = hdr.payload; + end = hdr.payload + hdr.length; + *next = end; + + while (pos < end) { + val = 0; + + do { + if (pos >= end) + return -1; + tmp = *pos++; + val = (val << 7) | (tmp & 0x7f); + } while (tmp & 0x80); + + if (oid->len >= ASN1_MAX_OID_LEN) { + wpa_printf(MSG_DEBUG, "ASN.1: Too long OID value"); + return -1; + } + if (oid->len == 0) { + /* + * The first octet encodes the first two object + * identifier components in (X*40) + Y formula. + * X = 0..2. + */ + oid->oid[0] = val / 40; + if (oid->oid[0] > 2) + oid->oid[0] = 2; + oid->oid[1] = val - oid->oid[0] * 40; + oid->len = 2; + } else + oid->oid[oid->len++] = val; + } + + return 0; +} + + +void asn1_oid_to_str(struct asn1_oid *oid, char *buf, size_t len) +{ + char *pos = buf; + size_t i; + int ret; + + if (len == 0) + return; + + buf[0] = '\0'; + + for (i = 0; i < oid->len; i++) { + ret = os_snprintf(pos, buf + len - pos, + "%s%lu", + i == 0 ? "" : ".", oid->oid[i]); + if (ret < 0 || ret >= buf + len - pos) + break; + pos += ret; + } + buf[len - 1] = '\0'; +} + + +static u8 rotate_bits(u8 octet) +{ + int i; + u8 res; + + res = 0; + for (i = 0; i < 8; i++) { + res <<= 1; + if (octet & 1) + res |= 1; + octet >>= 1; + } + + return res; +} + + +unsigned long asn1_bit_string_to_long(const u8 *buf, size_t len) +{ + unsigned long val = 0; + const u8 *pos = buf; + + /* BER requires that unused bits are zero, so we can ignore the number + * of unused bits */ + pos++; + + if (len >= 2) + val |= rotate_bits(*pos++); + if (len >= 3) + val |= ((unsigned long) rotate_bits(*pos++)) << 8; + if (len >= 4) + val |= ((unsigned long) rotate_bits(*pos++)) << 16; + if (len >= 5) + val |= ((unsigned long) rotate_bits(*pos++)) << 24; + if (len >= 6) + wpa_printf(MSG_DEBUG, "X509: %s - some bits ignored " + "(BIT STRING length %lu)", + __func__, (unsigned long) len); + + return val; +} + +#endif /* CONFIG_INTERNAL_X509 */ diff --git a/contrib/wpa_supplicant/asn1.h b/contrib/wpa_supplicant/asn1.h new file mode 100644 index 000000000000..c02ada8278a2 --- /dev/null +++ b/contrib/wpa_supplicant/asn1.h @@ -0,0 +1,71 @@ +/* + * ASN.1 DER parsing + * Copyright (c) 2006, Jouni Malinen <j@w1.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. + */ + +#ifndef ASN1_H +#define ASN1_H + +#define ASN1_TAG_EOC 0x00 /* not used with DER */ +#define ASN1_TAG_BOOLEAN 0x01 +#define ASN1_TAG_INTEGER 0x02 +#define ASN1_TAG_BITSTRING 0x03 +#define ASN1_TAG_OCTETSTRING 0x04 +#define ASN1_TAG_NULL 0x05 +#define ASN1_TAG_OID 0x06 +#define ASN1_TAG_OBJECT_DESCRIPTOR 0x07 /* not yet parsed */ +#define ASN1_TAG_EXTERNAL 0x08 /* not yet parsed */ +#define ASN1_TAG_REAL 0x09 /* not yet parsed */ +#define ASN1_TAG_ENUMERATED 0x0A /* not yet parsed */ +#define ASN1_TAG_UTF8STRING 0x0C /* not yet parsed */ +#define ANS1_TAG_RELATIVE_OID 0x0D +#define ASN1_TAG_SEQUENCE 0x10 /* shall be constructed */ +#define ASN1_TAG_SET 0x11 +#define ASN1_TAG_NUMERICSTRING 0x12 /* not yet parsed */ +#define ASN1_TAG_PRINTABLESTRING 0x13 +#define ASN1_TAG_TG1STRING 0x14 /* not yet parsed */ +#define ASN1_TAG_VIDEOTEXSTRING 0x15 /* not yet parsed */ +#define ASN1_TAG_IA5STRING 0x16 +#define ASN1_TAG_UTCTIME 0x17 +#define ASN1_TAG_GENERALIZEDTIME 0x18 /* not yet parsed */ +#define ASN1_TAG_GRAPHICSTRING 0x19 /* not yet parsed */ +#define ASN1_TAG_VISIBLESTRING 0x1A +#define ASN1_TAG_GENERALSTRING 0x1B /* not yet parsed */ +#define ASN1_TAG_UNIVERSALSTRING 0x1C /* not yet parsed */ +#define ASN1_TAG_BMPSTRING 0x1D /* not yet parsed */ + +#define ASN1_CLASS_UNIVERSAL 0 +#define ASN1_CLASS_APPLICATION 1 +#define ASN1_CLASS_CONTEXT_SPECIFIC 2 +#define ASN1_CLASS_PRIVATE 3 + + +struct asn1_hdr { + const u8 *payload; + u8 identifier, class, constructed; + unsigned int tag, length; +}; + +#define ASN1_MAX_OID_LEN 20 +struct asn1_oid { + unsigned long oid[ASN1_MAX_OID_LEN]; + size_t len; +}; + + +int asn1_get_next(const u8 *buf, size_t len, struct asn1_hdr *hdr); +int asn1_get_oid(const u8 *buf, size_t len, struct asn1_oid *oid, + const u8 **next); +void asn1_oid_to_str(struct asn1_oid *oid, char *buf, size_t len); +unsigned long asn1_bit_string_to_long(const u8 *buf, size_t len); + +#endif /* ASN1_H */ diff --git a/contrib/wpa_supplicant/asn1_test.c b/contrib/wpa_supplicant/asn1_test.c new file mode 100644 index 000000000000..a5c77535309f --- /dev/null +++ b/contrib/wpa_supplicant/asn1_test.c @@ -0,0 +1,210 @@ +/* + * Testing tool for ASN.1/X.509v3 routines + * Copyright (c) 2006, Jouni Malinen <j@w1.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 "includes.h" + +#include "common.h" +#include "asn1.h" +#include "x509v3.h" + +extern int wpa_debug_level; + + +static const char * asn1_class_str(int class) +{ + switch (class) { + case ASN1_CLASS_UNIVERSAL: + return "Universal"; + case ASN1_CLASS_APPLICATION: + return "Application"; + case ASN1_CLASS_CONTEXT_SPECIFIC: + return "Context-specific"; + case ASN1_CLASS_PRIVATE: + return "Private"; + default: + return "?"; + } +} + + +int asn1_parse(const u8 *buf, size_t len, int level) +{ + const u8 *pos, *prev, *end; + char prefix[10], str[100]; + int _level; + struct asn1_hdr hdr; + struct asn1_oid oid; + u8 tmp; + + _level = level; + if ((size_t) _level > sizeof(prefix) - 1) + _level = sizeof(prefix) - 1; + memset(prefix, ' ', _level); + prefix[_level] = '\0'; + + pos = buf; + end = buf + len; + + while (pos < end) { + if (asn1_get_next(pos, end - pos, &hdr) < 0) + return -1; + + prev = pos; + pos = hdr.payload; + + wpa_printf(MSG_MSGDUMP, "ASN.1:%s Class %d(%s) P/C %d(%s) " + "Tag %u Length %u", + prefix, hdr.class, asn1_class_str(hdr.class), + hdr.constructed, + hdr.constructed ? "Constructed" : "Primitive", + hdr.tag, hdr.length); + + if (hdr.class == ASN1_CLASS_CONTEXT_SPECIFIC && + hdr.constructed) { + if (asn1_parse(pos, hdr.length, level + 1) < 0) + return -1; + pos += hdr.length; + } + + if (hdr.class != ASN1_CLASS_UNIVERSAL) + continue; + + switch (hdr.tag) { + case ASN1_TAG_EOC: + if (hdr.length) { + wpa_printf(MSG_DEBUG, "ASN.1: Non-zero " + "end-of-contents length (%u)", + hdr.length); + return -1; + } + wpa_printf(MSG_MSGDUMP, "ASN.1:%s EOC", prefix); + break; + case ASN1_TAG_BOOLEAN: + if (hdr.length != 1) { + wpa_printf(MSG_DEBUG, "ASN.1: Unexpected " + "Boolean length (%u)", hdr.length); + return -1; + } + tmp = *pos++; + wpa_printf(MSG_MSGDUMP, "ASN.1:%s Boolean %s", + prefix, tmp ? "TRUE" : "FALSE"); + break; + case ASN1_TAG_INTEGER: + wpa_hexdump(MSG_MSGDUMP, "ASN.1: INTEGER", + pos, hdr.length); + pos += hdr.length; + break; + case ASN1_TAG_BITSTRING: + wpa_hexdump(MSG_MSGDUMP, "ASN.1: BitString", + pos, hdr.length); + pos += hdr.length; + break; + case ASN1_TAG_OCTETSTRING: + wpa_hexdump(MSG_MSGDUMP, "ASN.1: OctetString", + pos, hdr.length); + pos += hdr.length; + break; + case ASN1_TAG_NULL: + if (hdr.length) { + wpa_printf(MSG_DEBUG, "ASN.1: Non-zero Null " + "length (%u)", hdr.length); + return -1; + } + wpa_printf(MSG_MSGDUMP, "ASN.1:%s Null", prefix); + break; + case ASN1_TAG_OID: + if (asn1_get_oid(prev, end - prev, &oid, &prev) < 0) { + wpa_printf(MSG_DEBUG, "ASN.1: Invalid OID"); + return -1; + } + asn1_oid_to_str(&oid, str, sizeof(str)); + wpa_printf(MSG_DEBUG, "ASN.1:%s OID %s", prefix, str); + pos += hdr.length; + break; + case ANS1_TAG_RELATIVE_OID: + wpa_hexdump(MSG_MSGDUMP, "ASN.1: Relative OID", + pos, hdr.length); + pos += hdr.length; + break; + case ASN1_TAG_SEQUENCE: + wpa_printf(MSG_MSGDUMP, "ASN.1:%s SEQUENCE", prefix); + if (asn1_parse(pos, hdr.length, level + 1) < 0) + return -1; + pos += hdr.length; + break; + case ASN1_TAG_SET: + wpa_printf(MSG_MSGDUMP, "ASN.1:%s SET", prefix); + if (asn1_parse(pos, hdr.length, level + 1) < 0) + return -1; + pos += hdr.length; + break; + case ASN1_TAG_PRINTABLESTRING: + wpa_hexdump_ascii(MSG_MSGDUMP, + "ASN.1: PrintableString", + pos, hdr.length); + pos += hdr.length; + break; + case ASN1_TAG_IA5STRING: + wpa_hexdump_ascii(MSG_MSGDUMP, "ASN.1: IA5String", + pos, hdr.length); + pos += hdr.length; + break; + case ASN1_TAG_UTCTIME: + wpa_hexdump_ascii(MSG_MSGDUMP, "ASN.1: UTCTIME", + pos, hdr.length); + pos += hdr.length; + break; + case ASN1_TAG_VISIBLESTRING: + wpa_hexdump_ascii(MSG_MSGDUMP, "ASN.1: VisibleString", + pos, hdr.length); + pos += hdr.length; + break; + default: + wpa_printf(MSG_DEBUG, "ASN.1: Unknown tag %d", + hdr.tag); + return -1; + } + } + + return 0; +} + + +int main(int argc, char *argv[]) +{ + FILE *f; + u8 buf[3000]; + size_t len; + struct x509_certificate *cert; + + wpa_debug_level = 0; + + f = fopen(argv[1], "rb"); + if (f == NULL) + return -1; + len = fread(buf, 1, sizeof(buf), f); + fclose(f); + + if (asn1_parse(buf, len, 0) < 0) + printf("Failed to parse DER ASN.1\n"); + + printf("\n\n"); + + cert = x509_certificate_parse(buf, len); + if (cert == NULL) + printf("Failed to parse X.509 certificate\n"); + x509_certificate_free(cert); + + return 0; +} diff --git a/contrib/wpa_supplicant/base64.c b/contrib/wpa_supplicant/base64.c index 2717e30c6980..0c33e5881b64 100644 --- a/contrib/wpa_supplicant/base64.c +++ b/contrib/wpa_supplicant/base64.c @@ -1,6 +1,6 @@ /* * Base64 encoding/decoding (RFC1341) - * Copyright (c) 2005, Jouni Malinen <jkmaline@cc.hut.fi> + * Copyright (c) 2005, Jouni Malinen <j@w1.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 @@ -12,12 +12,12 @@ * See README and COPYING for more details. */ -#include <stdlib.h> -#include <string.h> +#include "includes.h" +#include "os.h" #include "base64.h" -static const unsigned char base64_table[64] = +static const unsigned char base64_table[65] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"; /** @@ -43,7 +43,7 @@ unsigned char * base64_encode(const unsigned char *src, size_t len, olen = len * 4 / 3 + 4; /* 3-byte blocks to 4-byte */ olen += olen / 72; /* line feeds */ olen++; /* nul termination */ - out = malloc(olen); + out = os_malloc(olen); if (out == NULL) return NULL; @@ -104,9 +104,9 @@ unsigned char * base64_decode(const unsigned char *src, size_t len, unsigned char dtable[256], *out, *pos, in[4], block[4], tmp; size_t i, count, olen; - memset(dtable, 0x80, 256); - for (i = 0; i < sizeof(base64_table); i++) - dtable[base64_table[i]] = i; + os_memset(dtable, 0x80, 256); + for (i = 0; i < sizeof(base64_table) - 1; i++) + dtable[base64_table[i]] = (unsigned char) i; dtable['='] = 0; count = 0; @@ -119,7 +119,7 @@ unsigned char * base64_decode(const unsigned char *src, size_t len, return NULL; olen = count / 4 * 3; - pos = out = malloc(count); + pos = out = os_malloc(olen); if (out == NULL) return NULL; @@ -166,19 +166,9 @@ int main(int argc, char *argv[]) return -1; } - f = fopen(argv[2], "r"); - if (f == NULL) - return -1; - fseek(f, 0, SEEK_END); - len = ftell(f); - fseek(f, 0, SEEK_SET); - buf = malloc(len); - if (buf == NULL) { - fclose(f); + buf = os_readfile(argv[2], &len); + if (buf == NULL) return -1; - } - fread(buf, 1, len, f); - fclose(f); if (strcmp(argv[1], "encode") == 0) e = base64_encode(buf, len, &elen); diff --git a/contrib/wpa_supplicant/base64.h b/contrib/wpa_supplicant/base64.h index 7043328f678e..73312dde8f64 100644 --- a/contrib/wpa_supplicant/base64.h +++ b/contrib/wpa_supplicant/base64.h @@ -1,6 +1,6 @@ /* * Base64 encoding/decoding (RFC1341) - * Copyright (c) 2005, Jouni Malinen <jkmaline@cc.hut.fi> + * Copyright (c) 2005, Jouni Malinen <j@w1.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 diff --git a/contrib/wpa_supplicant/bignum.c b/contrib/wpa_supplicant/bignum.c new file mode 100644 index 000000000000..4c304c2a5af5 --- /dev/null +++ b/contrib/wpa_supplicant/bignum.c @@ -0,0 +1,230 @@ +/* + * Big number math + * Copyright (c) 2006, Jouni Malinen <j@w1.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 "includes.h" + +#include "common.h" +#include "bignum.h" + +#ifdef CONFIG_INTERNAL_LIBTOMMATH +#include "libtommath.c" +#else /* CONFIG_INTERNAL_LIBTOMMATH */ +#include <tommath.h> +#endif /* CONFIG_INTERNAL_LIBTOMMATH */ + + +/* + * The current version is just a wrapper for LibTomMath library, so + * struct bignum is just typecast to mp_int. + */ + +/** + * bignum_init - Allocate memory for bignum + * Returns: Pointer to allocated bignum or %NULL on failure + */ +struct bignum * bignum_init(void) +{ + struct bignum *n = os_zalloc(sizeof(mp_int)); + if (n == NULL) + return NULL; + if (mp_init((mp_int *) n) != MP_OKAY) { + os_free(n); + n = NULL; + } + return n; +} + + +/** + * bignum_deinit - Free bignum + * @n: Bignum from bignum_init() + */ +void bignum_deinit(struct bignum *n) +{ + if (n) { + mp_clear((mp_int *) n); + os_free(n); + } +} + + +/** + * bignum_get_unsigned_bin - Get length of bignum as an unsigned binary buffer + * @n: Bignum from bignum_init() + * Returns: Length of n if written to a binary buffer + */ +size_t bignum_get_unsigned_bin_len(struct bignum *n) +{ + return mp_unsigned_bin_size((mp_int *) n); +} + + +/** + * bignum_get_unsigned_bin - Set binary buffer to unsigned bignum + * @n: Bignum from bignum_init() + * @buf: Buffer for the binary number + * @len: Length of the buffer, can be %NULL if buffer is known to be long + * enough. Set to used buffer length on success if not %NULL. + * Returns: 0 on success, -1 on failure + */ +int bignum_get_unsigned_bin(const struct bignum *n, u8 *buf, size_t *len) +{ + size_t need = mp_unsigned_bin_size((mp_int *) n); + if (len && need > *len) { + *len = need; + return -1; + } + if (mp_to_unsigned_bin((mp_int *) n, buf) != MP_OKAY) { + wpa_printf(MSG_DEBUG, "BIGNUM: %s failed", __func__); + return -1; + } + if (len) + *len = need; + return 0; +} + + +/** + * bignum_set_unsigned_bin - Set bignum based on unsigned binary buffer + * @a: Bignum from bignum_init(); to be set to the given value + * @buf: Buffer with unsigned binary value + * @len: Length of buf in octets + * Returns: 0 on success, -1 on failure + */ +int bignum_set_unsigned_bin(struct bignum *n, const u8 *buf, size_t len) +{ + if (mp_read_unsigned_bin((mp_int *) n, (u8 *) buf, len) != MP_OKAY) { + wpa_printf(MSG_DEBUG, "BIGNUM: %s failed", __func__); + return -1; + } + return 0; +} + + +/** + * bignum_cmp - Signed comparison + * @a: Bignum from bignum_init() + * @b: Bignum from bignum_init() + * Returns: 0 on success, -1 on failure + */ +int bignum_cmp(const struct bignum *a, const struct bignum *b) +{ + return mp_cmp((mp_int *) a, (mp_int *) b); +} + + +/** + * bignum_cmd_d - Compare bignum to standard integer + * @a: Bignum from bignum_init() + * @b: Small integer + * Returns: 0 on success, -1 on failure + */ +int bignum_cmp_d(const struct bignum *a, unsigned long b) +{ + return mp_cmp_d((mp_int *) a, b); +} + + +/** + * bignum_add - c = a + b + * @a: Bignum from bignum_init() + * @b: Bignum from bignum_init() + * @c: Bignum from bignum_init(); used to store the result of a + b + * Returns: 0 on success, -1 on failure + */ +int bignum_add(const struct bignum *a, const struct bignum *b, + struct bignum *c) +{ + if (mp_add((mp_int *) a, (mp_int *) b, (mp_int *) c) != MP_OKAY) { + wpa_printf(MSG_DEBUG, "BIGNUM: %s failed", __func__); + return -1; + } + return 0; +} + + +/** + * bignum_sub - c = a - b + * @a: Bignum from bignum_init() + * @b: Bignum from bignum_init() + * @c: Bignum from bignum_init(); used to store the result of a - b + * Returns: 0 on success, -1 on failure + */ +int bignum_sub(const struct bignum *a, const struct bignum *b, + struct bignum *c) +{ + if (mp_sub((mp_int *) a, (mp_int *) b, (mp_int *) c) != MP_OKAY) { + wpa_printf(MSG_DEBUG, "BIGNUM: %s failed", __func__); + return -1; + } + return 0; +} + + +/** + * bignum_mul - c = a * b + * @a: Bignum from bignum_init() + * @b: Bignum from bignum_init() + * @c: Bignum from bignum_init(); used to store the result of a * b + * Returns: 0 on success, -1 on failure + */ +int bignum_mul(const struct bignum *a, const struct bignum *b, + struct bignum *c) +{ + if (mp_mul((mp_int *) a, (mp_int *) b, (mp_int *) c) != MP_OKAY) { + wpa_printf(MSG_DEBUG, "BIGNUM: %s failed", __func__); + return -1; + } + return 0; +} + + +/** + * bignum_mulmod - d = a * b (mod c) + * @a: Bignum from bignum_init() + * @b: Bignum from bignum_init() + * @c: Bignum from bignum_init(); modulus + * @d: Bignum from bignum_init(); used to store the result of a * b (mod c) + * Returns: 0 on success, -1 on failure + */ +int bignum_mulmod(const struct bignum *a, const struct bignum *b, + const struct bignum *c, struct bignum *d) +{ + if (mp_mulmod((mp_int *) a, (mp_int *) b, (mp_int *) c, (mp_int *) d) + != MP_OKAY) { + wpa_printf(MSG_DEBUG, "BIGNUM: %s failed", __func__); + return -1; + } + return 0; +} + + +/** + * bignum_exptmod - Modular exponentiation: d = a^b (mod c) + * @a: Bignum from bignum_init(); base + * @b: Bignum from bignum_init(); exponent + * @c: Bignum from bignum_init(); modulus + * @d: Bignum from bignum_init(); used to store the result of a^b (mod c) + * Returns: 0 on success, -1 on failure + */ +int bignum_exptmod(const struct bignum *a, const struct bignum *b, + const struct bignum *c, struct bignum *d) +{ + if (mp_exptmod((mp_int *) a, (mp_int *) b, (mp_int *) c, (mp_int *) d) + != MP_OKAY) { + wpa_printf(MSG_DEBUG, "BIGNUM: %s failed", __func__); + return -1; + } + return 0; +} diff --git a/contrib/wpa_supplicant/bignum.h b/contrib/wpa_supplicant/bignum.h new file mode 100644 index 000000000000..f25e26783a0a --- /dev/null +++ b/contrib/wpa_supplicant/bignum.h @@ -0,0 +1,38 @@ +/* + * Big number math + * Copyright (c) 2006, Jouni Malinen <j@w1.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. + */ + +#ifndef BIGNUM_H +#define BIGNUM_H + +struct bignum; + +struct bignum * bignum_init(void); +void bignum_deinit(struct bignum *n); +size_t bignum_get_unsigned_bin_len(struct bignum *n); +int bignum_get_unsigned_bin(const struct bignum *n, u8 *buf, size_t *len); +int bignum_set_unsigned_bin(struct bignum *n, const u8 *buf, size_t len); +int bignum_cmp(const struct bignum *a, const struct bignum *b); +int bignum_cmp_d(const struct bignum *a, unsigned long b); +int bignum_add(const struct bignum *a, const struct bignum *b, + struct bignum *c); +int bignum_sub(const struct bignum *a, const struct bignum *b, + struct bignum *c); +int bignum_mul(const struct bignum *a, const struct bignum *b, + struct bignum *c); +int bignum_mulmod(const struct bignum *a, const struct bignum *b, + const struct bignum *c, struct bignum *d); +int bignum_exptmod(const struct bignum *a, const struct bignum *b, + const struct bignum *c, struct bignum *d); + +#endif /* BIGNUM_H */ diff --git a/contrib/wpa_supplicant/build_config.h b/contrib/wpa_supplicant/build_config.h new file mode 100644 index 000000000000..58bcda825345 --- /dev/null +++ b/contrib/wpa_supplicant/build_config.h @@ -0,0 +1,50 @@ +/* + * wpa_supplicant/hostapd - Build time configuration defines + * Copyright (c) 2005-2006, Jouni Malinen <j@w1.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. + * + * This header file can be used to define configuration defines that were + * originally defined in Makefile. This is mainly meant for IDE use or for + * systems that do not have suitable 'make' tool. In these cases, it may be + * easier to have a single place for defining all the needed C pre-processor + * defines. + */ + +#ifndef BUILD_CONFIG_H +#define BUILD_CONFIG_H + +/* Insert configuration defines, e.g., #define EAP_MD5, here, if needed. */ + +#ifdef CONFIG_WIN32_DEFAULTS +#define CONFIG_NATIVE_WINDOWS +#define CONFIG_ANSI_C_EXTRA +#define CONFIG_WINPCAP +#define IEEE8021X_EAPOL +#define EAP_TLS_FUNCS +#define PKCS12_FUNCS +#define PCSC_FUNCS +#define CONFIG_CTRL_IFACE +#define CONFIG_CTRL_IFACE_NAMED_PIPE +#define CONFIG_DRIVER_NDIS +#define CONFIG_NDIS_EVENTS_INTEGRATED +#define CONFIG_DEBUG_FILE +#define EAP_MD5 +#define EAP_TLS +#define EAP_MSCHAPv2 +#define EAP_PEAP +#define EAP_TTLS +#define EAP_GTC +#define EAP_OTP +#define EAP_LEAP +#define _CRT_SECURE_NO_DEPRECATE +#endif /* CONFIG_WIN32_DEFAULTS */ + +#endif /* BUILD_CONFIG_H */ diff --git a/contrib/wpa_supplicant/common.c b/contrib/wpa_supplicant/common.c index 4b756d8f9292..c8d6f130a960 100644 --- a/contrib/wpa_supplicant/common.c +++ b/contrib/wpa_supplicant/common.c @@ -1,6 +1,6 @@ /* * wpa_supplicant/hostapd / common helper functions, etc. - * Copyright (c) 2002-2005, Jouni Malinen <jkmaline@cc.hut.fi> + * Copyright (c) 2002-2006, Jouni Malinen <j@w1.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 @@ -12,70 +12,20 @@ * See README and COPYING for more details. */ -#include <stdlib.h> -#include <stdio.h> -#include <string.h> -#include <unistd.h> -#include <errno.h> -#include <stdarg.h> -#include <ctype.h> -#include <time.h> -#include <sys/time.h> -#ifdef CONFIG_NATIVE_WINDOWS -#include <winsock2.h> -#include <wincrypt.h> -#endif /* CONFIG_NATIVE_WINDOWS */ +#include "includes.h" #include "common.h" +#ifdef CONFIG_DEBUG_FILE +static FILE *out_file = NULL; +#endif /* CONFIG_DEBUG_FILE */ +int wpa_debug_use_file = 0; int wpa_debug_level = MSG_INFO; int wpa_debug_show_keys = 0; int wpa_debug_timestamp = 0; -int hostapd_get_rand(u8 *buf, size_t len) -{ -#ifdef CONFIG_NATIVE_WINDOWS - HCRYPTPROV prov; - BOOL ret; - - if (!CryptAcquireContext(&prov, NULL, NULL, PROV_RSA_FULL, - CRYPT_VERIFYCONTEXT)) - return -1; - - ret = CryptGenRandom(prov, len, buf); - CryptReleaseContext(prov, 0); - - return ret ? 0 : -1; -#else /* CONFIG_NATIVE_WINDOWS */ - FILE *f; - size_t rc; - - f = fopen("/dev/urandom", "r"); - if (f == NULL) { - printf("Could not open /dev/urandom.\n"); - return -1; - } - - rc = fread(buf, 1, len, f); - fclose(f); - - return rc != len ? -1 : 0; -#endif /* CONFIG_NATIVE_WINDOWS */ -} - - -void hostapd_hexdump(const char *title, const u8 *buf, size_t len) -{ - size_t i; - printf("%s - hexdump(len=%lu):", title, (unsigned long) len); - for (i = 0; i < len; i++) - printf(" %02x", buf[i]); - printf("\n"); -} - - static int hex2num(char c) { if (c >= '0' && c <= '9') @@ -139,7 +89,8 @@ int hwaddr_aton(const char *txt, u8 *addr) */ int hexstr2bin(const char *hex, u8 *buf, size_t len) { - int i, a; + size_t i; + int a; const char *ipos = hex; u8 *opos = buf; @@ -154,45 +105,6 @@ int hexstr2bin(const char *hex, u8 *buf, size_t len) } -char * rel2abs_path(const char *rel_path) -{ - char *buf = NULL, *cwd, *ret; - size_t len = 128, cwd_len, rel_len, ret_len; - - if (rel_path[0] == '/') - return strdup(rel_path); - - for (;;) { - buf = malloc(len); - if (buf == NULL) - return NULL; - cwd = getcwd(buf, len); - if (cwd == NULL) { - free(buf); - if (errno != ERANGE) { - return NULL; - } - len *= 2; - } else { - break; - } - } - - cwd_len = strlen(cwd); - rel_len = strlen(rel_path); - ret_len = cwd_len + 1 + rel_len + 1; - ret = malloc(ret_len); - if (ret) { - memcpy(ret, cwd, cwd_len); - ret[cwd_len] = '/'; - memcpy(ret + cwd_len + 1, rel_path, rel_len); - ret[ret_len - 1] = '\0'; - } - free(buf); - return ret; -} - - /** * inc_byte_array - Increment arbitrary length byte array by one * @counter: Pointer to byte array @@ -214,40 +126,40 @@ void inc_byte_array(u8 *counter, size_t len) } -void print_char(char c) +void wpa_get_ntp_timestamp(u8 *buf) { - if (c >= 32 && c < 127) - printf("%c", c); - else - printf("<%02x>", c); + struct os_time now; + u32 sec, usec; + + /* 64-bit NTP timestamp (time from 1900-01-01 00:00:00) */ + os_get_time(&now); + sec = host_to_be32(now.sec + 2208988800U); /* Epoch to 1900 */ + /* Estimate 2^32/10^6 = 4295 - 1/32 - 1/512 */ + usec = now.usec; + usec = host_to_be32(4295 * usec - (usec >> 5) - (usec >> 9)); + os_memcpy(buf, (u8 *) &sec, 4); + os_memcpy(buf + 4, (u8 *) &usec, 4); } -void fprint_char(FILE *f, char c) -{ - if (c >= 32 && c < 127) - fprintf(f, "%c", c); - else - fprintf(f, "<%02x>", c); -} - #ifndef CONFIG_NO_STDOUT_DEBUG void wpa_debug_print_timestamp(void) { - struct timeval tv; - char buf[16]; + struct os_time tv; if (!wpa_debug_timestamp) return; - gettimeofday(&tv, NULL); - if (strftime(buf, sizeof(buf), "%b %d %H:%M:%S", - localtime((const time_t *) &tv.tv_sec)) <= 0) { - snprintf(buf, sizeof(buf), "%u", (int) tv.tv_sec); - } - printf("%s.%06u: ", buf, (unsigned int) tv.tv_usec); + os_get_time(&tv); +#ifdef CONFIG_DEBUG_FILE + if (out_file) { + fprintf(out_file, "%ld.%06u: ", (long) tv.sec, + (unsigned int) tv.usec); + } else +#endif /* CONFIG_DEBUG_FILE */ + printf("%ld.%06u: ", (long) tv.sec, (unsigned int) tv.usec); } @@ -269,8 +181,17 @@ void wpa_printf(int level, char *fmt, ...) va_start(ap, fmt); if (level >= wpa_debug_level) { wpa_debug_print_timestamp(); +#ifdef CONFIG_DEBUG_FILE + if (out_file) { + vfprintf(out_file, fmt, ap); + fprintf(out_file, "\n"); + } else { +#endif /* CONFIG_DEBUG_FILE */ vprintf(fmt, ap); printf("\n"); +#ifdef CONFIG_DEBUG_FILE + } +#endif /* CONFIG_DEBUG_FILE */ } va_end(ap); } @@ -283,6 +204,21 @@ static void _wpa_hexdump(int level, const char *title, const u8 *buf, if (level < wpa_debug_level) return; wpa_debug_print_timestamp(); +#ifdef CONFIG_DEBUG_FILE + if (out_file) { + fprintf(out_file, "%s - hexdump(len=%lu):", + title, (unsigned long) len); + if (buf == NULL) { + fprintf(out_file, " [NULL]"); + } else if (show) { + for (i = 0; i < len; i++) + fprintf(out_file, " %02x", buf[i]); + } else { + fprintf(out_file, " [REMOVED]"); + } + fprintf(out_file, "\n"); + } else { +#endif /* CONFIG_DEBUG_FILE */ printf("%s - hexdump(len=%lu):", title, (unsigned long) len); if (buf == NULL) { printf(" [NULL]"); @@ -293,6 +229,9 @@ static void _wpa_hexdump(int level, const char *title, const u8 *buf, printf(" [REMOVED]"); } printf("\n"); +#ifdef CONFIG_DEBUG_FILE + } +#endif /* CONFIG_DEBUG_FILE */ } void wpa_hexdump(int level, const char *title, const u8 *buf, size_t len) @@ -310,13 +249,51 @@ void wpa_hexdump_key(int level, const char *title, const u8 *buf, size_t len) static void _wpa_hexdump_ascii(int level, const char *title, const u8 *buf, size_t len, int show) { - int i, llen; + size_t i, llen; const u8 *pos = buf; - const int line_len = 16; + const size_t line_len = 16; if (level < wpa_debug_level) return; wpa_debug_print_timestamp(); +#ifdef CONFIG_DEBUG_FILE + if (out_file) { + if (!show) { + fprintf(out_file, + "%s - hexdump_ascii(len=%lu): [REMOVED]\n", + title, (unsigned long) len); + return; + } + if (buf == NULL) { + fprintf(out_file, + "%s - hexdump_ascii(len=%lu): [NULL]\n", + title, (unsigned long) len); + return; + } + fprintf(out_file, "%s - hexdump_ascii(len=%lu):\n", + title, (unsigned long) len); + while (len) { + llen = len > line_len ? line_len : len; + fprintf(out_file, " "); + for (i = 0; i < llen; i++) + fprintf(out_file, " %02x", pos[i]); + for (i = llen; i < line_len; i++) + fprintf(out_file, " "); + fprintf(out_file, " "); + for (i = 0; i < llen; i++) { + if (isprint(pos[i])) + fprintf(out_file, "%c", pos[i]); + else + fprintf(out_file, "_"); + } + for (i = llen; i < line_len; i++) + fprintf(out_file, " "); + fprintf(out_file, "\n"); + pos += llen; + len -= llen; + } + } else { +#endif /* CONFIG_DEBUG_FILE */ if (!show) { printf("%s - hexdump_ascii(len=%lu): [REMOVED]\n", title, (unsigned long) len); @@ -348,6 +325,9 @@ static void _wpa_hexdump_ascii(int level, const char *title, const u8 *buf, pos += llen; len -= llen; } +#ifdef CONFIG_DEBUG_FILE + } +#endif /* CONFIG_DEBUG_FILE */ } @@ -363,26 +343,261 @@ void wpa_hexdump_ascii_key(int level, const char *title, const u8 *buf, _wpa_hexdump_ascii(level, title, buf, len, wpa_debug_show_keys); } + +int wpa_debug_open_file(void) +{ +#ifdef CONFIG_DEBUG_FILE + static int count = 0; + char fname[64]; + if (!wpa_debug_use_file) + return 0; +#ifdef _WIN32 + os_snprintf(fname, sizeof(fname), "\\Temp\\wpa_supplicant-log-%d.txt", + count++); +#else /* _WIN32 */ + os_snprintf(fname, sizeof(fname), "/tmp/wpa_supplicant-log-%d.txt", + count++); +#endif /* _WIN32 */ + out_file = fopen(fname, "w"); + return out_file == NULL ? -1 : 0; +#else /* CONFIG_DEBUG_FILE */ + return 0; +#endif /* CONFIG_DEBUG_FILE */ +} + + +void wpa_debug_close_file(void) +{ +#ifdef CONFIG_DEBUG_FILE + if (!wpa_debug_use_file) + return; + fclose(out_file); + out_file = NULL; +#endif /* CONFIG_DEBUG_FILE */ +} + #endif /* CONFIG_NO_STDOUT_DEBUG */ -#ifdef CONFIG_NATIVE_WINDOWS +#ifndef CONFIG_NO_WPA_MSG +static wpa_msg_cb_func wpa_msg_cb = NULL; + +void wpa_msg_register_cb(wpa_msg_cb_func func) +{ + wpa_msg_cb = func; +} + + +void wpa_msg(void *ctx, int level, char *fmt, ...) +{ + va_list ap; + char *buf; + const int buflen = 2048; + int len; -#define EPOCHFILETIME (116444736000000000ULL) + buf = os_malloc(buflen); + if (buf == NULL) { + wpa_printf(MSG_ERROR, "wpa_msg: Failed to allocate message " + "buffer"); + return; + } + va_start(ap, fmt); + len = vsnprintf(buf, buflen, fmt, ap); + va_end(ap); + wpa_printf(level, "%s", buf); + if (wpa_msg_cb) + wpa_msg_cb(ctx, level, buf, len); + os_free(buf); +} +#endif /* CONFIG_NO_WPA_MSG */ -int gettimeofday(struct timeval *tv, struct timezone *tz) + +static inline int _wpa_snprintf_hex(char *buf, size_t buf_size, const u8 *data, + size_t len, int uppercase) { - FILETIME ft; - LARGE_INTEGER li; - ULONGLONG t; + size_t i; + char *pos = buf, *end = buf + buf_size; + int ret; + if (buf_size == 0) + return 0; + for (i = 0; i < len; i++) { + ret = os_snprintf(pos, end - pos, uppercase ? "%02X" : "%02x", + data[i]); + if (ret < 0 || ret >= end - pos) { + end[-1] = '\0'; + return pos - buf; + } + pos += ret; + } + end[-1] = '\0'; + return pos - buf; +} - GetSystemTimeAsFileTime(&ft); - li.LowPart = ft.dwLowDateTime; - li.HighPart = ft.dwHighDateTime; - t = (li.QuadPart - EPOCHFILETIME) / 10; - tv->tv_sec = (long) (t / 1000000); - tv->tv_usec = (long) (t % 1000000); +/** + * wpa_snprintf_hex - Print data as a hex string into a buffer + * @buf: Memory area to use as the output buffer + * @buf_size: Maximum buffer size in bytes (should be at least 2 * len + 1) + * @data: Data to be printed + * @len: Length of data in bytes + * Returns: Number of bytes written + */ +int wpa_snprintf_hex(char *buf, size_t buf_size, const u8 *data, size_t len) +{ + return _wpa_snprintf_hex(buf, buf_size, data, len, 0); +} - return 0; + +/** + * wpa_snprintf_hex_uppercase - Print data as a upper case hex string into buf + * @buf: Memory area to use as the output buffer + * @buf_size: Maximum buffer size in bytes (should be at least 2 * len + 1) + * @data: Data to be printed + * @len: Length of data in bytes + * Returns: Number of bytes written + */ +int wpa_snprintf_hex_uppercase(char *buf, size_t buf_size, const u8 *data, + size_t len) +{ + return _wpa_snprintf_hex(buf, buf_size, data, len, 1); +} + + +#ifdef CONFIG_ANSI_C_EXTRA + +#ifdef _WIN32_WCE +void perror(const char *s) +{ + wpa_printf(MSG_ERROR, "%s: GetLastError: %d", + s, (int) GetLastError()); +} +#endif /* _WIN32_WCE */ + + +int optind = 1; +int optopt; +char *optarg; + +int getopt(int argc, char *const argv[], const char *optstring) +{ + static int optchr = 1; + char *cp; + + if (optchr == 1) { + if (optind >= argc) { + /* all arguments processed */ + return EOF; + } + + if (argv[optind][0] != '-' || argv[optind][1] == '\0') { + /* no option characters */ + return EOF; + } + } + + if (os_strcmp(argv[optind], "--") == 0) { + /* no more options */ + optind++; + return EOF; + } + + optopt = argv[optind][optchr]; + cp = os_strchr(optstring, optopt); + if (cp == NULL || optopt == ':') { + if (argv[optind][++optchr] == '\0') { + optchr = 1; + optind++; + } + return '?'; + } + + if (cp[1] == ':') { + /* Argument required */ + optchr = 1; + if (argv[optind][optchr + 1]) { + /* No space between option and argument */ + optarg = &argv[optind++][optchr + 1]; + } else if (++optind >= argc) { + /* option requires an argument */ + return '?'; + } else { + /* Argument in the next argv */ + optarg = argv[optind++]; + } + } else { + /* No argument */ + if (argv[optind][++optchr] == '\0') { + optchr = 1; + optind++; + } + optarg = NULL; + } + return *cp; +} +#endif /* CONFIG_ANSI_C_EXTRA */ + + +#ifdef CONFIG_NATIVE_WINDOWS +/** + * wpa_unicode2ascii_inplace - Convert unicode string into ASCII + * @str: Pointer to string to convert + * + * This function converts a unicode string to ASCII using the same + * buffer for output. If UNICODE is not set, the buffer is not + * modified. + */ +void wpa_unicode2ascii_inplace(TCHAR *str) +{ +#ifdef UNICODE + char *dst = (char *) str; + while (*str) + *dst++ = (char) *str++; + *dst = '\0'; +#endif /* UNICODE */ +} + + +TCHAR * wpa_strdup_tchar(const char *str) +{ +#ifdef UNICODE + TCHAR *buf; + buf = os_malloc((strlen(str) + 1) * sizeof(TCHAR)); + if (buf == NULL) + return NULL; + wsprintf(buf, L"%S", str); + return buf; +#else /* UNICODE */ + return os_strdup(str); +#endif /* UNICODE */ } #endif /* CONFIG_NATIVE_WINDOWS */ + + +/** + * wpa_ssid_txt - Convert SSID to a printable string + * @ssid: SSID (32-octet string) + * @ssid_len: Length of ssid in octets + * Returns: Pointer to a printable string + * + * This function can be used to convert SSIDs into printable form. In most + * cases, SSIDs do not use unprintable characters, but IEEE 802.11 standard + * does not limit the used character set, so anything could be used in an SSID. + * + * This function uses a static buffer, so only one call can be used at the + * time, i.e., this is not re-entrant and the returned buffer must be used + * before calling this again. + */ +const char * wpa_ssid_txt(u8 *ssid, size_t ssid_len) +{ + static char ssid_txt[33]; + char *pos; + + if (ssid_len > 32) + ssid_len = 32; + os_memcpy(ssid_txt, ssid, ssid_len); + ssid_txt[ssid_len] = '\0'; + for (pos = ssid_txt; *pos != '\0'; pos++) { + if ((u8) *pos < 32 || (u8) *pos >= 127) + *pos = '_'; + } + return ssid_txt; +} diff --git a/contrib/wpa_supplicant/common.h b/contrib/wpa_supplicant/common.h index 4bece7f6ecd9..b200b580d5df 100644 --- a/contrib/wpa_supplicant/common.h +++ b/contrib/wpa_supplicant/common.h @@ -1,6 +1,6 @@ /* * wpa_supplicant/hostapd / common helper functions, etc. - * Copyright (c) 2002-2005, Jouni Malinen <jkmaline@cc.hut.fi> + * Copyright (c) 2002-2006, Jouni Malinen <j@w1.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 @@ -15,12 +15,14 @@ #ifndef COMMON_H #define COMMON_H +#include "os.h" + #ifdef __linux__ #include <endian.h> #include <byteswap.h> #endif /* __linux__ */ -#if defined(__FreeBSD__) || defined(__NetBSD__) +#if defined(__FreeBSD__) || defined(__NetBSD__) || defined(__DragonFly__) #include <sys/types.h> #include <sys/endian.h> #define __BYTE_ORDER _BYTE_ORDER @@ -29,51 +31,22 @@ #define bswap_16 bswap16 #define bswap_32 bswap32 #define bswap_64 bswap64 -#endif /* defined(__FreeBSD__) || defined(__NetBSD__) */ - -#ifdef CONFIG_NATIVE_WINDOWS -#include <winsock2.h> - -static inline int daemon(int nochdir, int noclose) -{ - printf("Windows - daemon() not supported yet\n"); - return -1; -} - -static inline void sleep(int seconds) -{ - Sleep(seconds * 1000); -} - -static inline void usleep(unsigned long usec) -{ - Sleep(usec / 1000); -} - -#ifndef timersub -#define timersub(a, b, res) do { \ - (res)->tv_sec = (a)->tv_sec - (b)->tv_sec; \ - (res)->tv_usec = (a)->tv_usec - (b)->tv_usec; \ - if ((res)->tv_usec < 0) { \ - (res)->tv_sec--; \ - (res)->tv_usec += 1000000; \ - } \ -} while (0) +#endif /* defined(__FreeBSD__) || defined(__NetBSD__) || + * defined(__DragonFly__) */ + +#ifdef CONFIG_TI_COMPILER +#define __BIG_ENDIAN 4321 +#define __LITTLE_ENDIAN 1234 +#ifdef __big_endian__ +#define __BYTE_ORDER __BIG_ENDIAN +#else +#define __BYTE_ORDER __LITTLE_ENDIAN #endif +#endif /* CONFIG_TI_COMPILER */ -struct timezone { - int tz_minuteswest; - int tz_dsttime; -}; - -int gettimeofday(struct timeval *tv, struct timezone *tz); - -static inline long int random(void) -{ - return rand(); -} +#ifdef CONFIG_NATIVE_WINDOWS +#include <winsock.h> -typedef int gid_t; typedef int socklen_t; #ifndef MSG_DONTWAIT @@ -84,6 +57,10 @@ typedef int socklen_t; #if defined(__CYGWIN__) || defined(CONFIG_NATIVE_WINDOWS) +#ifdef _MSC_VER +#define inline __inline +#endif /* _MSC_VER */ + static inline unsigned short wpa_swap_16(unsigned short v) { return ((v & 0xff) << 8) | (v >> 8); @@ -105,6 +82,18 @@ static inline unsigned int wpa_swap_32(unsigned int v) #else /* __CYGWIN__ */ +#ifndef __BYTE_ORDER +#ifndef __LITTLE_ENDIAN +#ifndef __BIG_ENDIAN +#define __LITTLE_ENDIAN 1234 +#define __BIG_ENDIAN 4321 +#if defined(sparc) +#define __BYTE_ORDER __BIG_ENDIAN +#endif +#endif /* __BIG_ENDIAN */ +#endif /* __LITTLE_ENDIAN */ +#endif /* __BYTE_ORDER */ + #if __BYTE_ORDER == __LITTLE_ENDIAN #define le_to_host16(n) (n) #define host_to_le16(n) (n) @@ -113,6 +102,10 @@ static inline unsigned int wpa_swap_32(unsigned int v) #define le_to_host32(n) (n) #define be_to_host32(n) bswap_32(n) #define host_to_be32(n) bswap_32(n) +#define le_to_host64(n) (n) +#define host_to_le64(n) (n) +#define be_to_host64(n) bswap_64(n) +#define host_to_be64(n) bswap_64(n) #elif __BYTE_ORDER == __BIG_ENDIAN #define le_to_host16(n) bswap_16(n) #define host_to_le16(n) bswap_16(n) @@ -121,6 +114,10 @@ static inline unsigned int wpa_swap_32(unsigned int v) #define le_to_host32(n) bswap_32(n) #define be_to_host32(n) (n) #define host_to_be32(n) (n) +#define le_to_host64(n) bswap_64(n) +#define host_to_le64(n) bswap_64(n) +#define be_to_host64(n) (n) +#define host_to_be64(n) (n) #ifndef WORDS_BIGENDIAN #define WORDS_BIGENDIAN #endif @@ -145,12 +142,88 @@ static inline unsigned int wpa_swap_32(unsigned int v) (a)[0] = ((u16) (val)) & 0xff; \ } while (0) +#define WPA_GET_BE24(a) ((((u32) (a)[0]) << 16) | (((u32) (a)[1]) << 8) | \ + ((u32) (a)[2])) +#define WPA_PUT_BE24(a, val) \ + do { \ + (a)[0] = (u8) (((u32) (val)) >> 16); \ + (a)[1] = (u8) (((u32) (val)) >> 8); \ + (a)[2] = (u8) (((u32) (val)) & 0xff); \ + } while (0) + +#define WPA_GET_BE32(a) ((((u32) (a)[0]) << 24) | (((u32) (a)[1]) << 16) | \ + (((u32) (a)[2]) << 8) | ((u32) (a)[3])) +#define WPA_PUT_BE32(a, val) \ + do { \ + (a)[0] = (u8) (((u32) (val)) >> 24); \ + (a)[1] = (u8) (((u32) (val)) >> 16); \ + (a)[2] = (u8) (((u32) (val)) >> 8); \ + (a)[3] = (u8) (((u32) (val)) & 0xff); \ + } while (0) + +#define WPA_PUT_BE64(a, val) \ + do { \ + (a)[0] = (u8) (((u64) (val)) >> 56); \ + (a)[1] = (u8) (((u64) (val)) >> 48); \ + (a)[2] = (u8) (((u64) (val)) >> 40); \ + (a)[3] = (u8) (((u64) (val)) >> 32); \ + (a)[4] = (u8) (((u64) (val)) >> 24); \ + (a)[5] = (u8) (((u64) (val)) >> 16); \ + (a)[6] = (u8) (((u64) (val)) >> 8); \ + (a)[7] = (u8) (((u64) (val)) & 0xff); \ + } while (0) + #ifndef ETH_ALEN #define ETH_ALEN 6 #endif +#ifdef _MSC_VER +typedef UINT64 u64; +typedef UINT32 u32; +typedef UINT16 u16; +typedef UINT8 u8; +typedef INT64 s64; +typedef INT32 s32; +typedef INT16 s16; +typedef INT8 s8; +#define WPA_TYPES_DEFINED +#endif /* _MSC_VER */ + +#ifdef __vxworks +typedef unsigned long long u64; +typedef UINT32 u32; +typedef UINT16 u16; +typedef UINT8 u8; +typedef long long s64; +typedef INT32 s32; +typedef INT16 s16; +typedef INT8 s8; +#define WPA_TYPES_DEFINED +#endif /* __vxworks */ + +#ifdef CONFIG_TI_COMPILER +#ifdef _LLONG_AVAILABLE +typedef unsigned long long u64; +#else +/* + * TODO: 64-bit variable not available. Using long as a workaround to test the + * build, but this will likely not work for all operations. + */ +typedef unsigned long u64; +#endif +typedef unsigned int u32; +typedef unsigned short u16; +typedef unsigned char u8; +#define WPA_TYPES_DEFINED +#endif /* CONFIG_TI_COMPILER */ + +#ifndef WPA_TYPES_DEFINED +#ifdef CONFIG_USE_INTTYPES_H +#include <inttypes.h> +#else #include <stdint.h> +#endif typedef uint64_t u64; typedef uint32_t u32; typedef uint16_t u16; @@ -159,19 +232,27 @@ typedef int64_t s64; typedef int32_t s32; typedef int16_t s16; typedef int8_t s8; +#define WPA_TYPES_DEFINED +#endif /* !WPA_TYPES_DEFINED */ -int hostapd_get_rand(u8 *buf, size_t len); -void hostapd_hexdump(const char *title, const u8 *buf, size_t len); +#define hostapd_get_rand os_get_random int hwaddr_aton(const char *txt, u8 *addr); int hexstr2bin(const char *hex, u8 *buf, size_t len); -char * rel2abs_path(const char *rel_path); void inc_byte_array(u8 *counter, size_t len); -void print_char(char c); -void fprint_char(FILE *f, char c); +void wpa_get_ntp_timestamp(u8 *buf); + + +#ifdef __GNUC__ +#define PRINTF_FORMAT(a,b) __attribute__ ((format (printf, (a), (b)))) +#define STRUCT_PACKED __attribute__ ((packed)) +#else +#define PRINTF_FORMAT(a,b) +#define STRUCT_PACKED +#endif /* Debugging function - conditional printf and hex dump. Driver wrappers can - * use these for debugging purposes. */ + * use these for debugging purposes. */ enum { MSG_MSGDUMP, MSG_DEBUG, MSG_INFO, MSG_WARNING, MSG_ERROR }; @@ -179,13 +260,18 @@ enum { MSG_MSGDUMP, MSG_DEBUG, MSG_INFO, MSG_WARNING, MSG_ERROR }; #define wpa_debug_print_timestamp() do { } while (0) #define wpa_printf(args...) do { } while (0) -#define wpa_hexdump(args...) do { } while (0) -#define wpa_hexdump_key(args...) do { } while (0) -#define wpa_hexdump_ascii(args...) do { } while (0) -#define wpa_hexdump_ascii_key(args...) do { } while (0) +#define wpa_hexdump(l,t,b,le) do { } while (0) +#define wpa_hexdump_key(l,t,b,le) do { } while (0) +#define wpa_hexdump_ascii(l,t,b,le) do { } while (0) +#define wpa_hexdump_ascii_key(l,t,b,le) do { } while (0) +#define wpa_debug_open_file() do { } while (0) +#define wpa_debug_close_file() do { } while (0) #else /* CONFIG_NO_STDOUT_DEBUG */ +int wpa_debug_open_file(void); +void wpa_debug_close_file(void); + /** * wpa_debug_printf_timestamp - Print timestamp for debug output * @@ -207,7 +293,7 @@ void wpa_debug_print_timestamp(void); * Note: New line '\n' is added to the end of the text when printing to stdout. */ void wpa_printf(int level, char *fmt, ...) -__attribute__ ((format (printf, 2, 3))); +PRINTF_FORMAT(2, 3); /** * wpa_hexdump - conditional hex dump @@ -273,6 +359,42 @@ void wpa_hexdump_ascii_key(int level, const char *title, const u8 *buf, #endif /* CONFIG_NO_STDOUT_DEBUG */ +#ifdef CONFIG_NO_WPA_MSG +#define wpa_msg(args...) do { } while (0) +#define wpa_msg_register_cb(f) do { } while (0) +#else /* CONFIG_NO_WPA_MSG */ +/** + * wpa_msg - Conditional printf for default target and ctrl_iface monitors + * @ctx: Pointer to context data; this is the ctx variable registered + * with struct wpa_driver_ops::init() + * @level: priority level (MSG_*) of the message + * @fmt: printf format string, followed by optional arguments + * + * This function is used to print conditional debugging and error messages. The + * output may be directed to stdout, stderr, and/or syslog based on + * configuration. This function is like wpa_printf(), but it also sends the + * same message to all attached ctrl_iface monitors. + * + * Note: New line '\n' is added to the end of the text when printing to stdout. + */ +void wpa_msg(void *ctx, int level, char *fmt, ...) PRINTF_FORMAT(3, 4); + +typedef void (*wpa_msg_cb_func)(void *ctx, int level, const char *txt, + size_t len); + +/** + * wpa_msg_register_cb - Register callback function for wpa_msg() messages + * @func: Callback function (%NULL to unregister) + */ +void wpa_msg_register_cb(wpa_msg_cb_func func); +#endif /* CONFIG_NO_WPA_MSG */ + + +int wpa_snprintf_hex(char *buf, size_t buf_size, const u8 *data, size_t len); +int wpa_snprintf_hex_uppercase(char *buf, size_t buf_size, const u8 *data, + size_t len); + + #ifdef EAPOL_TEST #define WPA_ASSERT(a) \ do { \ @@ -287,4 +409,84 @@ void wpa_hexdump_ascii_key(int level, const char *title, const u8 *buf, #define WPA_ASSERT(a) do { } while (0) #endif + +#ifdef _MSC_VER +#undef vsnprintf +#define vsnprintf _vsnprintf +#undef close +#define close closesocket +#endif /* _MSC_VER */ + + +#ifdef CONFIG_ANSI_C_EXTRA + +#if !defined(_MSC_VER) || _MSC_VER < 1400 +/* snprintf - used in number of places; sprintf() is _not_ a good replacement + * due to possible buffer overflow; see, e.g., + * http://www.ijs.si/software/snprintf/ for portable implementation of + * snprintf. */ +int snprintf(char *str, size_t size, const char *format, ...); + +/* vsnprintf - only used for wpa_msg() in wpa_supplicant.c */ +int vsnprintf(char *str, size_t size, const char *format, va_list ap); +#endif /* !defined(_MSC_VER) || _MSC_VER < 1400 */ + +/* getopt - only used in main.c */ +int getopt(int argc, char *const argv[], const char *optstring); +extern char *optarg; +extern int optind; + +#ifndef CONFIG_NO_SOCKLEN_T_TYPEDEF +#ifndef __socklen_t_defined +typedef int socklen_t; +#endif +#endif + +/* inline - define as __inline or just define it to be empty, if needed */ +#ifdef CONFIG_NO_INLINE +#define inline +#else +#define inline __inline +#endif + +#ifndef __func__ +#define __func__ "__func__ not defined" +#endif + +#ifndef bswap_16 +#define bswap_16(a) ((((u16) (a) << 8) & 0xff00) | (((u16) (a) >> 8) & 0xff)) +#endif + +#ifndef bswap_32 +#define bswap_32(a) ((((u32) (a) << 24) & 0xff000000) | \ + (((u32) (a) << 8) & 0xff0000) | \ + (((u32) (a) >> 8) & 0xff00) | \ + (((u32) (a) >> 24) & 0xff)) +#endif + +#ifndef MSG_DONTWAIT +#define MSG_DONTWAIT 0 +#endif + +#ifdef _WIN32_WCE +void perror(const char *s); +#endif /* _WIN32_WCE */ + +#endif /* CONFIG_ANSI_C_EXTRA */ + +#define wpa_zalloc(s) os_zalloc((s)) + +#ifdef CONFIG_NATIVE_WINDOWS +void wpa_unicode2ascii_inplace(TCHAR *str); +TCHAR * wpa_strdup_tchar(const char *str); +#else /* CONFIG_NATIVE_WINDOWS */ +#define wpa_unicode2ascii_inplace(s) do { } while (0) +#define wpa_strdup_tchar(s) strdup((s)) +#endif /* CONFIG_NATIVE_WINDOWS */ + +const char * wpa_ssid_txt(u8 *ssid, size_t ssid_len); + +typedef u32 __be32; +typedef u64 __be64; + #endif /* COMMON_H */ diff --git a/contrib/wpa_supplicant/config.c b/contrib/wpa_supplicant/config.c index 2bba4ab22171..171970dc210f 100644 --- a/contrib/wpa_supplicant/config.c +++ b/contrib/wpa_supplicant/config.c @@ -1,6 +1,6 @@ /* * WPA Supplicant / Configuration parser and common functions - * Copyright (c) 2003-2005, Jouni Malinen <jkmaline@cc.hut.fi> + * Copyright (c) 2003-2006, Jouni Malinen <j@w1.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 @@ -12,14 +12,11 @@ * See README and COPYING for more details. */ -#include <stdlib.h> -#include <stdio.h> -#include <string.h> +#include "includes.h" #include "common.h" #include "wpa.h" #include "sha1.h" -#include "wpa_supplicant.h" #include "eapol_sm.h" #include "eap.h" #include "l2_packet.h" @@ -46,9 +43,11 @@ struct parse_data { /* Variable specific parameters for the parser. */ void *param1, *param2, *param3, *param4; - /* 0 = this variable can be included in debug output + /* 0 = this variable can be included in debug output and ctrl_iface * 1 = this variable contains key/private data and it must not be - * included in debug output unless explicitly requested + * included in debug output unless explicitly requested. In + * addition, this variable will not be readable through the + * ctrl_iface. */ int key_data; }; @@ -59,23 +58,23 @@ static char * wpa_config_parse_string(const char *value, size_t *len) if (*value == '"') { char *pos; value++; - pos = strchr(value, '"'); + pos = os_strrchr(value, '"'); if (pos == NULL || pos[1] != '\0') return NULL; *pos = '\0'; - *len = strlen(value); - return strdup(value); + *len = os_strlen(value); + return os_strdup(value); } else { u8 *str; - size_t hlen = strlen(value); - if (hlen % 1) + size_t hlen = os_strlen(value); + if (hlen & 1) return NULL; *len = hlen / 2; - str = malloc(*len); + str = os_malloc(*len); if (str == NULL) return NULL; if (hexstr2bin(value, str, *len)) { - free(str); + os_free(str); return NULL; } return (char *) str; @@ -88,35 +87,29 @@ static int wpa_config_parse_str(const struct parse_data *data, int line, const char *value) { size_t res_len, *dst_len; - char **dst; + char **dst, *tmp; - dst = (char **) (((u8 *) ssid) + (long) data->param1); - dst_len = (size_t *) (((u8 *) ssid) + (long) data->param2); - - free(*dst); - *dst = wpa_config_parse_string(value, &res_len); - if (*dst == NULL) { + tmp = wpa_config_parse_string(value, &res_len); + if (tmp == NULL) { wpa_printf(MSG_ERROR, "Line %d: failed to parse %s '%s'.", - line, data->name, value); + line, data->name, + data->key_data ? "[KEY DATA REMOVED]" : value); return -1; } - if (data->param2) - *dst_len = res_len; if (data->key_data) { wpa_hexdump_ascii_key(MSG_MSGDUMP, data->name, - (u8 *) *dst, res_len); + (u8 *) tmp, res_len); } else { wpa_hexdump_ascii(MSG_MSGDUMP, data->name, - (u8 *) *dst, res_len); + (u8 *) tmp, res_len); } if (data->param3 && res_len < (size_t) data->param3) { wpa_printf(MSG_ERROR, "Line %d: too short %s (len=%lu " "min_len=%ld)", line, data->name, (unsigned long) res_len, (long) data->param3); - free(*dst); - *dst = NULL; + os_free(tmp); return -1; } @@ -124,18 +117,24 @@ static int wpa_config_parse_str(const struct parse_data *data, wpa_printf(MSG_ERROR, "Line %d: too long %s (len=%lu " "max_len=%ld)", line, data->name, (unsigned long) res_len, (long) data->param4); - free(*dst); - *dst = NULL; + os_free(tmp); return -1; } + dst = (char **) (((u8 *) ssid) + (long) data->param1); + dst_len = (size_t *) (((u8 *) ssid) + (long) data->param2); + os_free(*dst); + *dst = tmp; + if (data->param2) + *dst_len = res_len; + return 0; } static int is_hex(const u8 *data, size_t len) { - int i; + size_t i; for (i = 0; i < len; i++) { if (data[i] < 32 || data[i] >= 127) @@ -147,17 +146,15 @@ static int is_hex(const u8 *data, size_t len) static char * wpa_config_write_string_ascii(const u8 *value, size_t len) { - int i; - char *buf, *pos, *end; + char *buf; - pos = buf = malloc(len + 3); + buf = os_malloc(len + 3); if (buf == NULL) return NULL; - end = buf + len + 3; - pos += snprintf(pos, end - pos, "\""); - for (i = 0; i < len; i++) - pos += snprintf(pos, end - pos, "%c", value[i]); - pos += snprintf(pos, end - pos, "\""); + buf[0] = '"'; + os_memcpy(buf + 1, value, len); + buf[len + 1] = '"'; + buf[len + 2] = '\0'; return buf; } @@ -165,16 +162,12 @@ static char * wpa_config_write_string_ascii(const u8 *value, size_t len) static char * wpa_config_write_string_hex(const u8 *value, size_t len) { - int i; - char *buf, *pos, *end; + char *buf; - pos = buf = malloc(2 * len + 1); + buf = os_zalloc(2 * len + 1); if (buf == NULL) return NULL; - memset(buf, 0, 2 * len + 1); - end = buf + 2 * len + 1; - for (i = 0; i < len; i++) - pos += snprintf(pos, end - pos, "%02x", value[i]); + wpa_snprintf_hex(buf, 2 * len + 1, value, len); return buf; } @@ -205,7 +198,7 @@ static char * wpa_config_write_str(const struct parse_data *data, if (data->param2) len = *((size_t *) (((u8 *) ssid) + (long) data->param2)); else - len = strlen(*src); + len = os_strlen(*src); return wpa_config_write_string((const u8 *) *src, len); } @@ -249,10 +242,11 @@ static char * wpa_config_write_int(const struct parse_data *data, src = (int *) (((u8 *) ssid) + (long) data->param1); - value = malloc(20); + value = os_malloc(20); if (value == NULL) return NULL; - snprintf(value, 20, "%d", *src); + os_snprintf(value, 20, "%d", *src); + value[20 - 1] = '\0'; return value; } @@ -280,10 +274,11 @@ static char * wpa_config_write_bssid(const struct parse_data *data, if (!ssid->bssid_set) return NULL; - value = malloc(20); + value = os_malloc(20); if (value == NULL) return NULL; - snprintf(value, 20, MACSTR, MAC2STR(ssid->bssid)); + os_snprintf(value, 20, MACSTR, MAC2STR(ssid->bssid)); + value[20 - 1] = '\0'; return value; } @@ -293,14 +288,15 @@ static int wpa_config_parse_psk(const struct parse_data *data, const char *value) { if (*value == '"') { - char *pos; + const char *pos; size_t len; value++; - pos = strrchr(value, '"'); + pos = os_strrchr(value, '"'); if (pos) - *pos = '\0'; - len = strlen(value); + len = pos - value; + else + len = os_strlen(value); if (len < 8 || len > 63) { wpa_printf(MSG_ERROR, "Line %d: Invalid passphrase " "length %lu (expected: 8..63) '%s'.", @@ -309,8 +305,17 @@ static int wpa_config_parse_psk(const struct parse_data *data, } wpa_hexdump_ascii_key(MSG_MSGDUMP, "PSK (ASCII passphrase)", (u8 *) value, len); - ssid->passphrase = strdup(value); - return ssid->passphrase == NULL ? -1 : 0; + if (ssid->passphrase && os_strlen(ssid->passphrase) == len && + os_memcmp(ssid->passphrase, value, len) == 0) + return 0; + ssid->psk_set = 0; + os_free(ssid->passphrase); + ssid->passphrase = os_malloc(len + 1); + if (ssid->passphrase == NULL) + return -1; + os_memcpy(ssid->passphrase, value, len); + ssid->passphrase[len] = '\0'; + return 0; } if (hexstr2bin(value, ssid->psk, PMK_LEN) || @@ -319,6 +324,10 @@ static int wpa_config_parse_psk(const struct parse_data *data, line, value); return -1; } + + os_free(ssid->passphrase); + ssid->passphrase = NULL; + ssid->psk_set = 1; wpa_hexdump_key(MSG_MSGDUMP, "PSK", ssid->psk, PMK_LEN); return 0; @@ -331,7 +340,7 @@ static char * wpa_config_write_psk(const struct parse_data *data, if (ssid->passphrase) return wpa_config_write_string_ascii( (const u8 *) ssid->passphrase, - strlen(ssid->passphrase)); + os_strlen(ssid->passphrase)); if (ssid->psk_set) return wpa_config_write_string_hex(ssid->psk, PMK_LEN); @@ -347,7 +356,7 @@ static int wpa_config_parse_proto(const struct parse_data *data, int val = 0, last, errors = 0; char *start, *end, *buf; - buf = strdup(value); + buf = os_strdup(value); if (buf == NULL) return -1; start = buf; @@ -362,10 +371,10 @@ static int wpa_config_parse_proto(const struct parse_data *data, end++; last = *end == '\0'; *end = '\0'; - if (strcmp(start, "WPA") == 0) + if (os_strcmp(start, "WPA") == 0) val |= WPA_PROTO_WPA; - else if (strcmp(start, "RSN") == 0 || - strcmp(start, "WPA2") == 0) + else if (os_strcmp(start, "RSN") == 0 || + os_strcmp(start, "WPA2") == 0) val |= WPA_PROTO_RSN; else { wpa_printf(MSG_ERROR, "Line %d: invalid proto '%s'", @@ -377,7 +386,7 @@ static int wpa_config_parse_proto(const struct parse_data *data, break; start = end + 1; } - free(buf); + os_free(buf); if (val == 0) { wpa_printf(MSG_ERROR, @@ -394,22 +403,27 @@ static int wpa_config_parse_proto(const struct parse_data *data, static char * wpa_config_write_proto(const struct parse_data *data, struct wpa_ssid *ssid) { - int first = 1; + int first = 1, ret; char *buf, *pos, *end; - pos = buf = malloc(10); + pos = buf = os_zalloc(10); if (buf == NULL) return NULL; - memset(buf, 0, 10); end = buf + 10; if (ssid->proto & WPA_PROTO_WPA) { - pos += snprintf(pos, end - pos, "%sWPA", first ? "" : " "); + ret = os_snprintf(pos, end - pos, "%sWPA", first ? "" : " "); + if (ret < 0 || ret >= end - pos) + return buf; + pos += ret; first = 0; } if (ssid->proto & WPA_PROTO_RSN) { - pos += snprintf(pos, end - pos, "%sRSN", first ? "" : " "); + ret = os_snprintf(pos, end - pos, "%sRSN", first ? "" : " "); + if (ret < 0 || ret >= end - pos) + return buf; + pos += ret; first = 0; } @@ -424,7 +438,7 @@ static int wpa_config_parse_key_mgmt(const struct parse_data *data, int val = 0, last, errors = 0; char *start, *end, *buf; - buf = strdup(value); + buf = os_strdup(value); if (buf == NULL) return -1; start = buf; @@ -439,15 +453,15 @@ static int wpa_config_parse_key_mgmt(const struct parse_data *data, end++; last = *end == '\0'; *end = '\0'; - if (strcmp(start, "WPA-PSK") == 0) + if (os_strcmp(start, "WPA-PSK") == 0) val |= WPA_KEY_MGMT_PSK; - else if (strcmp(start, "WPA-EAP") == 0) + else if (os_strcmp(start, "WPA-EAP") == 0) val |= WPA_KEY_MGMT_IEEE8021X; - else if (strcmp(start, "IEEE8021X") == 0) + else if (os_strcmp(start, "IEEE8021X") == 0) val |= WPA_KEY_MGMT_IEEE8021X_NO_WPA; - else if (strcmp(start, "NONE") == 0) + else if (os_strcmp(start, "NONE") == 0) val |= WPA_KEY_MGMT_NONE; - else if (strcmp(start, "WPA-NONE") == 0) + else if (os_strcmp(start, "WPA-NONE") == 0) val |= WPA_KEY_MGMT_WPA_NONE; else { wpa_printf(MSG_ERROR, "Line %d: invalid key_mgmt '%s'", @@ -459,7 +473,7 @@ static int wpa_config_parse_key_mgmt(const struct parse_data *data, break; start = end + 1; } - free(buf); + os_free(buf); if (val == 0) { wpa_printf(MSG_ERROR, @@ -476,40 +490,62 @@ static int wpa_config_parse_key_mgmt(const struct parse_data *data, static char * wpa_config_write_key_mgmt(const struct parse_data *data, struct wpa_ssid *ssid) { - int first = 1; char *buf, *pos, *end; + int ret; - pos = buf = malloc(50); + pos = buf = os_zalloc(50); if (buf == NULL) return NULL; - memset(buf, 0, 50); end = buf + 50; if (ssid->key_mgmt & WPA_KEY_MGMT_PSK) { - pos += snprintf(pos, end - pos, "%sWPA-PSK", first ? "" : " "); - first = 0; + ret = os_snprintf(pos, end - pos, "%sWPA-PSK", + pos == buf ? "" : " "); + if (ret < 0 || ret >= end - pos) { + end[-1] = '\0'; + return buf; + } + pos += ret; } if (ssid->key_mgmt & WPA_KEY_MGMT_IEEE8021X) { - pos += snprintf(pos, end - pos, "%sWPA-EAP", first ? "" : " "); - first = 0; + ret = os_snprintf(pos, end - pos, "%sWPA-EAP", + pos == buf ? "" : " "); + if (ret < 0 || ret >= end - pos) { + end[-1] = '\0'; + return buf; + } + pos += ret; } if (ssid->key_mgmt & WPA_KEY_MGMT_IEEE8021X_NO_WPA) { - pos += snprintf(pos, end - pos, "%sIEEE8021X", - first ? "" : " "); - first = 0; + ret = os_snprintf(pos, end - pos, "%sIEEE8021X", + pos == buf ? "" : " "); + if (ret < 0 || ret >= end - pos) { + end[-1] = '\0'; + return buf; + } + pos += ret; } if (ssid->key_mgmt & WPA_KEY_MGMT_NONE) { - pos += snprintf(pos, end - pos, "%sNONE", first ? "" : " "); - first = 0; + ret = os_snprintf(pos, end - pos, "%sNONE", + pos == buf ? "" : " "); + if (ret < 0 || ret >= end - pos) { + end[-1] = '\0'; + return buf; + } + pos += ret; } if (ssid->key_mgmt & WPA_KEY_MGMT_WPA_NONE) { - pos += snprintf(pos, end - pos, "%sWPA-NONE", - first ? "" : " "); - first = 0; + ret = os_snprintf(pos, end - pos, "%sWPA-NONE", + pos == buf ? "" : " "); + if (ret < 0 || ret >= end - pos) { + end[-1] = '\0'; + return buf; + } + pos += ret; } return buf; @@ -521,7 +557,7 @@ static int wpa_config_parse_cipher(int line, const char *value) int val = 0, last; char *start, *end, *buf; - buf = strdup(value); + buf = os_strdup(value); if (buf == NULL) return -1; start = buf; @@ -536,20 +572,20 @@ static int wpa_config_parse_cipher(int line, const char *value) end++; last = *end == '\0'; *end = '\0'; - if (strcmp(start, "CCMP") == 0) + if (os_strcmp(start, "CCMP") == 0) val |= WPA_CIPHER_CCMP; - else if (strcmp(start, "TKIP") == 0) + else if (os_strcmp(start, "TKIP") == 0) val |= WPA_CIPHER_TKIP; - else if (strcmp(start, "WEP104") == 0) + else if (os_strcmp(start, "WEP104") == 0) val |= WPA_CIPHER_WEP104; - else if (strcmp(start, "WEP40") == 0) + else if (os_strcmp(start, "WEP40") == 0) val |= WPA_CIPHER_WEP40; - else if (strcmp(start, "NONE") == 0) + else if (os_strcmp(start, "NONE") == 0) val |= WPA_CIPHER_NONE; else { wpa_printf(MSG_ERROR, "Line %d: invalid cipher '%s'.", line, start); - free(buf); + os_free(buf); return -1; } @@ -557,7 +593,7 @@ static int wpa_config_parse_cipher(int line, const char *value) break; start = end + 1; } - free(buf); + os_free(buf); if (val == 0) { wpa_printf(MSG_ERROR, "Line %d: no cipher values configured.", @@ -570,38 +606,62 @@ static int wpa_config_parse_cipher(int line, const char *value) static char * wpa_config_write_cipher(int cipher) { - int first = 1; char *buf, *pos, *end; + int ret; - pos = buf = malloc(50); + pos = buf = os_zalloc(50); if (buf == NULL) return NULL; - memset(buf, 0, 50); end = buf + 50; if (cipher & WPA_CIPHER_CCMP) { - pos += snprintf(pos, end - pos, "%sCCMP", first ? "" : " "); - first = 0; + ret = os_snprintf(pos, end - pos, "%sCCMP", + pos == buf ? "" : " "); + if (ret < 0 || ret >= end - pos) { + end[-1] = '\0'; + return buf; + } + pos += ret; } if (cipher & WPA_CIPHER_TKIP) { - pos += snprintf(pos, end - pos, "%sTKIP", first ? "" : " "); - first = 0; + ret = os_snprintf(pos, end - pos, "%sTKIP", + pos == buf ? "" : " "); + if (ret < 0 || ret >= end - pos) { + end[-1] = '\0'; + return buf; + } + pos += ret; } if (cipher & WPA_CIPHER_WEP104) { - pos += snprintf(pos, end - pos, "%sWEP104", first ? "" : " "); - first = 0; + ret = os_snprintf(pos, end - pos, "%sWEP104", + pos == buf ? "" : " "); + if (ret < 0 || ret >= end - pos) { + end[-1] = '\0'; + return buf; + } + pos += ret; } if (cipher & WPA_CIPHER_WEP40) { - pos += snprintf(pos, end - pos, "%sWEP40", first ? "" : " "); - first = 0; + ret = os_snprintf(pos, end - pos, "%sWEP40", + pos == buf ? "" : " "); + if (ret < 0 || ret >= end - pos) { + end[-1] = '\0'; + return buf; + } + pos += ret; } if (cipher & WPA_CIPHER_NONE) { - pos += snprintf(pos, end - pos, "%sNONE", first ? "" : " "); - first = 0; + ret = os_snprintf(pos, end - pos, "%sNONE", + pos == buf ? "" : " "); + if (ret < 0 || ret >= end - pos) { + end[-1] = '\0'; + return buf; + } + pos += ret; } return buf; @@ -670,7 +730,7 @@ static int wpa_config_parse_auth_alg(const struct parse_data *data, int val = 0, last, errors = 0; char *start, *end, *buf; - buf = strdup(value); + buf = os_strdup(value); if (buf == NULL) return -1; start = buf; @@ -685,11 +745,11 @@ static int wpa_config_parse_auth_alg(const struct parse_data *data, end++; last = *end == '\0'; *end = '\0'; - if (strcmp(start, "OPEN") == 0) + if (os_strcmp(start, "OPEN") == 0) val |= WPA_AUTH_ALG_OPEN; - else if (strcmp(start, "SHARED") == 0) + else if (os_strcmp(start, "SHARED") == 0) val |= WPA_AUTH_ALG_SHARED; - else if (strcmp(start, "LEAP") == 0) + else if (os_strcmp(start, "LEAP") == 0) val |= WPA_AUTH_ALG_LEAP; else { wpa_printf(MSG_ERROR, "Line %d: invalid auth_alg '%s'", @@ -701,7 +761,7 @@ static int wpa_config_parse_auth_alg(const struct parse_data *data, break; start = end + 1; } - free(buf); + os_free(buf); if (val == 0) { wpa_printf(MSG_ERROR, @@ -718,44 +778,59 @@ static int wpa_config_parse_auth_alg(const struct parse_data *data, static char * wpa_config_write_auth_alg(const struct parse_data *data, struct wpa_ssid *ssid) { - int first = 1; char *buf, *pos, *end; + int ret; - pos = buf = malloc(30); + pos = buf = os_zalloc(30); if (buf == NULL) return NULL; - memset(buf, 0, 30); end = buf + 30; if (ssid->auth_alg & WPA_AUTH_ALG_OPEN) { - pos += snprintf(pos, end - pos, "%sOPEN", first ? "" : " "); - first = 0; + ret = os_snprintf(pos, end - pos, "%sOPEN", + pos == buf ? "" : " "); + if (ret < 0 || ret >= end - pos) { + end[-1] = '\0'; + return buf; + } + pos += ret; } if (ssid->auth_alg & WPA_AUTH_ALG_SHARED) { - pos += snprintf(pos, end - pos, "%sSHARED", first ? "" : " "); - first = 0; + ret = os_snprintf(pos, end - pos, "%sSHARED", + pos == buf ? "" : " "); + if (ret < 0 || ret >= end - pos) { + end[-1] = '\0'; + return buf; + } + pos += ret; } if (ssid->auth_alg & WPA_AUTH_ALG_LEAP) { - pos += snprintf(pos, end - pos, "%sLEAP", first ? "" : " "); - first = 0; + ret = os_snprintf(pos, end - pos, "%sLEAP", + pos == buf ? "" : " "); + if (ret < 0 || ret >= end - pos) { + end[-1] = '\0'; + return buf; + } + pos += ret; } return buf; } +#ifdef IEEE8021X_EAPOL static int wpa_config_parse_eap(const struct parse_data *data, struct wpa_ssid *ssid, int line, const char *value) { int last, errors = 0; char *start, *end, *buf; - u8 *methods = NULL, *tmp; + struct eap_method_type *methods = NULL, *tmp; size_t num_methods = 0; - buf = strdup(value); + buf = os_strdup(value); if (buf == NULL) return -1; start = buf; @@ -771,13 +846,17 @@ static int wpa_config_parse_eap(const struct parse_data *data, last = *end == '\0'; *end = '\0'; tmp = methods; - methods = realloc(methods, num_methods + 1); + methods = os_realloc(methods, + (num_methods + 1) * sizeof(*methods)); if (methods == NULL) { - free(tmp); + os_free(tmp); + os_free(buf); return -1; } - methods[num_methods] = eap_get_type(start); - if (methods[num_methods] == EAP_TYPE_NONE) { + methods[num_methods].method = eap_get_type( + start, &methods[num_methods].vendor); + if (methods[num_methods].vendor == EAP_VENDOR_IETF && + methods[num_methods].method == EAP_TYPE_NONE) { wpa_printf(MSG_ERROR, "Line %d: unknown EAP method " "'%s'", line, start); wpa_printf(MSG_ERROR, "You may need to add support for" @@ -785,7 +864,8 @@ static int wpa_config_parse_eap(const struct parse_data *data, "build time configuration.\n" "See README for more information."); errors++; - } else if (methods[num_methods] == EAP_TYPE_LEAP) + } else if (methods[num_methods].vendor == EAP_VENDOR_IETF && + methods[num_methods].method == EAP_TYPE_LEAP) ssid->leap++; else ssid->non_leap++; @@ -794,18 +874,20 @@ static int wpa_config_parse_eap(const struct parse_data *data, break; start = end + 1; } - free(buf); + os_free(buf); tmp = methods; - methods = realloc(methods, num_methods + 1); + methods = os_realloc(methods, (num_methods + 1) * sizeof(*methods)); if (methods == NULL) { - free(tmp); + os_free(tmp); return -1; } - methods[num_methods] = EAP_TYPE_NONE; + methods[num_methods].vendor = EAP_VENDOR_IETF; + methods[num_methods].method = EAP_TYPE_NONE; num_methods++; - wpa_hexdump(MSG_MSGDUMP, "eap methods", methods, num_methods); + wpa_hexdump(MSG_MSGDUMP, "eap methods", + (u8 *) methods, num_methods * sizeof(*methods)); ssid->eap_methods = methods; return errors ? -1 : 0; } @@ -814,31 +896,37 @@ static int wpa_config_parse_eap(const struct parse_data *data, static char * wpa_config_write_eap(const struct parse_data *data, struct wpa_ssid *ssid) { - int first = 1; + int i, ret; char *buf, *pos, *end; - const u8 *eap_methods = ssid->eap_methods; + const struct eap_method_type *eap_methods = ssid->eap_methods; const char *name; if (eap_methods == NULL) return NULL; - pos = buf = malloc(100); + pos = buf = os_zalloc(100); if (buf == NULL) return NULL; - memset(buf, 0, 100); end = buf + 100; - while (*eap_methods != EAP_TYPE_NONE) { - name = eap_get_name(*eap_methods); - if (name) - pos += snprintf(pos, end - pos, "%s%s", - first ? "" : " ", name); - first = 0; - eap_methods++; + for (i = 0; eap_methods[i].vendor != EAP_VENDOR_IETF || + eap_methods[i].method != EAP_TYPE_NONE; i++) { + name = eap_get_name(eap_methods[i].vendor, + eap_methods[i].method); + if (name) { + ret = os_snprintf(pos, end - pos, "%s%s", + pos == buf ? "" : " ", name); + if (ret < 0 || ret >= end - pos) + break; + pos += ret; + } } + end[-1] = '\0'; + return buf; } +#endif /* IEEE8021X_EAPOL */ static int wpa_config_parse_wep_key(u8 *key, size_t *len, int line, @@ -855,12 +943,12 @@ static int wpa_config_parse_wep_key(u8 *key, size_t *len, int line, if (*len > MAX_WEP_KEY_LEN) { wpa_printf(MSG_ERROR, "Line %d: Too long WEP key %d '%s'.", line, idx, value); - free(buf); + os_free(buf); return -1; } - memcpy(key, buf, *len); - free(buf); - snprintf(title, sizeof(title), "wep_key%d", idx); + os_memcpy(key, buf, *len); + os_free(buf); + os_snprintf(title, sizeof(title), "wep_key%d", idx); wpa_hexdump_key(MSG_MSGDUMP, title, key, *len); return 0; } @@ -945,42 +1033,50 @@ static char * wpa_config_write_wep_key3(const struct parse_data *data, /* Helper macros for network block parser */ +#ifdef OFFSET +#undef OFFSET +#endif /* OFFSET */ /* OFFSET: Get offset of a variable within the wpa_ssid structure */ #define OFFSET(v) ((void *) &((struct wpa_ssid *) 0)->v) /* STR: Define a string variable for an ASCII string; f = field name */ -#define STR(f) .name = #f, .parser = wpa_config_parse_str, \ - .writer = wpa_config_write_str, .param1 = OFFSET(f) +#define _STR(f) #f, wpa_config_parse_str, wpa_config_write_str, OFFSET(f) +#define STR(f) _STR(f), NULL, NULL, NULL, 0 +#define STR_KEY(f) _STR(f), NULL, NULL, NULL, 1 /* STR_LEN: Define a string variable with a separate variable for storing the * data length. Unlike STR(), this can be used to store arbitrary binary data * (i.e., even nul termination character). */ -#define STR_LEN(f) STR(f), .param2 = OFFSET(f ## _len) +#define _STR_LEN(f) _STR(f), OFFSET(f ## _len) +#define STR_LEN(f) _STR_LEN(f), NULL, NULL, 0 +#define STR_LEN_KEY(f) _STR_LEN(f), NULL, NULL, 1 /* STR_RANGE: Like STR_LEN(), but with minimum and maximum allowed length * explicitly specified. */ -#define STR_RANGE(f, min, max) STR_LEN(f), .param3 = (void *) (min), \ - .param4 = (void *) (max) +#define _STR_RANGE(f, min, max) _STR_LEN(f), (void *) (min), (void *) (max) +#define STR_RANGE(f, min, max) _STR_RANGE(f, min, max), 0 +#define STR_RANGE_KEY(f, min, max) _STR_RANGE(f, min, max), 1 +#define _INT(f) #f, wpa_config_parse_int, wpa_config_write_int, \ + OFFSET(f), (void *) 0 /* INT: Define an integer variable */ -#define INT(f) .name = #f, .parser = wpa_config_parse_int, \ - .writer = wpa_config_write_int, \ - .param1 = OFFSET(f), .param2 = (void *) 0 +#define INT(f) _INT(f), NULL, NULL, 0 -/* INT: Define an integer variable with allowed value range */ -#define INT_RANGE(f, min, max) INT(f), .param3 = (void *) (min), \ - .param4 = (void *) (max) +/* INT_RANGE: Define an integer variable with allowed value range */ +#define INT_RANGE(f, min, max) _INT(f), (void *) (min), (void *) (max), 0 /* FUNC: Define a configuration variable that uses a custom function for * parsing and writing the value. */ -#define FUNC(f) .name = #f, .parser = wpa_config_parse_ ## f, \ - .writer = wpa_config_write_ ## f +#define _FUNC(f) #f, wpa_config_parse_ ## f, wpa_config_write_ ## f, \ + NULL, NULL, NULL, NULL +#define FUNC(f) _FUNC(f), 0 +#define FUNC_KEY(f) _FUNC(f), 1 /* * Table of network configuration variables. This table is used to parse each * network configuration variable, e.g., each line in wpa_supplicant.conf file - * that is insider a network block. + * that is inside a network block. * * This table is generated using the helper macros defined above and with * generous help from the C pre-processor. The field name is stored as a string @@ -995,31 +1091,33 @@ static char * wpa_config_write_wep_key3(const struct parse_data *data, * function (.parser) is then called to parse the actual value of the field. * * This kind of mechanism makes it easy to add new configuration parameters, - * since only one line needs to be added into this table and in struct wpa_ssid - * definitions if the new variable is either a string or integer. More complex - * types will need to use their own parser and writer functions. + * since only one line needs to be added into this table and into the + * struct wpa_ssid definition if the new variable is either a string or + * integer. More complex types will need to use their own parser and writer + * functions. */ static const struct parse_data ssid_fields[] = { { STR_RANGE(ssid, 0, MAX_SSID_LEN) }, { INT_RANGE(scan_ssid, 0, 1) }, { FUNC(bssid) }, - { FUNC(psk), .key_data = 1 }, + { FUNC_KEY(psk) }, { FUNC(proto) }, { FUNC(key_mgmt) }, { FUNC(pairwise) }, { FUNC(group) }, { FUNC(auth_alg) }, +#ifdef IEEE8021X_EAPOL { FUNC(eap) }, { STR_LEN(identity) }, { STR_LEN(anonymous_identity) }, - { STR_RANGE(eappsk, EAP_PSK_LEN, EAP_PSK_LEN), .key_data = 1 }, + { STR_RANGE_KEY(eappsk, EAP_PSK_LEN_MIN, EAP_PSK_LEN_MAX) }, { STR_LEN(nai) }, - { STR_LEN(password), .key_data = 1 }, + { STR_LEN_KEY(password) }, { STR(ca_cert) }, { STR(ca_path) }, { STR(client_cert) }, { STR(private_key) }, - { STR(private_key_passwd), .key_data = 1 }, + { STR_KEY(private_key_passwd) }, { STR(dh_file) }, { STR(subject_match) }, { STR(altsubject_match) }, @@ -1027,44 +1125,64 @@ static const struct parse_data ssid_fields[] = { { STR(ca_path2) }, { STR(client_cert2) }, { STR(private_key2) }, - { STR(private_key2_passwd), .key_data = 1 }, + { STR_KEY(private_key2_passwd) }, { STR(dh_file2) }, { STR(subject_match2) }, { STR(altsubject_match2) }, { STR(phase1) }, { STR(phase2) }, { STR(pcsc) }, - { STR(pin), .key_data = 1 }, + { STR_KEY(pin) }, { STR(engine_id) }, { STR(key_id) }, { INT(engine) }, { INT(eapol_flags) }, - { FUNC(wep_key0), .key_data = 1 }, - { FUNC(wep_key1), .key_data = 1 }, - { FUNC(wep_key2), .key_data = 1 }, - { FUNC(wep_key3), .key_data = 1 }, +#endif /* IEEE8021X_EAPOL */ + { FUNC_KEY(wep_key0) }, + { FUNC_KEY(wep_key1) }, + { FUNC_KEY(wep_key2) }, + { FUNC_KEY(wep_key3) }, { INT(wep_tx_keyidx) }, { INT(priority) }, +#ifdef IEEE8021X_EAPOL { INT(eap_workaround) }, { STR(pac_file) }, + { INT(fragment_size) }, +#endif /* IEEE8021X_EAPOL */ { INT_RANGE(mode, 0, 1) }, { INT_RANGE(proactive_key_caching, 0, 1) }, { INT_RANGE(disabled, 0, 1) }, + { STR(id_str) }, +#ifdef CONFIG_IEEE80211W + { INT_RANGE(ieee80211w, 0, 2) }, +#endif /* CONFIG_IEEE80211W */ + { INT_RANGE(peerkey, 0, 1) }, + { INT_RANGE(mixed_cell, 0, 1) } }; #undef OFFSET +#undef _STR #undef STR +#undef STR_KEY +#undef _STR_LEN #undef STR_LEN +#undef STR_LEN_KEY +#undef _STR_RANGE #undef STR_RANGE +#undef STR_RANGE_KEY +#undef _INT #undef INT #undef INT_RANGE +#undef _FUNC #undef FUNC +#undef FUNC_KEY #define NUM_SSID_FIELDS (sizeof(ssid_fields) / sizeof(ssid_fields[0])) /** * wpa_config_add_prio_network - Add a network to priority lists * @config: Configuration data from wpa_config_read() + * @ssid: Pointer to the network configuration to be added to the list * Returns: 0 on success, -1 on failure * * This function is used to add a network block to the priority list of @@ -1078,6 +1196,10 @@ int wpa_config_add_prio_network(struct wpa_config *config, int prio; struct wpa_ssid *prev, **nlist; + /* + * Add to an existing priority list if one is available for the + * configured priority level for this network. + */ for (prio = 0; prio < config->num_prio; prio++) { prev = config->pssid[prio]; if (prev->priority == ssid->priority) { @@ -1088,9 +1210,9 @@ int wpa_config_add_prio_network(struct wpa_config *config, } } - /* First network for this priority - add new priority list */ - nlist = realloc(config->pssid, - (config->num_prio + 1) * sizeof(struct wpa_ssid *)); + /* First network for this priority - add a new priority list */ + nlist = os_realloc(config->pssid, + (config->num_prio + 1) * sizeof(struct wpa_ssid *)); if (nlist == NULL) return -1; @@ -1099,8 +1221,8 @@ int wpa_config_add_prio_network(struct wpa_config *config, break; } - memmove(&nlist[prio + 1], &nlist[prio], - (config->num_prio - prio) * sizeof(struct wpa_ssid *)); + os_memmove(&nlist[prio + 1], &nlist[prio], + (config->num_prio - prio) * sizeof(struct wpa_ssid *)); nlist[prio] = ssid; config->num_prio++; @@ -1124,7 +1246,7 @@ static int wpa_config_update_prio_list(struct wpa_config *config) struct wpa_ssid *ssid; int ret = 0; - free(config->pssid); + os_free(config->pssid); config->pssid = NULL; config->num_prio = 0; @@ -1144,46 +1266,49 @@ static int wpa_config_update_prio_list(struct wpa_config *config) * wpa_config_free_ssid - Free network/ssid configuration data * @ssid: Configuration data for the network * - * This function frees all resources allocated for the netowkr configuration + * This function frees all resources allocated for the network configuration * data. */ void wpa_config_free_ssid(struct wpa_ssid *ssid) { - free(ssid->ssid); - free(ssid->passphrase); - free(ssid->eap_methods); - free(ssid->identity); - free(ssid->anonymous_identity); - free(ssid->eappsk); - free(ssid->nai); - free(ssid->password); - free(ssid->ca_cert); - free(ssid->ca_path); - free(ssid->client_cert); - free(ssid->private_key); - free(ssid->private_key_passwd); - free(ssid->dh_file); - free(ssid->subject_match); - free(ssid->altsubject_match); - free(ssid->ca_cert2); - free(ssid->ca_path2); - free(ssid->client_cert2); - free(ssid->private_key2); - free(ssid->private_key2_passwd); - free(ssid->dh_file2); - free(ssid->subject_match2); - free(ssid->altsubject_match2); - free(ssid->phase1); - free(ssid->phase2); - free(ssid->pcsc); - free(ssid->pin); - free(ssid->engine_id); - free(ssid->key_id); - free(ssid->otp); - free(ssid->pending_req_otp); - free(ssid->pac_file); - free(ssid->new_password); - free(ssid); + os_free(ssid->ssid); + os_free(ssid->passphrase); +#ifdef IEEE8021X_EAPOL + os_free(ssid->eap_methods); + os_free(ssid->identity); + os_free(ssid->anonymous_identity); + os_free(ssid->eappsk); + os_free(ssid->nai); + os_free(ssid->password); + os_free(ssid->ca_cert); + os_free(ssid->ca_path); + os_free(ssid->client_cert); + os_free(ssid->private_key); + os_free(ssid->private_key_passwd); + os_free(ssid->dh_file); + os_free(ssid->subject_match); + os_free(ssid->altsubject_match); + os_free(ssid->ca_cert2); + os_free(ssid->ca_path2); + os_free(ssid->client_cert2); + os_free(ssid->private_key2); + os_free(ssid->private_key2_passwd); + os_free(ssid->dh_file2); + os_free(ssid->subject_match2); + os_free(ssid->altsubject_match2); + os_free(ssid->phase1); + os_free(ssid->phase2); + os_free(ssid->pcsc); + os_free(ssid->pin); + os_free(ssid->engine_id); + os_free(ssid->key_id); + os_free(ssid->otp); + os_free(ssid->pending_req_otp); + os_free(ssid->pac_file); + os_free(ssid->new_password); +#endif /* IEEE8021X_EAPOL */ + os_free(ssid->id_str); + os_free(ssid); } @@ -1213,37 +1338,43 @@ void wpa_config_free(struct wpa_config *config) wpa_config_free_blob(prevblob); } - free(config->ctrl_interface); - free(config->opensc_engine_path); - free(config->pkcs11_engine_path); - free(config->pkcs11_module_path); - free(config->driver_param); - free(config->pssid); - free(config); + os_free(config->ctrl_interface); + os_free(config->ctrl_interface_group); + os_free(config->opensc_engine_path); + os_free(config->pkcs11_engine_path); + os_free(config->pkcs11_module_path); + os_free(config->driver_param); + os_free(config->pssid); + os_free(config); } +#ifdef IEEE8021X_EAPOL /** * wpa_config_allowed_eap_method - Check whether EAP method is allowed - * @ssid: Pointer to a configuration data + * @ssid: Pointer to configuration data + * @vendor: Vendor-Id for expanded types or 0 = IETF for legacy types * @method: EAP type * Returns: 1 = allowed EAP method, 0 = not allowed */ -int wpa_config_allowed_eap_method(struct wpa_ssid *ssid, int method) +int wpa_config_allowed_eap_method(struct wpa_ssid *ssid, int vendor, + u32 method) { - u8 *pos; + int i; + struct eap_method_type *m; if (ssid == NULL || ssid->eap_methods == NULL) return 1; - pos = ssid->eap_methods; - while (*pos != EAP_TYPE_NONE) { - if (*pos == method) + m = ssid->eap_methods; + for (i = 0; m[i].vendor != EAP_VENDOR_IETF || + m[i].method != EAP_TYPE_NONE; i++) { + if (m[i].vendor == vendor && m[i].method == method) return 1; - pos++; } return 0; } +#endif /* IEEE8021X_EAPOL */ /** @@ -1287,10 +1418,9 @@ struct wpa_ssid * wpa_config_add_network(struct wpa_config *config) } id++; - ssid = malloc(sizeof(*ssid)); + ssid = os_zalloc(sizeof(*ssid)); if (ssid == NULL) return NULL; - memset(ssid, 0, sizeof(*ssid)); ssid->id = id; if (last) last->next = ssid; @@ -1337,7 +1467,7 @@ int wpa_config_remove_network(struct wpa_config *config, int id) /** * wpa_config_set_network_defaults - Set network default values - * @ssid: Pointer to a network configuration data + * @ssid: Pointer to network configuration data */ void wpa_config_set_network_defaults(struct wpa_ssid *ssid) { @@ -1345,14 +1475,17 @@ void wpa_config_set_network_defaults(struct wpa_ssid *ssid) ssid->pairwise_cipher = DEFAULT_PAIRWISE; ssid->group_cipher = DEFAULT_GROUP; ssid->key_mgmt = DEFAULT_KEY_MGMT; +#ifdef IEEE8021X_EAPOL ssid->eapol_flags = DEFAULT_EAPOL_FLAGS; ssid->eap_workaround = DEFAULT_EAP_WORKAROUND; + ssid->fragment_size = DEFAULT_FRAGMENT_SIZE; +#endif /* IEEE8021X_EAPOL */ } /** * wpa_config_set - Set a variable in network configuration - * @ssid: Pointer to a network configuration data + * @ssid: Pointer to network configuration data * @var: Variable name, e.g., "ssid" * @value: Variable value * @line: Line number in configuration file or 0 if not used @@ -1366,14 +1499,15 @@ void wpa_config_set_network_defaults(struct wpa_ssid *ssid) int wpa_config_set(struct wpa_ssid *ssid, const char *var, const char *value, int line) { - int i, ret = 0; + size_t i; + int ret = 0; if (ssid == NULL || var == NULL || value == NULL) return -1; for (i = 0; i < NUM_SSID_FIELDS; i++) { const struct parse_data *field = &ssid_fields[i]; - if (strcmp(var, field->name) != 0) + if (os_strcmp(var, field->name) != 0) continue; if (field->parser(field, ssid, line, value)) { @@ -1399,7 +1533,7 @@ int wpa_config_set(struct wpa_ssid *ssid, const char *var, const char *value, /** * wpa_config_get - Get a variable in network configuration - * @ssid: Pointer to a network configuration data + * @ssid: Pointer to network configuration data * @var: Variable name, e.g., "ssid" * Returns: Value of the variable or %NULL on failure * @@ -1411,14 +1545,14 @@ int wpa_config_set(struct wpa_ssid *ssid, const char *var, const char *value, */ char * wpa_config_get(struct wpa_ssid *ssid, const char *var) { - int i; + size_t i; if (ssid == NULL || var == NULL) return NULL; for (i = 0; i < NUM_SSID_FIELDS; i++) { const struct parse_data *field = &ssid_fields[i]; - if (strcmp(var, field->name) == 0) + if (os_strcmp(var, field->name) == 0) return field->writer(field, ssid); } @@ -1427,8 +1561,55 @@ char * wpa_config_get(struct wpa_ssid *ssid, const char *var) /** + * wpa_config_get_no_key - Get a variable in network configuration (no keys) + * @ssid: Pointer to network configuration data + * @var: Variable name, e.g., "ssid" + * Returns: Value of the variable or %NULL on failure + * + * This function can be used to get network configuration variable like + * wpa_config_get(). The only difference is that this functions does not expose + * key/password material from the configuration. In case a key/password field + * is requested, the returned value is an empty string or %NULL if the variable + * is not set or "*" if the variable is set (regardless of its value). The + * returned value is a copy of the configuration variable in text format, i.e,. + * the same format that the text-based configuration file and wpa_config_set() + * are using for the value. The caller is responsible for freeing the returned + * value. + */ +char * wpa_config_get_no_key(struct wpa_ssid *ssid, const char *var) +{ + size_t i; + + if (ssid == NULL || var == NULL) + return NULL; + + for (i = 0; i < NUM_SSID_FIELDS; i++) { + const struct parse_data *field = &ssid_fields[i]; + if (os_strcmp(var, field->name) == 0) { + char *res = field->writer(field, ssid); + if (field->key_data) { + if (res && res[0]) { + wpa_printf(MSG_DEBUG, "Do not allow " + "key_data field to be " + "exposed"); + os_free(res); + return os_strdup("*"); + } + + os_free(res); + return NULL; + } + return res; + } + } + + return NULL; +} + + +/** * wpa_config_update_psk - Update WPA PSK based on passphrase and SSID - * @ssid: Pointer to a network configuration data + * @ssid: Pointer to network configuration data * * This function must be called to update WPA PSK when either SSID or the * passphrase has changed for the network configuration. @@ -1456,7 +1637,7 @@ const struct wpa_config_blob * wpa_config_get_blob(struct wpa_config *config, struct wpa_config_blob *blob = config->blobs; while (blob) { - if (strcmp(blob->name, name) == 0) + if (os_strcmp(blob->name, name) == 0) return blob; blob = blob->next; } @@ -1488,9 +1669,9 @@ void wpa_config_set_blob(struct wpa_config *config, void wpa_config_free_blob(struct wpa_config_blob *blob) { if (blob) { - free(blob->name); - free(blob->data); - free(blob); + os_free(blob->name); + os_free(blob->data); + os_free(blob); } } @@ -1506,7 +1687,7 @@ int wpa_config_remove_blob(struct wpa_config *config, const char *name) struct wpa_config_blob *pos = config->blobs, *prev = NULL; while (pos) { - if (strcmp(pos->name, name) == 0) { + if (os_strcmp(pos->name, name) == 0) { if (prev) prev->next = pos->next; else @@ -1534,18 +1715,42 @@ struct wpa_config * wpa_config_alloc_empty(const char *ctrl_interface, { struct wpa_config *config; - config = malloc(sizeof(*config)); + config = os_zalloc(sizeof(*config)); if (config == NULL) return NULL; - memset(config, 0, sizeof(*config)); config->eapol_version = DEFAULT_EAPOL_VERSION; config->ap_scan = DEFAULT_AP_SCAN; config->fast_reauth = DEFAULT_FAST_REAUTH; if (ctrl_interface) - config->ctrl_interface = strdup(ctrl_interface); + config->ctrl_interface = os_strdup(ctrl_interface); if (driver_param) - config->driver_param = strdup(driver_param); + config->driver_param = os_strdup(driver_param); return config; } + + +#ifndef CONFIG_NO_STDOUT_DEBUG +/** + * wpa_config_debug_dump_networks - Debug dump of configured networks + * @config: Configuration data from wpa_config_read() + */ +void wpa_config_debug_dump_networks(struct wpa_config *config) +{ + int prio; + struct wpa_ssid *ssid; + + for (prio = 0; prio < config->num_prio; prio++) { + ssid = config->pssid[prio]; + wpa_printf(MSG_DEBUG, "Priority group %d", + ssid->priority); + while (ssid) { + wpa_printf(MSG_DEBUG, " id=%d ssid='%s'", + ssid->id, + wpa_ssid_txt(ssid->ssid, ssid->ssid_len)); + ssid = ssid->pnext; + } + } +} +#endif /* CONFIG_NO_STDOUT_DEBUG */ diff --git a/contrib/wpa_supplicant/config.h b/contrib/wpa_supplicant/config.h index bd479b6b4fb4..3852f9274e2b 100644 --- a/contrib/wpa_supplicant/config.h +++ b/contrib/wpa_supplicant/config.h @@ -1,6 +1,6 @@ /* * WPA Supplicant / Configuration file structures - * Copyright (c) 2003-2005, Jouni Malinen <jkmaline@cc.hut.fi> + * Copyright (c) 2003-2005, Jouni Malinen <j@w1.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 @@ -15,12 +15,6 @@ #ifndef CONFIG_H #define CONFIG_H -#ifdef CONFIG_CTRL_IFACE -#ifndef CONFIG_CTRL_IFACE_UDP -#include <grp.h> -#endif /* CONFIG_CTRL_IFACE_UDP */ -#endif /* CONFIG_CTRL_IFACE */ - #define DEFAULT_EAPOL_VERSION 1 #define DEFAULT_AP_SCAN 1 #define DEFAULT_FAST_REAUTH 1 @@ -128,45 +122,67 @@ struct wpa_config { int ap_scan; /** - * ctrl_interface - Directory for UNIX domain sockets + * ctrl_interface - Parameters for the control interface * - * This variable is used to configure where the UNIX domain sockets - * for the control interface are created. If UDP-based ctrl_iface is - * used, this variable can be set to any string (i.e., %NULL is not - * allowed). - */ - char *ctrl_interface; - -#ifdef CONFIG_CTRL_IFACE -#ifndef CONFIG_CTRL_IFACE_UDP - /** - * ctrl_interface_gid - Group identity for the UNIX domain sockets + * If this is specified, %wpa_supplicant will open a control interface + * that is available for external programs to manage %wpa_supplicant. + * The meaning of this string depends on which control interface + * mechanism is used. For all cases, the existance of this parameter + * in configuration is used to determine whether the control interface + * is enabled. + * + * For UNIX domain sockets (default on Linux and BSD): This is a + * directory that will be created for UNIX domain sockets for listening + * to requests from external programs (CLI/GUI, etc.) for status + * information and configuration. The socket file will be named based + * on the interface name, so multiple %wpa_supplicant processes can be + * run at the same time if more than one interface is used. + * /var/run/wpa_supplicant is the recommended directory for sockets and + * by default, wpa_cli will use it when trying to connect with + * %wpa_supplicant. * * Access control for the control interface can be configured * by setting the directory to allow only members of a group * to use sockets. This way, it is possible to run - * wpa_supplicant as root (since it needs to change network + * %wpa_supplicant as root (since it needs to change network * configuration and open raw sockets) and still allow GUI/CLI * components to be run as non-root users. However, since the * control interface can be used to change the network * configuration, this access needs to be protected in many - * cases. By default, wpa_supplicant is configured to use gid + * cases. By default, %wpa_supplicant is configured to use gid * 0 (root). If you want to allow non-root users to use the * control interface, add a new group and change this value to * match with that group. Add users that should have control * interface access to this group. + * + * When configuring both the directory and group, use following format: + * DIR=/var/run/wpa_supplicant GROUP=wheel + * DIR=/var/run/wpa_supplicant GROUP=0 + * (group can be either group name or gid) + * + * For UDP connections (default on Windows): The value will be ignored. + * This variable is just used to select that the control interface is + * to be created. The value can be set to, e.g., udp + * (ctrl_interface=udp). + * + * For Windows Named Pipe: This value can be used to set the security + * descriptor for controlling access to the control interface. Security + * descriptor can be set using Security Descriptor String Format (see + * http://msdn.microsoft.com/library/default.asp?url=/library/en-us/secauthz/security/security_descriptor_string_format.asp). + * The descriptor string needs to be prefixed with SDDL=. For example, + * ctrl_interface=SDDL=D: would set an empty DACL (which will reject + * all connections). */ - gid_t ctrl_interface_gid; -#endif /* CONFIG_CTRL_IFACE_UDP */ + char *ctrl_interface; + /** - * ctrl_interface_gid_set - Whether ctrl_interface_gid is used + * ctrl_interface_group - Control interface group (DEPRECATED) * - * If this variable is zero, ctrl_interface_gid value is not used and - * group will not be changed from the value it got by default - * when the directory or socket was created. + * This variable is only used for backwards compatibility. Group for + * UNIX domain sockets should now be specified using GROUP=<group> in + * ctrl_interface variable. */ - int ctrl_interface_gid_set; -#endif /* CONFIG_CTRL_IFACE */ + char *ctrl_interface_group; /** * fast_reauth - EAP fast re-authentication (session resumption) @@ -257,7 +273,7 @@ struct wpa_config { }; -/* Protypes for common functions from config.c */ +/* Prototypes for common functions from config.c */ void wpa_config_free(struct wpa_config *ssid); void wpa_config_free_ssid(struct wpa_ssid *ssid); @@ -268,6 +284,7 @@ void wpa_config_set_network_defaults(struct wpa_ssid *ssid); int wpa_config_set(struct wpa_ssid *ssid, const char *var, const char *value, int line); char * wpa_config_get(struct wpa_ssid *ssid, const char *var); +char * wpa_config_get_no_key(struct wpa_ssid *ssid, const char *var); void wpa_config_update_psk(struct wpa_ssid *ssid); int wpa_config_add_prio_network(struct wpa_config *config, struct wpa_ssid *ssid); @@ -280,6 +297,11 @@ void wpa_config_free_blob(struct wpa_config_blob *blob); int wpa_config_remove_blob(struct wpa_config *config, const char *name); struct wpa_config * wpa_config_alloc_empty(const char *ctrl_interface, const char *driver_param); +#ifndef CONFIG_NO_STDOUT_DEBUG +void wpa_config_debug_dump_networks(struct wpa_config *config); +#else /* CONFIG_NO_STDOUT_DEBUG */ +#define wpa_config_debug_dump_networks(c) do { } while (0) +#endif /* CONFIG_NO_STDOUT_DEBUG */ /* Prototypes for backend specific functions from the selected config_*.c */ diff --git a/contrib/wpa_supplicant/config_file.c b/contrib/wpa_supplicant/config_file.c index b203893d7547..757a1b8b1d6b 100644 --- a/contrib/wpa_supplicant/config_file.c +++ b/contrib/wpa_supplicant/config_file.c @@ -1,6 +1,6 @@ /* * WPA Supplicant / Configuration backend: text file - * Copyright (c) 2003-2005, Jouni Malinen <jkmaline@cc.hut.fi> + * Copyright (c) 2003-2006, Jouni Malinen <j@w1.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 @@ -16,18 +16,30 @@ * described in the sample configuration file, wpa_supplicant.conf. */ -#include <stdlib.h> -#include <stdio.h> -#include <string.h> +#include "includes.h" #include "common.h" -#include "wpa.h" -#include "wpa_supplicant.h" #include "config.h" #include "base64.h" - - -static char * wpa_config_get_line(char *s, int size, FILE *stream, int *line) +#include "eap_methods.h" + + +/** + * wpa_config_get_line - Read the next configuration file line + * @s: Buffer for the line + * @size: The buffer length + * @stream: File stream to read from + * @line: Pointer to a variable storing the file line number + * @_pos: Buffer for the pointer to the beginning of data on the text line or + * %NULL if not needed (returned value used instead) + * Returns: Pointer to the beginning of data on the text line or %NULL if no + * more text lines are available. + * + * This function reads the next non-empty line from the configuration file and + * removes comments. The returned string is guaranteed to be null-terminated. + */ +static char * wpa_config_get_line(char *s, int size, FILE *stream, int *line, + char **_pos) { char *pos, *end, *sstart; @@ -36,39 +48,82 @@ static char * wpa_config_get_line(char *s, int size, FILE *stream, int *line) s[size - 1] = '\0'; pos = s; + /* Skip white space from the beginning of line. */ while (*pos == ' ' || *pos == '\t' || *pos == '\r') pos++; - if (*pos == '#' || *pos == '\n' || *pos == '\0' || - *pos == '\r') + + /* Skip comment lines and empty lines */ + if (*pos == '#' || *pos == '\n' || *pos == '\0') continue; - /* Remove # comments unless they are within a double quoted - * string. Remove trailing white space. */ - sstart = strchr(pos, '"'); + /* + * Remove # comments unless they are within a double quoted + * string. + */ + sstart = os_strchr(pos, '"'); if (sstart) - sstart = strrchr(sstart + 1, '"'); + sstart = os_strrchr(sstart + 1, '"'); if (!sstart) sstart = pos; - end = strchr(sstart, '#'); + end = os_strchr(sstart, '#'); if (end) *end-- = '\0'; else - end = pos + strlen(pos) - 1; + end = pos + os_strlen(pos) - 1; + + /* Remove trailing white space. */ while (end > pos && (*end == '\n' || *end == ' ' || *end == '\t' || - *end == '\r')) { + *end == '\r')) *end-- = '\0'; - } + if (*pos == '\0') continue; + if (_pos) + *_pos = pos; return pos; } + if (_pos) + *_pos = NULL; return NULL; } +static int wpa_config_validate_network(struct wpa_ssid *ssid, int line) +{ + int errors = 0; + + if (ssid->passphrase) { + if (ssid->psk_set) { + wpa_printf(MSG_ERROR, "Line %d: both PSK and " + "passphrase configured.", line); + errors++; + } + wpa_config_update_psk(ssid); + } + + if ((ssid->key_mgmt & WPA_KEY_MGMT_PSK) && !ssid->psk_set) { + wpa_printf(MSG_ERROR, "Line %d: WPA-PSK accepted for key " + "management, but no PSK configured.", line); + errors++; + } + + if ((ssid->group_cipher & WPA_CIPHER_CCMP) && + !(ssid->pairwise_cipher & WPA_CIPHER_CCMP) && + !(ssid->pairwise_cipher & WPA_CIPHER_NONE)) { + /* Group cipher cannot be stronger than the pairwise cipher. */ + wpa_printf(MSG_DEBUG, "Line %d: removed CCMP from group cipher" + " list since it was not allowed for pairwise " + "cipher", line); + ssid->group_cipher &= ~WPA_CIPHER_CCMP; + } + + return errors; +} + + static struct wpa_ssid * wpa_config_read_network(FILE *f, int *line, int id) { struct wpa_ssid *ssid; @@ -77,21 +132,20 @@ static struct wpa_ssid * wpa_config_read_network(FILE *f, int *line, int id) wpa_printf(MSG_MSGDUMP, "Line: %d - start of a new network block", *line); - ssid = (struct wpa_ssid *) malloc(sizeof(*ssid)); + ssid = os_zalloc(sizeof(*ssid)); if (ssid == NULL) return NULL; - memset(ssid, 0, sizeof(*ssid)); ssid->id = id; wpa_config_set_network_defaults(ssid); - while ((pos = wpa_config_get_line(buf, sizeof(buf), f, line))) { - if (strcmp(pos, "}") == 0) { + while (wpa_config_get_line(buf, sizeof(buf), f, line, &pos)) { + if (os_strcmp(pos, "}") == 0) { end = 1; break; } - pos2 = strchr(pos, '='); + pos2 = os_strchr(pos, '='); if (pos2 == NULL) { wpa_printf(MSG_ERROR, "Line %d: Invalid SSID line " "'%s'.", *line, pos); @@ -101,7 +155,7 @@ static struct wpa_ssid * wpa_config_read_network(FILE *f, int *line, int id) *pos2++ = '\0'; if (*pos2 == '"') { - if (strchr(pos2 + 1, '"') == NULL) { + if (os_strchr(pos2 + 1, '"') == NULL) { wpa_printf(MSG_ERROR, "Line %d: invalid " "quotation '%s'.", *line, pos2); errors++; @@ -119,32 +173,10 @@ static struct wpa_ssid * wpa_config_read_network(FILE *f, int *line, int id) errors++; } - if (ssid->passphrase) { - if (ssid->psk_set) { - wpa_printf(MSG_ERROR, "Line %d: both PSK and " - "passphrase configured.", *line); - errors++; - } - wpa_config_update_psk(ssid); - } - - if ((ssid->key_mgmt & WPA_KEY_MGMT_PSK) && !ssid->psk_set) { - wpa_printf(MSG_ERROR, "Line %d: WPA-PSK accepted for key " - "management, but no PSK configured.", *line); - errors++; - } - - if ((ssid->group_cipher & WPA_CIPHER_CCMP) && - !(ssid->pairwise_cipher & WPA_CIPHER_CCMP)) { - /* Group cipher cannot be stronger than the pairwise cipher. */ - wpa_printf(MSG_DEBUG, "Line %d: removed CCMP from group cipher" - " list since it was not allowed for pairwise " - "cipher", *line); - ssid->group_cipher &= ~WPA_CIPHER_CCMP; - } + errors += wpa_config_validate_network(ssid, *line); if (errors) { - free(ssid); + wpa_config_free_ssid(ssid); ssid = NULL; } @@ -164,41 +196,40 @@ static struct wpa_config_blob * wpa_config_read_blob(FILE *f, int *line, wpa_printf(MSG_MSGDUMP, "Line: %d - start of a new named blob '%s'", *line, name); - while ((pos = wpa_config_get_line(buf, sizeof(buf), f, line))) { - if (strcmp(pos, "}") == 0) { + while (wpa_config_get_line(buf, sizeof(buf), f, line, &pos)) { + if (os_strcmp(pos, "}") == 0) { end = 1; break; } - len = strlen(pos); - nencoded = realloc(encoded, encoded_len + len); + len = os_strlen(pos); + nencoded = os_realloc(encoded, encoded_len + len); if (nencoded == NULL) { wpa_printf(MSG_ERROR, "Line %d: not enough memory for " "blob", *line); - free(encoded); + os_free(encoded); return NULL; } encoded = nencoded; - memcpy(encoded + encoded_len, pos, len); + os_memcpy(encoded + encoded_len, pos, len); encoded_len += len; } if (!end) { wpa_printf(MSG_ERROR, "Line %d: blob was not terminated " "properly", *line); - free(encoded); + os_free(encoded); return NULL; } - blob = malloc(sizeof(*blob)); + blob = os_zalloc(sizeof(*blob)); if (blob == NULL) { - free(encoded); + os_free(encoded); return NULL; } - memset(blob, 0, sizeof(*blob)); - blob->name = strdup(name); + blob->name = os_strdup(name); blob->data = base64_decode(encoded, encoded_len, &blob->len); - free(encoded); + os_free(encoded); if (blob->name == NULL || blob->data == NULL) { wpa_config_free_blob(blob); @@ -216,7 +247,7 @@ struct wpa_config * wpa_config_read(const char *name) int errors = 0, line = 0; struct wpa_ssid *ssid, *tail = NULL, *head = NULL; struct wpa_config *config; - int id = 0, prio; + int id = 0; config = wpa_config_alloc_empty(NULL, NULL); if (config == NULL) @@ -224,12 +255,12 @@ struct wpa_config * wpa_config_read(const char *name) wpa_printf(MSG_DEBUG, "Reading configuration file '%s'", name); f = fopen(name, "r"); if (f == NULL) { - free(config); + os_free(config); return NULL; } - while ((pos = wpa_config_get_line(buf, sizeof(buf), f, &line))) { - if (strcmp(pos, "network={") == 0) { + while (wpa_config_get_line(buf, sizeof(buf), f, &line, &pos)) { + if (os_strcmp(pos, "network={") == 0) { ssid = wpa_config_read_network(f, &line, id++); if (ssid == NULL) { wpa_printf(MSG_ERROR, "Line %d: failed to " @@ -250,11 +281,11 @@ struct wpa_config * wpa_config_read(const char *name) errors++; continue; } - } else if (strncmp(pos, "blob-base64-", 12) == 0) { - char *name = pos + 12, *name_end; + } else if (os_strncmp(pos, "blob-base64-", 12) == 0) { + char *bname = pos + 12, *name_end; struct wpa_config_blob *blob; - name_end = strchr(name, '='); + name_end = os_strchr(bname, '='); if (name_end == NULL) { wpa_printf(MSG_ERROR, "Line %d: no blob name " "terminator", line); @@ -263,51 +294,28 @@ struct wpa_config * wpa_config_read(const char *name) } *name_end = '\0'; - blob = wpa_config_read_blob(f, &line, name); + blob = wpa_config_read_blob(f, &line, bname); if (blob == NULL) { wpa_printf(MSG_ERROR, "Line %d: failed to read" - " blob %s", line, name); + " blob %s", line, bname); errors++; continue; } wpa_config_set_blob(config, blob); #ifdef CONFIG_CTRL_IFACE - } else if (strncmp(pos, "ctrl_interface=", 15) == 0) { - free(config->ctrl_interface); - config->ctrl_interface = strdup(pos + 15); + } else if (os_strncmp(pos, "ctrl_interface=", 15) == 0) { + os_free(config->ctrl_interface); + config->ctrl_interface = os_strdup(pos + 15); wpa_printf(MSG_DEBUG, "ctrl_interface='%s'", config->ctrl_interface); -#ifndef CONFIG_CTRL_IFACE_UDP - } else if (strncmp(pos, "ctrl_interface_group=", 21) == 0) { - struct group *grp; - char *endp; - const char *group = pos + 21; - - grp = getgrnam(group); - if (grp) { - config->ctrl_interface_gid = grp->gr_gid; - config->ctrl_interface_gid_set = 1; - wpa_printf(MSG_DEBUG, "ctrl_interface_group=%d" - " (from group name '%s')", - (int) config->ctrl_interface_gid, - group); - continue; - } - - /* Group name not found - try to parse this as gid */ - config->ctrl_interface_gid = strtol(group, &endp, 10); - if (*group == '\0' || *endp != '\0') { - wpa_printf(MSG_DEBUG, "Line %d: Invalid group " - "'%s'", line, group); - errors++; - continue; - } - config->ctrl_interface_gid_set = 1; - wpa_printf(MSG_DEBUG, "ctrl_interface_group=%d", - (int) config->ctrl_interface_gid); -#endif /* CONFIG_CTRL_IFACE_UDP */ + } else if (os_strncmp(pos, "ctrl_interface_group=", 21) == 0) { + os_free(config->ctrl_interface_group); + config->ctrl_interface_group = os_strdup(pos + 21); + wpa_printf(MSG_DEBUG, "ctrl_interface_group='%s' " + "(DEPRECATED)", + config->ctrl_interface_group); #endif /* CONFIG_CTRL_IFACE */ - } else if (strncmp(pos, "eapol_version=", 14) == 0) { + } else if (os_strncmp(pos, "eapol_version=", 14) == 0) { config->eapol_version = atoi(pos + 14); if (config->eapol_version < 1 || config->eapol_version > 2) { @@ -319,55 +327,69 @@ struct wpa_config * wpa_config_read(const char *name) } wpa_printf(MSG_DEBUG, "eapol_version=%d", config->eapol_version); - } else if (strncmp(pos, "ap_scan=", 8) == 0) { + } else if (os_strncmp(pos, "ap_scan=", 8) == 0) { config->ap_scan = atoi(pos + 8); wpa_printf(MSG_DEBUG, "ap_scan=%d", config->ap_scan); - } else if (strncmp(pos, "fast_reauth=", 12) == 0) { + } else if (os_strncmp(pos, "fast_reauth=", 12) == 0) { config->fast_reauth = atoi(pos + 12); wpa_printf(MSG_DEBUG, "fast_reauth=%d", config->fast_reauth); - } else if (strncmp(pos, "opensc_engine_path=", 19) == 0) { - free(config->opensc_engine_path); - config->opensc_engine_path = strdup(pos + 19); + } else if (os_strncmp(pos, "opensc_engine_path=", 19) == 0) { + os_free(config->opensc_engine_path); + config->opensc_engine_path = os_strdup(pos + 19); wpa_printf(MSG_DEBUG, "opensc_engine_path='%s'", config->opensc_engine_path); - } else if (strncmp(pos, "pkcs11_engine_path=", 19) == 0) { - free(config->pkcs11_engine_path); - config->pkcs11_engine_path = strdup(pos + 19); + } else if (os_strncmp(pos, "pkcs11_engine_path=", 19) == 0) { + os_free(config->pkcs11_engine_path); + config->pkcs11_engine_path = os_strdup(pos + 19); wpa_printf(MSG_DEBUG, "pkcs11_engine_path='%s'", config->pkcs11_engine_path); - } else if (strncmp(pos, "pkcs11_module_path=", 19) == 0) { - free(config->pkcs11_module_path); - config->pkcs11_module_path = strdup(pos + 19); + } else if (os_strncmp(pos, "pkcs11_module_path=", 19) == 0) { + os_free(config->pkcs11_module_path); + config->pkcs11_module_path = os_strdup(pos + 19); wpa_printf(MSG_DEBUG, "pkcs11_module_path='%s'", config->pkcs11_module_path); - } else if (strncmp(pos, "driver_param=", 13) == 0) { - free(config->driver_param); - config->driver_param = strdup(pos + 13); + } else if (os_strncmp(pos, "driver_param=", 13) == 0) { + os_free(config->driver_param); + config->driver_param = os_strdup(pos + 13); wpa_printf(MSG_DEBUG, "driver_param='%s'", config->driver_param); - } else if (strncmp(pos, "dot11RSNAConfigPMKLifetime=", 27) == - 0) { + } else if (os_strncmp(pos, "dot11RSNAConfigPMKLifetime=", 27) + == 0) { config->dot11RSNAConfigPMKLifetime = atoi(pos + 27); wpa_printf(MSG_DEBUG, "dot11RSNAConfigPMKLifetime=%d", config->dot11RSNAConfigPMKLifetime); - } else if (strncmp(pos, "dot11RSNAConfigPMKReauthThreshold=", - 34) == - 0) { + } else if (os_strncmp(pos, + "dot11RSNAConfigPMKReauthThreshold=", 34) + == 0) { config->dot11RSNAConfigPMKReauthThreshold = atoi(pos + 34); wpa_printf(MSG_DEBUG, "dot11RSNAConfigPMKReauthThreshold=%d", config->dot11RSNAConfigPMKReauthThreshold); - } else if (strncmp(pos, "dot11RSNAConfigSATimeout=", 25) == + } else if (os_strncmp(pos, "dot11RSNAConfigSATimeout=", 25) == 0) { config->dot11RSNAConfigSATimeout = atoi(pos + 25); wpa_printf(MSG_DEBUG, "dot11RSNAConfigSATimeout=%d", config->dot11RSNAConfigSATimeout); - } else if (strncmp(pos, "update_config=", 14) == 0) { + } else if (os_strncmp(pos, "update_config=", 14) == 0) { config->update_config = atoi(pos + 14); wpa_printf(MSG_DEBUG, "update_config=%d", config->update_config); + } else if (os_strncmp(pos, "load_dynamic_eap=", 17) == 0) { + char *so = pos + 17; + int ret; + wpa_printf(MSG_DEBUG, "load_dynamic_eap=%s", so); + ret = eap_peer_method_load(so); + if (ret == -2) { + wpa_printf(MSG_DEBUG, "This EAP type was " + "already loaded - not reloading."); + } else if (ret) { + wpa_printf(MSG_ERROR, "Line %d: Failed to " + "load dynamic EAP method '%s'.", + line, so); + errors++; + } } else { wpa_printf(MSG_ERROR, "Line %d: Invalid configuration " "line '%s'.", line, pos); @@ -379,17 +401,8 @@ struct wpa_config * wpa_config_read(const char *name) fclose(f); config->ssid = head; - for (prio = 0; prio < config->num_prio; prio++) { - ssid = config->pssid[prio]; - wpa_printf(MSG_DEBUG, "Priority group %d", - ssid->priority); - while (ssid) { - wpa_printf(MSG_DEBUG, " id=%d ssid='%s'", - ssid->id, - wpa_ssid_txt(ssid->ssid, ssid->ssid_len)); - ssid = ssid->pnext; - } - } + wpa_config_debug_dump_networks(config); + if (errors) { wpa_config_free(config); config = NULL; @@ -406,7 +419,7 @@ static void write_str(FILE *f, const char *field, struct wpa_ssid *ssid) if (value == NULL) return; fprintf(f, "\t%s=%s\n", field, value); - free(value); + os_free(value); } @@ -424,7 +437,7 @@ static void write_bssid(FILE *f, struct wpa_ssid *ssid) if (value == NULL) return; fprintf(f, "\tbssid=%s\n", value); - free(value); + os_free(value); } @@ -434,7 +447,7 @@ static void write_psk(FILE *f, struct wpa_ssid *ssid) if (value == NULL) return; fprintf(f, "\tpsk=%s\n", value); - free(value); + os_free(value); } @@ -450,7 +463,7 @@ static void write_proto(FILE *f, struct wpa_ssid *ssid) return; if (value[0]) fprintf(f, "\tproto=%s\n", value); - free(value); + os_free(value); } @@ -466,7 +479,7 @@ static void write_key_mgmt(FILE *f, struct wpa_ssid *ssid) return; if (value[0]) fprintf(f, "\tkey_mgmt=%s\n", value); - free(value); + os_free(value); } @@ -482,7 +495,7 @@ static void write_pairwise(FILE *f, struct wpa_ssid *ssid) return; if (value[0]) fprintf(f, "\tpairwise=%s\n", value); - free(value); + os_free(value); } @@ -498,7 +511,7 @@ static void write_group(FILE *f, struct wpa_ssid *ssid) return; if (value[0]) fprintf(f, "\tgroup=%s\n", value); - free(value); + os_free(value); } @@ -514,10 +527,11 @@ static void write_auth_alg(FILE *f, struct wpa_ssid *ssid) return; if (value[0]) fprintf(f, "\tauth_alg=%s\n", value); - free(value); + os_free(value); } +#ifdef IEEE8021X_EAPOL static void write_eap(FILE *f, struct wpa_ssid *ssid) { char *value; @@ -528,19 +542,20 @@ static void write_eap(FILE *f, struct wpa_ssid *ssid) if (value[0]) fprintf(f, "\teap=%s\n", value); - free(value); + os_free(value); } +#endif /* IEEE8021X_EAPOL */ static void write_wep_key(FILE *f, int idx, struct wpa_ssid *ssid) { char field[20], *value; - snprintf(field, sizeof(field), "wep_key%d", idx); + os_snprintf(field, sizeof(field), "wep_key%d", idx); value = wpa_config_get(ssid, field); if (value) { fprintf(f, "\t%s=%s\n", field, value); - free(value); + os_free(value); } } @@ -562,6 +577,7 @@ static void wpa_config_write_network(FILE *f, struct wpa_ssid *ssid) write_pairwise(f, ssid); write_group(f, ssid); write_auth_alg(f, ssid); +#ifdef IEEE8021X_EAPOL write_eap(f, ssid); STR(identity); STR(anonymous_identity); @@ -569,6 +585,7 @@ static void wpa_config_write_network(FILE *f, struct wpa_ssid *ssid) STR(nai); STR(password); STR(ca_cert); + STR(ca_path); STR(client_cert); STR(private_key); STR(private_key_passwd); @@ -576,6 +593,7 @@ static void wpa_config_write_network(FILE *f, struct wpa_ssid *ssid) STR(subject_match); STR(altsubject_match); STR(ca_cert2); + STR(ca_path2); STR(client_cert2); STR(private_key2); STR(private_key2_passwd); @@ -590,15 +608,24 @@ static void wpa_config_write_network(FILE *f, struct wpa_ssid *ssid) STR(key_id); INT(engine); INT_DEF(eapol_flags, DEFAULT_EAPOL_FLAGS); +#endif /* IEEE8021X_EAPOL */ for (i = 0; i < 4; i++) write_wep_key(f, i, ssid); INT(wep_tx_keyidx); INT(priority); +#ifdef IEEE8021X_EAPOL INT_DEF(eap_workaround, DEFAULT_EAP_WORKAROUND); STR(pac_file); + INT_DEF(fragment_size, DEFAULT_FRAGMENT_SIZE); +#endif /* IEEE8021X_EAPOL */ INT(mode); INT(proactive_key_caching); INT(disabled); + INT(peerkey); +#ifdef CONFIG_IEEE80211W + INT(ieee80211w); +#endif /* CONFIG_IEEE80211W */ + STR(id_str); #undef STR #undef INT @@ -615,36 +642,19 @@ static int wpa_config_write_blob(FILE *f, struct wpa_config_blob *blob) return -1; fprintf(f, "\nblob-base64-%s={\n%s}\n", blob->name, encoded); - free(encoded); + os_free(encoded); return 0; } -int wpa_config_write(const char *name, struct wpa_config *config) +static void wpa_config_write_global(FILE *f, struct wpa_config *config) { - FILE *f; - struct wpa_ssid *ssid; - struct wpa_config_blob *blob; - int ret = 0; - - wpa_printf(MSG_DEBUG, "Writing configuration file '%s'", name); - - - f = fopen(name, "w"); - if (f == NULL) { - wpa_printf(MSG_DEBUG, "Failed to open '%s' for writing", name); - return -1; - } - #ifdef CONFIG_CTRL_IFACE if (config->ctrl_interface) fprintf(f, "ctrl_interface=%s\n", config->ctrl_interface); -#ifndef CONFIG_CTRL_IFACE_UDP - if (config->ctrl_interface_gid_set) { - fprintf(f, "ctrl_interface_group=%d\n", - (int) config->ctrl_interface_gid); - } -#endif /* CONFIG_CTRL_IFACE_UDP */ + if (config->ctrl_interface_group) + fprintf(f, "ctrl_interface_group=%s\n", + config->ctrl_interface_group); #endif /* CONFIG_CTRL_IFACE */ if (config->eapol_version != DEFAULT_EAPOL_VERSION) fprintf(f, "eapol_version=%d\n", config->eapol_version); @@ -674,6 +684,25 @@ int wpa_config_write(const char *name, struct wpa_config *config) config->dot11RSNAConfigSATimeout); if (config->update_config) fprintf(f, "update_config=%d\n", config->update_config); +} + + +int wpa_config_write(const char *name, struct wpa_config *config) +{ + FILE *f; + struct wpa_ssid *ssid; + struct wpa_config_blob *blob; + int ret = 0; + + wpa_printf(MSG_DEBUG, "Writing configuration file '%s'", name); + + f = fopen(name, "w"); + if (f == NULL) { + wpa_printf(MSG_DEBUG, "Failed to open '%s' for writing", name); + return -1; + } + + wpa_config_write_global(f, config); for (ssid = config->ssid; ssid; ssid = ssid->next) { fprintf(f, "\nnetwork={\n"); diff --git a/contrib/wpa_supplicant/config_none.c b/contrib/wpa_supplicant/config_none.c new file mode 100644 index 000000000000..2e9ccc0a2835 --- /dev/null +++ b/contrib/wpa_supplicant/config_none.c @@ -0,0 +1,57 @@ +/* + * WPA Supplicant / Configuration backend: empty starting point + * Copyright (c) 2003-2005, Jouni Malinen <j@w1.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. + * + * This file implements dummy example of a configuration backend. None of the + * functions are actually implemented so this can be used as a simple + * compilation test or a starting point for a new configuration backend. + */ + +#include "includes.h" + +#include "common.h" +#include "config.h" +#include "base64.h" + + +struct wpa_config * wpa_config_read(const char *name) +{ + struct wpa_config *config; + + config = wpa_config_alloc_empty(NULL, NULL); + if (config == NULL) + return NULL; + /* TODO: fill in configuration data */ + return config; +} + + +int wpa_config_write(const char *name, struct wpa_config *config) +{ + struct wpa_ssid *ssid; + struct wpa_config_blob *blob; + + wpa_printf(MSG_DEBUG, "Writing configuration file '%s'", name); + + /* TODO: write global config parameters */ + + + for (ssid = config->ssid; ssid; ssid = ssid->next) { + /* TODO: write networks */ + } + + for (blob = config->blobs; blob; blob = blob->next) { + /* TODO: write blobs */ + } + + return 0; +} diff --git a/contrib/wpa_supplicant/config_ssid.h b/contrib/wpa_supplicant/config_ssid.h index 14dc0f47dadc..d4c36541194d 100644 --- a/contrib/wpa_supplicant/config_ssid.h +++ b/contrib/wpa_supplicant/config_ssid.h @@ -1,6 +1,6 @@ /* * WPA Supplicant / Network configuration structures - * Copyright (c) 2003-2005, Jouni Malinen <jkmaline@cc.hut.fi> + * Copyright (c) 2003-2006, Jouni Malinen <j@w1.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 @@ -15,11 +15,18 @@ #ifndef CONFIG_SSID_H #define CONFIG_SSID_H +#ifndef BIT +#define BIT(n) (1 << (n)) +#endif + #define WPA_CIPHER_NONE BIT(0) #define WPA_CIPHER_WEP40 BIT(1) #define WPA_CIPHER_WEP104 BIT(2) #define WPA_CIPHER_TKIP BIT(3) #define WPA_CIPHER_CCMP BIT(4) +#ifdef CONFIG_IEEE80211W +#define WPA_CIPHER_AES_128_CMAC BIT(5) +#endif /* CONFIG_IEEE80211W */ #define WPA_KEY_MGMT_IEEE8021X BIT(0) #define WPA_KEY_MGMT_PSK BIT(1) @@ -36,7 +43,8 @@ #define MAX_SSID_LEN 32 #define PMK_LEN 32 -#define EAP_PSK_LEN 16 +#define EAP_PSK_LEN_MIN 16 +#define EAP_PSK_LEN_MAX 32 #define DEFAULT_EAP_WORKAROUND ((unsigned int) -1) @@ -47,6 +55,7 @@ #define DEFAULT_PAIRWISE (WPA_CIPHER_CCMP | WPA_CIPHER_TKIP) #define DEFAULT_GROUP (WPA_CIPHER_CCMP | WPA_CIPHER_TKIP | \ WPA_CIPHER_WEP104 | WPA_CIPHER_WEP40) +#define DEFAULT_FRAGMENT_SIZE 1398 /** * struct wpa_ssid - Network configuration data @@ -191,6 +200,8 @@ struct wpa_ssid { */ int scan_ssid; +#ifdef IEEE8021X_EAPOL + /** * identity - EAP Identity */ @@ -216,19 +227,20 @@ struct wpa_ssid { size_t anonymous_identity_len; /** - * eappsk - EAP-PSK pre-shared key + * eappsk - EAP-PSK/PAX/SAKE pre-shared key */ u8 *eappsk; /** - * eappsk_len - EAP-PSK pre-shared key length + * eappsk_len - EAP-PSK/PAX/SAKE pre-shared key length * - * This field is always 16 for the current version of EAP-PSK. + * This field is always 16 for the current version of EAP-PSK/PAX and + * 32 for EAP-SAKE. */ size_t eappsk_len; /** - * nai - User NAI (for EAP-PSK) + * nai - User NAI (for EAP-PSK/PAX/SAKE) */ u8 *nai; @@ -263,6 +275,9 @@ struct wpa_ssid { * On Windows, trusted CA certificates can be loaded from the system * certificate store by setting this to cert_store://<name>, e.g., * ca_cert="cert_store://CA" or ca_cert="cert_store://ROOT". + * Note that when running wpa_supplicant as an application, the user + * certificate store (My user account) is used, whereas computer store + * (Computer account) is used when running wpasvc as a service. */ u8 *ca_cert; @@ -309,6 +324,10 @@ struct wpa_ssid { * * For example: private_key="hash://63093aa9c47f56ae88334c7b65a4" * + * Note that when running wpa_supplicant as an application, the user + * certificate store (My user account) is used, whereas computer store + * (Computer account) is used when running wpasvc as a service. + * * Alternatively, a named configuration blob can be used by setting * this to blob://<blob name>. */ @@ -354,14 +373,16 @@ struct wpa_ssid { /** * altsubject_match - Constraint for server certificate alt. subject * - * This substring is matched against the alternative subject name of - * the authentication server certificate. If this string is set, the - * server sertificate is only accepted if it contains this string in an - * alternative subject name extension. + * Semicolon separated string of entries to be matched against the + * alternative subject name of the authentication server certificate. + * If this string is set, the server sertificate is only accepted if it + * contains one of the entries in an alternative subject name + * extension. * * altSubjectName string is in following format: TYPE:VALUE * - * Example: DNS:server.example.com + * Example: EMAIL:server@example.com + * Example: DNS:server.example.com;DNS:server2.example.com * * Following types are supported: EMAIL, DNS, URI */ @@ -465,10 +486,10 @@ struct wpa_ssid { /** * eap_methods - Allowed EAP methods * - * Zero (EAP_TYPE_NONE) terminated list of allowed EAP methods or %NULL - * if all methods are accepted. + * (vendor=EAP_VENDOR_IETF,method=EAP_TYPE_NONE) terminated list of + * allowed EAP methods or %NULL if all methods are accepted. */ - u8 *eap_methods; + struct eap_method_type *eap_methods; /** * phase1 - Phase 1 (outer authentication) parameters @@ -569,6 +590,8 @@ struct wpa_ssid { */ int eapol_flags; +#endif /* IEEE8021X_EAPOL */ + #define NUM_WEP_KEYS 4 #define MAX_WEP_KEY_LEN 16 /** @@ -602,6 +625,18 @@ struct wpa_ssid { int proactive_key_caching; /** + * mixed_cell - Whether mixed cells are allowed + * + * This option can be used to configure whether so called mixed cells, + * i.e., networks that use both plaintext and encryption in the same + * SSID, are allowed. This is disabled (0) by default. Enable by + * setting this to 1. + */ + int mixed_cell; + +#ifdef IEEE8021X_EAPOL + + /** * otp - One-time-password * * This field should not be set in configuration step. It is only used @@ -715,6 +750,8 @@ struct wpa_ssid { */ char *pac_file; +#endif /* IEEE8021X_EAPOL */ + /** * mode - IEEE 802.11 operation mode (Infrastucture/IBSS) * @@ -731,6 +768,8 @@ struct wpa_ssid { */ int mode; +#ifdef IEEE8021X_EAPOL + /** * mschapv2_retry - MSCHAPv2 retry in progress * @@ -753,6 +792,8 @@ struct wpa_ssid { */ size_t new_password_len; +#endif /* IEEE8021X_EAPOL */ + /** * disabled - Whether this network is currently disabled * @@ -761,8 +802,58 @@ struct wpa_ssid { * ctrl_iface, e.g., with wpa_cli or wpa_gui). */ int disabled; + + /** + * peerkey - Whether PeerKey handshake for direct links is allowed + * + * This is only used when both RSN/WPA2 and IEEE 802.11e (QoS) are + * enabled. + * + * 0 = disabled (default) + * 1 = enabled + */ + int peerkey; + +#ifdef IEEE8021X_EAPOL + + /** + * fragment_size - Maximum EAP fragment size in bytes (default 1398) + * + * This value limits the fragment size for EAP methods that support + * fragmentation (e.g., EAP-TLS and EAP-PEAP). This value should be set + * small enough to make the EAP messages fit in MTU of the network + * interface used for EAPOL. The default value is suitable for most + * cases. + */ + int fragment_size; + +#endif /* IEEE8021X_EAPOL */ + + /** + * id_str - Network identifier string for external scripts + * + * This value is passed to external ctrl_iface monitors in + * WPA_EVENT_CONNECTED event and wpa_cli sets this as WPA_ID_STR + * environment variable for action scripts. + */ + char *id_str; + +#ifdef CONFIG_IEEE80211W + /** + * ieee80211w - Whether management frame protection is enabled + * + * This value is used to configure policy for management frame + * protection (IEEE 802.11w). 0 = disabled, 1 = optional, 2 = required. + */ + enum { + NO_IEEE80211W = 0, + IEEE80211W_OPTIONAL = 1, + IEEE80211W_REQUIRED = 2 + } ieee80211w; +#endif /* CONFIG_IEEE80211W */ }; -int wpa_config_allowed_eap_method(struct wpa_ssid *ssid, int method); +int wpa_config_allowed_eap_method(struct wpa_ssid *ssid, int vendor, + u32 method); #endif /* CONFIG_SSID_H */ diff --git a/contrib/wpa_supplicant/config_types.h b/contrib/wpa_supplicant/config_types.h index 12b57cb4acf1..ffcffa3c0cd4 100644 --- a/contrib/wpa_supplicant/config_types.h +++ b/contrib/wpa_supplicant/config_types.h @@ -1,3 +1,17 @@ +/* + * hostapd / Shared configuration file defines + * Copyright (c) 2003-2005, Jouni Malinen <j@w1.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. + */ + #ifndef CONFIG_TYPES_H #define CONFIG_TYPES_H diff --git a/contrib/wpa_supplicant/config_winreg.c b/contrib/wpa_supplicant/config_winreg.c new file mode 100644 index 000000000000..8a3ba53734f9 --- /dev/null +++ b/contrib/wpa_supplicant/config_winreg.c @@ -0,0 +1,882 @@ +/* + * WPA Supplicant / Configuration backend: Windows registry + * Copyright (c) 2003-2006, Jouni Malinen <j@w1.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. + * + * This file implements a configuration backend for Windows registry.. All the + * configuration information is stored in the registry and the format for + * network configuration fields is same as described in the sample + * configuration file, wpa_supplicant.conf. + * + * Configuration data is in HKEY_LOCAL_MACHINE\SOFTWARE\wpa_supplicant\configs + * key. Each configuration profile has its own key under this. In terms of text + * files, each profile would map to a separate text file with possibly multiple + * networks. Under each profile, there is a networks key that lists all + * networks as a subkey. Each network has set of values in the same way as + * network block in the configuration file. In addition, blobs subkey has + * possible blobs as values. + * + * HKEY_LOCAL_MACHINE\SOFTWARE\wpa_supplicant\configs\test\networks\0000 + * ssid="example" + * key_mgmt=WPA-PSK + */ + +#include "includes.h" + +#include "common.h" +#include "config.h" + +#ifndef WPA_KEY_ROOT +#define WPA_KEY_ROOT HKEY_LOCAL_MACHINE +#endif +#ifndef WPA_KEY_PREFIX +#define WPA_KEY_PREFIX TEXT("SOFTWARE\\wpa_supplicant") +#endif + +#ifdef UNICODE +#define TSTR "%S" +#else /* UNICODE */ +#define TSTR "%s" +#endif /* UNICODE */ + + +static int wpa_config_read_blobs(struct wpa_config *config, HKEY hk) +{ + struct wpa_config_blob *blob; + int errors = 0; + HKEY bhk; + LONG ret; + DWORD i; + + ret = RegOpenKeyEx(hk, TEXT("blobs"), 0, KEY_QUERY_VALUE, &bhk); + if (ret != ERROR_SUCCESS) { + wpa_printf(MSG_DEBUG, "Could not open wpa_supplicant config " + "blobs key"); + return 0; /* assume no blobs */ + } + + for (i = 0; ; i++) { +#define TNAMELEN 255 + TCHAR name[TNAMELEN]; + char data[4096]; + DWORD namelen, datalen, type; + + namelen = TNAMELEN; + datalen = sizeof(data); + ret = RegEnumValue(bhk, i, name, &namelen, NULL, &type, + (LPBYTE) data, &datalen); + + if (ret == ERROR_NO_MORE_ITEMS) + break; + + if (ret != ERROR_SUCCESS) { + wpa_printf(MSG_DEBUG, "RegEnumValue failed: 0x%x", + (unsigned int) ret); + break; + } + + if (namelen >= TNAMELEN) + namelen = TNAMELEN - 1; + name[namelen] = TEXT('\0'); + wpa_unicode2ascii_inplace(name); + + if (datalen >= sizeof(data)) + datalen = sizeof(data) - 1; + + wpa_printf(MSG_MSGDUMP, "blob %d: field='%s' len %d", + (int) i, name, (int) datalen); + + blob = os_zalloc(sizeof(*blob)); + if (blob == NULL) { + errors++; + break; + } + blob->name = os_strdup((char *) name); + blob->data = os_malloc(datalen); + if (blob->name == NULL || blob->data == NULL) { + wpa_config_free_blob(blob); + errors++; + break; + } + os_memcpy(blob->data, data, datalen); + blob->len = datalen; + + wpa_config_set_blob(config, blob); + } + + RegCloseKey(bhk); + + return errors ? -1 : 0; +} + + +static int wpa_config_read_reg_dword(HKEY hk, const TCHAR *name, int *_val) +{ + DWORD val, buflen; + LONG ret; + + buflen = sizeof(val); + ret = RegQueryValueEx(hk, name, NULL, NULL, (LPBYTE) &val, &buflen); + if (ret == ERROR_SUCCESS && buflen == sizeof(val)) { + wpa_printf(MSG_DEBUG, TSTR "=%d", name, (int) val); + *_val = val; + return 0; + } + + return -1; +} + + +static char * wpa_config_read_reg_string(HKEY hk, const TCHAR *name) +{ + DWORD buflen; + LONG ret; + TCHAR *val; + + buflen = 0; + ret = RegQueryValueEx(hk, name, NULL, NULL, NULL, &buflen); + if (ret != ERROR_SUCCESS) + return NULL; + val = os_malloc(buflen); + if (val == NULL) + return NULL; + + ret = RegQueryValueEx(hk, name, NULL, NULL, (LPBYTE) val, &buflen); + if (ret != ERROR_SUCCESS) { + os_free(val); + return NULL; + } + + wpa_unicode2ascii_inplace(val); + wpa_printf(MSG_DEBUG, TSTR "=%s", name, (char *) val); + return (char *) val; +} + + +static int wpa_config_read_global(struct wpa_config *config, HKEY hk) +{ + int errors = 0; + + wpa_config_read_reg_dword(hk, TEXT("ap_scan"), &config->ap_scan); + wpa_config_read_reg_dword(hk, TEXT("fast_reauth"), + &config->fast_reauth); + wpa_config_read_reg_dword(hk, TEXT("dot11RSNAConfigPMKLifetime"), + &config->dot11RSNAConfigPMKLifetime); + wpa_config_read_reg_dword(hk, + TEXT("dot11RSNAConfigPMKReauthThreshold"), + &config->dot11RSNAConfigPMKReauthThreshold); + wpa_config_read_reg_dword(hk, TEXT("dot11RSNAConfigSATimeout"), + &config->dot11RSNAConfigSATimeout); + wpa_config_read_reg_dword(hk, TEXT("update_config"), + &config->update_config); + + if (wpa_config_read_reg_dword(hk, TEXT("eapol_version"), + &config->eapol_version) == 0) { + if (config->eapol_version < 1 || + config->eapol_version > 2) { + wpa_printf(MSG_ERROR, "Invalid EAPOL version (%d)", + config->eapol_version); + errors++; + } + } + + config->ctrl_interface = wpa_config_read_reg_string( + hk, TEXT("ctrl_interface")); + + return errors ? -1 : 0; +} + + +static struct wpa_ssid * wpa_config_read_network(HKEY hk, const TCHAR *netw, + int id) +{ + HKEY nhk; + LONG ret; + DWORD i; + struct wpa_ssid *ssid; + int errors = 0; + + ret = RegOpenKeyEx(hk, netw, 0, KEY_QUERY_VALUE, &nhk); + if (ret != ERROR_SUCCESS) { + wpa_printf(MSG_DEBUG, "Could not open wpa_supplicant config " + "network '" TSTR "'", netw); + return NULL; + } + + wpa_printf(MSG_MSGDUMP, "Start of a new network '" TSTR "'", netw); + ssid = os_zalloc(sizeof(*ssid)); + if (ssid == NULL) { + RegCloseKey(nhk); + return NULL; + } + ssid->id = id; + + wpa_config_set_network_defaults(ssid); + + for (i = 0; ; i++) { + TCHAR name[255], data[1024]; + DWORD namelen, datalen, type; + + namelen = 255; + datalen = sizeof(data); + ret = RegEnumValue(nhk, i, name, &namelen, NULL, &type, + (LPBYTE) data, &datalen); + + if (ret == ERROR_NO_MORE_ITEMS) + break; + + if (ret != ERROR_SUCCESS) { + wpa_printf(MSG_ERROR, "RegEnumValue failed: 0x%x", + (unsigned int) ret); + break; + } + + if (namelen >= 255) + namelen = 255 - 1; + name[namelen] = TEXT('\0'); + + if (datalen >= 1024) + datalen = 1024 - 1; + data[datalen] = TEXT('\0'); + + wpa_unicode2ascii_inplace(name); + wpa_unicode2ascii_inplace(data); + if (wpa_config_set(ssid, (char *) name, (char *) data, 0) < 0) + errors++; + } + + RegCloseKey(nhk); + + if (ssid->passphrase) { + if (ssid->psk_set) { + wpa_printf(MSG_ERROR, "Both PSK and passphrase " + "configured for network '" TSTR "'.", netw); + errors++; + } + wpa_config_update_psk(ssid); + } + + if ((ssid->key_mgmt & WPA_KEY_MGMT_PSK) && !ssid->psk_set) { + wpa_printf(MSG_ERROR, "WPA-PSK accepted for key management, " + "but no PSK configured for network '" TSTR "'.", + netw); + errors++; + } + + if ((ssid->group_cipher & WPA_CIPHER_CCMP) && + !(ssid->pairwise_cipher & WPA_CIPHER_CCMP) && + !(ssid->pairwise_cipher & WPA_CIPHER_NONE)) { + /* Group cipher cannot be stronger than the pairwise cipher. */ + wpa_printf(MSG_DEBUG, "Removed CCMP from group cipher " + "list since it was not allowed for pairwise " + "cipher for network '" TSTR "'.", netw); + ssid->group_cipher &= ~WPA_CIPHER_CCMP; + } + + if (errors) { + wpa_config_free_ssid(ssid); + ssid = NULL; + } + + return ssid; +} + + +static int wpa_config_read_networks(struct wpa_config *config, HKEY hk) +{ + HKEY nhk; + struct wpa_ssid *ssid, *tail = NULL, *head = NULL; + int errors = 0; + LONG ret; + DWORD i; + + ret = RegOpenKeyEx(hk, TEXT("networks"), 0, KEY_ENUMERATE_SUB_KEYS, + &nhk); + if (ret != ERROR_SUCCESS) { + wpa_printf(MSG_ERROR, "Could not open wpa_supplicant networks " + "registry key"); + return -1; + } + + for (i = 0; ; i++) { + TCHAR name[255]; + DWORD namelen; + + namelen = 255; + ret = RegEnumKeyEx(nhk, i, name, &namelen, NULL, NULL, NULL, + NULL); + + if (ret == ERROR_NO_MORE_ITEMS) + break; + + if (ret != ERROR_SUCCESS) { + wpa_printf(MSG_DEBUG, "RegEnumKeyEx failed: 0x%x", + (unsigned int) ret); + break; + } + + if (namelen >= 255) + namelen = 255 - 1; + name[namelen] = '\0'; + + ssid = wpa_config_read_network(nhk, name, i); + if (ssid == NULL) { + wpa_printf(MSG_ERROR, "Failed to parse network " + "profile '%s'.", name); + errors++; + continue; + } + if (head == NULL) { + head = tail = ssid; + } else { + tail->next = ssid; + tail = ssid; + } + if (wpa_config_add_prio_network(config, ssid)) { + wpa_printf(MSG_ERROR, "Failed to add network profile " + "'%s' to priority list.", name); + errors++; + continue; + } + } + + RegCloseKey(nhk); + + config->ssid = head; + + return errors ? -1 : 0; +} + + +struct wpa_config * wpa_config_read(const char *name) +{ + TCHAR buf[256]; + int errors = 0; + struct wpa_config *config; + HKEY hk; + LONG ret; + + config = wpa_config_alloc_empty(NULL, NULL); + if (config == NULL) + return NULL; + wpa_printf(MSG_DEBUG, "Reading configuration profile '%s'", name); + +#ifdef UNICODE + _snwprintf(buf, 256, WPA_KEY_PREFIX TEXT("\\configs\\%S"), name); +#else /* UNICODE */ + os_snprintf(buf, 256, WPA_KEY_PREFIX TEXT("\\configs\\%s"), name); +#endif /* UNICODE */ + + ret = RegOpenKeyEx(WPA_KEY_ROOT, buf, 0, KEY_QUERY_VALUE, &hk); + if (ret != ERROR_SUCCESS) { + wpa_printf(MSG_ERROR, "Could not open wpa_supplicant " + "configuration registry HKLM\\" TSTR, buf); + os_free(config); + return NULL; + } + + if (wpa_config_read_global(config, hk)) + errors++; + + if (wpa_config_read_networks(config, hk)) + errors++; + + if (wpa_config_read_blobs(config, hk)) + errors++; + + wpa_config_debug_dump_networks(config); + + RegCloseKey(hk); + + if (errors) { + wpa_config_free(config); + config = NULL; + } + + return config; +} + + +static int wpa_config_write_reg_dword(HKEY hk, const TCHAR *name, int val, + int def) +{ + LONG ret; + DWORD _val = val; + + if (val == def) { + RegDeleteValue(hk, name); + return 0; + } + + ret = RegSetValueEx(hk, name, 0, REG_DWORD, (LPBYTE) &_val, + sizeof(_val)); + if (ret != ERROR_SUCCESS) { + wpa_printf(MSG_ERROR, "WINREG: Failed to set %s=%d: error %d", + name, val, (int) GetLastError()); + return -1; + } + + return 0; +} + + +static int wpa_config_write_reg_string(HKEY hk, const char *name, + const char *val) +{ + LONG ret; + TCHAR *_name, *_val; + + _name = wpa_strdup_tchar(name); + if (_name == NULL) + return -1; + + if (val == NULL) { + RegDeleteValue(hk, _name); + os_free(_name); + return 0; + } + + _val = wpa_strdup_tchar(val); + if (_val == NULL) { + os_free(_name); + return -1; + } + ret = RegSetValueEx(hk, _name, 0, REG_SZ, (BYTE *) _val, + (os_strlen(val) + 1) * sizeof(TCHAR)); + if (ret != ERROR_SUCCESS) { + wpa_printf(MSG_ERROR, "WINREG: Failed to set %s='%s': " + "error %d", name, val, (int) GetLastError()); + os_free(_name); + os_free(_val); + return -1; + } + + os_free(_name); + os_free(_val); + return 0; +} + + +static int wpa_config_write_global(struct wpa_config *config, HKEY hk) +{ +#ifdef CONFIG_CTRL_IFACE + wpa_config_write_reg_string(hk, "ctrl_interface", + config->ctrl_interface); +#endif /* CONFIG_CTRL_IFACE */ + + wpa_config_write_reg_dword(hk, TEXT("eapol_version"), + config->eapol_version, + DEFAULT_EAPOL_VERSION); + wpa_config_write_reg_dword(hk, TEXT("ap_scan"), config->ap_scan, + DEFAULT_AP_SCAN); + wpa_config_write_reg_dword(hk, TEXT("fast_reauth"), + config->fast_reauth, DEFAULT_FAST_REAUTH); + wpa_config_write_reg_dword(hk, TEXT("dot11RSNAConfigPMKLifetime"), + config->dot11RSNAConfigPMKLifetime, 0); + wpa_config_write_reg_dword(hk, + TEXT("dot11RSNAConfigPMKReauthThreshold"), + config->dot11RSNAConfigPMKReauthThreshold, + 0); + wpa_config_write_reg_dword(hk, TEXT("dot11RSNAConfigSATimeout"), + config->dot11RSNAConfigSATimeout, 0); + wpa_config_write_reg_dword(hk, TEXT("update_config"), + config->update_config, + 0); + + return 0; +} + + +static int wpa_config_delete_subkeys(HKEY hk, const TCHAR *key) +{ + HKEY nhk; + int i, errors = 0; + LONG ret; + + ret = RegOpenKeyEx(hk, key, 0, KEY_ENUMERATE_SUB_KEYS | DELETE, &nhk); + if (ret != ERROR_SUCCESS) { + wpa_printf(MSG_DEBUG, "WINREG: Could not open key '" TSTR + "' for subkey deletion: error 0x%x (%d)", key, + (unsigned int) ret, (int) GetLastError()); + return 0; + } + + for (i = 0; ; i++) { + TCHAR name[255]; + DWORD namelen; + + namelen = 255; + ret = RegEnumKeyEx(nhk, i, name, &namelen, NULL, NULL, NULL, + NULL); + + if (ret == ERROR_NO_MORE_ITEMS) + break; + + if (ret != ERROR_SUCCESS) { + wpa_printf(MSG_DEBUG, "RegEnumKeyEx failed: 0x%x (%d)", + (unsigned int) ret, (int) GetLastError()); + break; + } + + if (namelen >= 255) + namelen = 255 - 1; + name[namelen] = TEXT('\0'); + + ret = RegDeleteKey(nhk, name); + if (ret != ERROR_SUCCESS) { + wpa_printf(MSG_DEBUG, "RegDeleteKey failed: 0x%x (%d)", + (unsigned int) ret, (int) GetLastError()); + errors++; + } + } + + RegCloseKey(nhk); + + return errors ? -1 : 0; +} + + +static void write_str(HKEY hk, const char *field, struct wpa_ssid *ssid) +{ + char *value = wpa_config_get(ssid, field); + if (value == NULL) + return; + wpa_config_write_reg_string(hk, field, value); + os_free(value); +} + + +static void write_int(HKEY hk, const char *field, int value, int def) +{ + char val[20]; + if (value == def) + return; + os_snprintf(val, sizeof(val), "%d", value); + wpa_config_write_reg_string(hk, field, val); +} + + +static void write_bssid(HKEY hk, struct wpa_ssid *ssid) +{ + char *value = wpa_config_get(ssid, "bssid"); + if (value == NULL) + return; + wpa_config_write_reg_string(hk, "bssid", value); + os_free(value); +} + + +static void write_psk(HKEY hk, struct wpa_ssid *ssid) +{ + char *value = wpa_config_get(ssid, "psk"); + if (value == NULL) + return; + wpa_config_write_reg_string(hk, "psk", value); + os_free(value); +} + + +static void write_proto(HKEY hk, struct wpa_ssid *ssid) +{ + char *value; + + if (ssid->proto == DEFAULT_PROTO) + return; + + value = wpa_config_get(ssid, "proto"); + if (value == NULL) + return; + if (value[0]) + wpa_config_write_reg_string(hk, "proto", value); + os_free(value); +} + + +static void write_key_mgmt(HKEY hk, struct wpa_ssid *ssid) +{ + char *value; + + if (ssid->key_mgmt == DEFAULT_KEY_MGMT) + return; + + value = wpa_config_get(ssid, "key_mgmt"); + if (value == NULL) + return; + if (value[0]) + wpa_config_write_reg_string(hk, "key_mgmt", value); + os_free(value); +} + + +static void write_pairwise(HKEY hk, struct wpa_ssid *ssid) +{ + char *value; + + if (ssid->pairwise_cipher == DEFAULT_PAIRWISE) + return; + + value = wpa_config_get(ssid, "pairwise"); + if (value == NULL) + return; + if (value[0]) + wpa_config_write_reg_string(hk, "pairwise", value); + os_free(value); +} + + +static void write_group(HKEY hk, struct wpa_ssid *ssid) +{ + char *value; + + if (ssid->group_cipher == DEFAULT_GROUP) + return; + + value = wpa_config_get(ssid, "group"); + if (value == NULL) + return; + if (value[0]) + wpa_config_write_reg_string(hk, "group", value); + os_free(value); +} + + +static void write_auth_alg(HKEY hk, struct wpa_ssid *ssid) +{ + char *value; + + if (ssid->auth_alg == 0) + return; + + value = wpa_config_get(ssid, "auth_alg"); + if (value == NULL) + return; + if (value[0]) + wpa_config_write_reg_string(hk, "auth_alg", value); + os_free(value); +} + + +#ifdef IEEE8021X_EAPOL +static void write_eap(HKEY hk, struct wpa_ssid *ssid) +{ + char *value; + + value = wpa_config_get(ssid, "eap"); + if (value == NULL) + return; + + if (value[0]) + wpa_config_write_reg_string(hk, "eap", value); + os_free(value); +} +#endif /* IEEE8021X_EAPOL */ + + +static void write_wep_key(HKEY hk, int idx, struct wpa_ssid *ssid) +{ + char field[20], *value; + + os_snprintf(field, sizeof(field), "wep_key%d", idx); + value = wpa_config_get(ssid, field); + if (value) { + wpa_config_write_reg_string(hk, field, value); + os_free(value); + } +} + + +static int wpa_config_write_network(HKEY hk, struct wpa_ssid *ssid, int id) +{ + int i, errors = 0; + HKEY nhk, netw; + LONG ret; + TCHAR name[5]; + + ret = RegOpenKeyEx(hk, TEXT("networks"), 0, KEY_CREATE_SUB_KEY, &nhk); + if (ret != ERROR_SUCCESS) { + wpa_printf(MSG_DEBUG, "WINREG: Could not open networks key " + "for subkey addition: error 0x%x (%d)", + (unsigned int) ret, (int) GetLastError()); + return 0; + } + +#ifdef UNICODE + wsprintf(name, L"%04d", id); +#else /* UNICODE */ + os_snprintf(name, sizeof(name), "%04d", id); +#endif /* UNICODE */ + ret = RegCreateKeyEx(nhk, name, 0, NULL, 0, KEY_WRITE, NULL, &netw, + NULL); + RegCloseKey(nhk); + if (ret != ERROR_SUCCESS) { + wpa_printf(MSG_DEBUG, "WINREG: Could not add network key '%s':" + " error 0x%x (%d)", + name, (unsigned int) ret, (int) GetLastError()); + return -1; + } + +#define STR(t) write_str(netw, #t, ssid) +#define INT(t) write_int(netw, #t, ssid->t, 0) +#define INT_DEF(t, def) write_int(netw, #t, ssid->t, def) + + STR(ssid); + INT(scan_ssid); + write_bssid(netw, ssid); + write_psk(netw, ssid); + write_proto(netw, ssid); + write_key_mgmt(netw, ssid); + write_pairwise(netw, ssid); + write_group(netw, ssid); + write_auth_alg(netw, ssid); +#ifdef IEEE8021X_EAPOL + write_eap(netw, ssid); + STR(identity); + STR(anonymous_identity); + STR(eappsk); + STR(nai); + STR(password); + STR(ca_cert); + STR(ca_path); + STR(client_cert); + STR(private_key); + STR(private_key_passwd); + STR(dh_file); + STR(subject_match); + STR(altsubject_match); + STR(ca_cert2); + STR(ca_path2); + STR(client_cert2); + STR(private_key2); + STR(private_key2_passwd); + STR(dh_file2); + STR(subject_match2); + STR(altsubject_match2); + STR(phase1); + STR(phase2); + STR(pcsc); + STR(pin); + STR(engine_id); + STR(key_id); + INT(engine); + INT_DEF(eapol_flags, DEFAULT_EAPOL_FLAGS); +#endif /* IEEE8021X_EAPOL */ + for (i = 0; i < 4; i++) + write_wep_key(netw, i, ssid); + INT(wep_tx_keyidx); + INT(priority); +#ifdef IEEE8021X_EAPOL + INT_DEF(eap_workaround, DEFAULT_EAP_WORKAROUND); + STR(pac_file); + INT_DEF(fragment_size, DEFAULT_FRAGMENT_SIZE); +#endif /* IEEE8021X_EAPOL */ + INT(mode); + INT(proactive_key_caching); + INT(disabled); + INT(peerkey); +#ifdef CONFIG_IEEE80211W + INT(ieee80211w); +#endif /* CONFIG_IEEE80211W */ + STR(id_str); + +#undef STR +#undef INT +#undef INT_DEF + + RegCloseKey(netw); + + return errors ? -1 : 0; +} + + +static int wpa_config_write_blob(HKEY hk, struct wpa_config_blob *blob) +{ + HKEY bhk; + LONG ret; + TCHAR *name; + + ret = RegCreateKeyEx(hk, TEXT("blobs"), 0, NULL, 0, KEY_WRITE, NULL, + &bhk, NULL); + if (ret != ERROR_SUCCESS) { + wpa_printf(MSG_DEBUG, "WINREG: Could not add blobs key: " + "error 0x%x (%d)", + (unsigned int) ret, (int) GetLastError()); + return -1; + } + + name = wpa_strdup_tchar(blob->name); + ret = RegSetValueEx(bhk, name, 0, REG_BINARY, blob->data, + blob->len); + if (ret != ERROR_SUCCESS) { + wpa_printf(MSG_ERROR, "WINREG: Failed to set blob %s': " + "error 0x%x (%d)", blob->name, (unsigned int) ret, + (int) GetLastError()); + RegCloseKey(bhk); + os_free(name); + return -1; + } + os_free(name); + + RegCloseKey(bhk); + + return 0; +} + + +int wpa_config_write(const char *name, struct wpa_config *config) +{ + TCHAR buf[256]; + HKEY hk; + LONG ret; + int errors = 0; + struct wpa_ssid *ssid; + struct wpa_config_blob *blob; + int id; + + wpa_printf(MSG_DEBUG, "Writing configuration file '%s'", name); + +#ifdef UNICODE + _snwprintf(buf, 256, WPA_KEY_PREFIX TEXT("\\configs\\%S"), name); +#else /* UNICODE */ + os_snprintf(buf, 256, WPA_KEY_PREFIX TEXT("\\configs\\%s"), name); +#endif /* UNICODE */ + + ret = RegOpenKeyEx(WPA_KEY_ROOT, buf, 0, KEY_SET_VALUE | DELETE, &hk); + if (ret != ERROR_SUCCESS) { + wpa_printf(MSG_ERROR, "Could not open wpa_supplicant " + "configuration registry %s: error %d", buf, + (int) GetLastError()); + return -1; + } + + if (wpa_config_write_global(config, hk)) { + wpa_printf(MSG_ERROR, "Failed to write global configuration " + "data"); + errors++; + } + + wpa_config_delete_subkeys(hk, TEXT("networks")); + for (ssid = config->ssid, id = 0; ssid; ssid = ssid->next, id++) { + if (wpa_config_write_network(hk, ssid, id)) + errors++; + } + + RegDeleteKey(hk, TEXT("blobs")); + for (blob = config->blobs; blob; blob = blob->next) { + if (wpa_config_write_blob(hk, blob)) + errors++; + } + + RegCloseKey(hk); + + wpa_printf(MSG_DEBUG, "Configuration '%s' written %ssuccessfully", + name, errors ? "un" : ""); + return errors ? -1 : 0; +} diff --git a/contrib/wpa_supplicant/crypto.c b/contrib/wpa_supplicant/crypto.c index b4c81892c66e..c5edd24c4b55 100644 --- a/contrib/wpa_supplicant/crypto.c +++ b/contrib/wpa_supplicant/crypto.c @@ -1,6 +1,6 @@ /* * WPA Supplicant / wrapper functions for libcrypto - * Copyright (c) 2004-2005, Jouni Malinen <jkmaline@cc.hut.fi> + * Copyright (c) 2004-2005, Jouni Malinen <j@w1.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 @@ -12,9 +12,8 @@ * See README and COPYING for more details. */ -#include <string.h> -#include <sys/types.h> - +#include "includes.h" +#include <openssl/opensslv.h> #include <openssl/md4.h> #include <openssl/md5.h> #include <openssl/sha.h> @@ -36,7 +35,7 @@ void md4_vector(size_t num_elem, const u8 *addr[], const size_t *len, u8 *mac) { MD4_CTX ctx; - int i; + size_t i; MD4_Init(&ctx); for (i = 0; i < num_elem; i++) @@ -70,7 +69,7 @@ void des_encrypt(const u8 *clear, const u8 *key, u8 *cypher) void md5_vector(size_t num_elem, const u8 *addr[], const size_t *len, u8 *mac) { MD5_CTX ctx; - int i; + size_t i; MD5_Init(&ctx); for (i = 0; i < num_elem; i++) @@ -82,7 +81,7 @@ void md5_vector(size_t num_elem, const u8 *addr[], const size_t *len, u8 *mac) void sha1_vector(size_t num_elem, const u8 *addr[], const size_t *len, u8 *mac) { SHA_CTX ctx; - int i; + size_t i; SHA1_Init(&ctx); for (i = 0; i < num_elem; i++) @@ -91,24 +90,78 @@ void sha1_vector(size_t num_elem, const u8 *addr[], const size_t *len, u8 *mac) } -void sha1_transform(u8 *state, const u8 data[64]) +static void sha1_transform(u8 *state, const u8 data[64]) { SHA_CTX context; - memset(&context, 0, sizeof(context)); - memcpy(&context.h0, state, 5 * 4); + os_memset(&context, 0, sizeof(context)); + os_memcpy(&context.h0, state, 5 * 4); SHA1_Transform(&context, data); - memcpy(state, &context.h0, 5 * 4); + os_memcpy(state, &context.h0, 5 * 4); +} + + +int fips186_2_prf(const u8 *seed, size_t seed_len, u8 *x, size_t xlen) +{ + u8 xkey[64]; + u32 t[5], _t[5]; + int i, j, m, k; + u8 *xpos = x; + u32 carry; + + if (seed_len > sizeof(xkey)) + seed_len = sizeof(xkey); + + /* FIPS 186-2 + change notice 1 */ + + os_memcpy(xkey, seed, seed_len); + os_memset(xkey + seed_len, 0, 64 - seed_len); + t[0] = 0x67452301; + t[1] = 0xEFCDAB89; + t[2] = 0x98BADCFE; + t[3] = 0x10325476; + t[4] = 0xC3D2E1F0; + + m = xlen / 40; + for (j = 0; j < m; j++) { + /* XSEED_j = 0 */ + for (i = 0; i < 2; i++) { + /* XVAL = (XKEY + XSEED_j) mod 2^b */ + + /* w_i = G(t, XVAL) */ + os_memcpy(_t, t, 20); + sha1_transform((u8 *) _t, xkey); + _t[0] = host_to_be32(_t[0]); + _t[1] = host_to_be32(_t[1]); + _t[2] = host_to_be32(_t[2]); + _t[3] = host_to_be32(_t[3]); + _t[4] = host_to_be32(_t[4]); + os_memcpy(xpos, _t, 20); + + /* XKEY = (1 + XKEY + w_i) mod 2^b */ + carry = 1; + for (k = 19; k >= 0; k--) { + carry += xkey[k] + xpos[k]; + xkey[k] = carry & 0xff; + carry >>= 8; + } + + xpos += 20; + } + /* x_j = w_0|w_1 */ + } + + return 0; } void * aes_encrypt_init(const u8 *key, size_t len) { AES_KEY *ak; - ak = malloc(sizeof(*ak)); + ak = os_malloc(sizeof(*ak)); if (ak == NULL) return NULL; if (AES_set_encrypt_key(key, 8 * len, ak) < 0) { - free(ak); + os_free(ak); return NULL; } return ak; @@ -123,18 +176,18 @@ void aes_encrypt(void *ctx, const u8 *plain, u8 *crypt) void aes_encrypt_deinit(void *ctx) { - free(ctx); + os_free(ctx); } void * aes_decrypt_init(const u8 *key, size_t len) { AES_KEY *ak; - ak = malloc(sizeof(*ak)); + ak = os_malloc(sizeof(*ak)); if (ak == NULL) return NULL; if (AES_set_decrypt_key(key, 8 * len, ak) < 0) { - free(ak); + os_free(ak); return NULL; } return ak; @@ -149,6 +202,6 @@ void aes_decrypt(void *ctx, const u8 *crypt, u8 *plain) void aes_decrypt_deinit(void *ctx) { - free(ctx); + os_free(ctx); } #endif /* EAP_TLS_FUNCS */ diff --git a/contrib/wpa_supplicant/crypto.h b/contrib/wpa_supplicant/crypto.h index e664861afe71..00b13b91c48e 100644 --- a/contrib/wpa_supplicant/crypto.h +++ b/contrib/wpa_supplicant/crypto.h @@ -1,6 +1,6 @@ /* * WPA Supplicant / wrapper functions for crypto libraries - * Copyright (c) 2004-2005, Jouni Malinen <jkmaline@cc.hut.fi> + * Copyright (c) 2004-2005, Jouni Malinen <j@w1.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 @@ -56,16 +56,28 @@ void sha1_vector(size_t num_elem, const u8 *addr[], const size_t *len, u8 *mac); /** - * sha1_transform - Perform one SHA-1 transform step - * @state: SHA-1 state - * @data: Input data for the SHA-1 transform + * fips186_2-prf - NIST FIPS Publication 186-2 change notice 1 PRF + * @seed: Seed/key for the PRF + * @seed_len: Seed length in bytes + * @x: Buffer for PRF output + * @xlen: Output length in bytes + * Returns: 0 on success, -1 on failure * - * This function is used to implement random number generation specified in - * NIST FIPS Publication 186-2 for EAP-SIM. This PRF uses a function that is - * similar to SHA-1, but has different message padding and as such, access to - * just part of the SHA-1 is needed. + * This function implements random number generation specified in NIST FIPS + * Publication 186-2 for EAP-SIM. This PRF uses a function that is similar to + * SHA-1, but has different message padding. */ -void sha1_transform(u8 *state, const u8 data[64]); +int fips186_2_prf(const u8 *seed, size_t seed_len, u8 *x, size_t xlen); + +/** + * sha256_vector - SHA256 hash for data vector + * @num_elem: Number of elements in the data vector + * @addr: Pointers to the data areas + * @len: Lengths of the data blocks + * @mac: Buffer for the hash + */ +void sha256_vector(size_t num_elem, const u8 *addr[], const size_t *len, + u8 *mac); /** * des_encrypt - Encrypt one block with DES @@ -120,4 +132,282 @@ void aes_decrypt(void *ctx, const u8 *crypt, u8 *plain); void aes_decrypt_deinit(void *ctx); +enum crypto_hash_alg { + CRYPTO_HASH_ALG_MD5, CRYPTO_HASH_ALG_SHA1, + CRYPTO_HASH_ALG_HMAC_MD5, CRYPTO_HASH_ALG_HMAC_SHA1 +}; + +struct crypto_hash; + +/** + * crypto_hash_init - Initialize hash/HMAC function + * @alg: Hash algorithm + * @key: Key for keyed hash (e.g., HMAC) or %NULL if not needed + * @key_len: Length of the key in bytes + * Returns: Pointer to hash context to use with other hash functions or %NULL + * on failure + * + * This function is only used with internal TLSv1 implementation + * (CONFIG_TLS=internal). If that is not used, the crypto wrapper does not need + * to implement this. + */ +struct crypto_hash * crypto_hash_init(enum crypto_hash_alg alg, const u8 *key, + size_t key_len); + +/** + * crypto_hash_update - Add data to hash calculation + * @ctx: Context pointer from crypto_hash_init() + * @data: Data buffer to add + * @len: Length of the buffer + * + * This function is only used with internal TLSv1 implementation + * (CONFIG_TLS=internal). If that is not used, the crypto wrapper does not need + * to implement this. + */ +void crypto_hash_update(struct crypto_hash *ctx, const u8 *data, size_t len); + +/** + * crypto_hash_finish - Complete hash calculation + * @ctx: Context pointer from crypto_hash_init() + * @hash: Buffer for hash value or %NULL if caller is just freeing the hash + * context + * @len: Pointer to length of the buffer or %NULL if caller is just freeing the + * hash context; on return, this is set to the actual length of the hash value + * Returns: 0 on success, -1 if buffer is too small (len set to needed length), + * or -2 on other failures (including failed crypto_hash_update() operations) + * + * This function calculates the hash value and frees the context buffer that + * was used for hash calculation. + * + * This function is only used with internal TLSv1 implementation + * (CONFIG_TLS=internal). If that is not used, the crypto wrapper does not need + * to implement this. + */ +int crypto_hash_finish(struct crypto_hash *ctx, u8 *hash, size_t *len); + + +enum crypto_cipher_alg { + CRYPTO_CIPHER_NULL = 0, CRYPTO_CIPHER_ALG_AES, CRYPTO_CIPHER_ALG_3DES, + CRYPTO_CIPHER_ALG_DES, CRYPTO_CIPHER_ALG_RC2, CRYPTO_CIPHER_ALG_RC4 +}; + +struct crypto_cipher; + +/** + * crypto_cipher_init - Initialize block/stream cipher function + * @alg: Cipher algorithm + * @iv: Initialization vector for block ciphers or %NULL for stream ciphers + * @key: Cipher key + * @key_len: Length of key in bytes + * Returns: Pointer to cipher context to use with other cipher functions or + * %NULL on failure + * + * This function is only used with internal TLSv1 implementation + * (CONFIG_TLS=internal). If that is not used, the crypto wrapper does not need + * to implement this. + */ +struct crypto_cipher * crypto_cipher_init(enum crypto_cipher_alg alg, + const u8 *iv, const u8 *key, + size_t key_len); + +/** + * crypto_cipher_encrypt - Cipher encrypt + * @ctx: Context pointer from crypto_cipher_init() + * @plain: Plaintext to cipher + * @crypt: Resulting ciphertext + * @len: Length of the plaintext + * Returns: 0 on success, -1 on failure + * + * This function is only used with internal TLSv1 implementation + * (CONFIG_TLS=internal). If that is not used, the crypto wrapper does not need + * to implement this. + */ +int crypto_cipher_encrypt(struct crypto_cipher *ctx, const u8 *plain, + u8 *crypt, size_t len); + +/** + * crypto_cipher_decrypt - Cipher decrypt + * @ctx: Context pointer from crypto_cipher_init() + * @crypt: Ciphertext to decrypt + * @plain: Resulting plaintext + * @len: Length of the cipher text + * Returns: 0 on success, -1 on failure + * + * This function is only used with internal TLSv1 implementation + * (CONFIG_TLS=internal). If that is not used, the crypto wrapper does not need + * to implement this. + */ +int crypto_cipher_decrypt(struct crypto_cipher *ctx, const u8 *crypt, + u8 *plain, size_t len); + +/** + * crypto_cipher_decrypt - Free cipher context + * @ctx: Context pointer from crypto_cipher_init() + * + * This function is only used with internal TLSv1 implementation + * (CONFIG_TLS=internal). If that is not used, the crypto wrapper does not need + * to implement this. + */ +void crypto_cipher_deinit(struct crypto_cipher *ctx); + + +struct crypto_public_key; +struct crypto_private_key; + +/** + * crypto_public_key_import - Import an RSA public key + * @key: Key buffer (DER encoded RSA public key) + * @len: Key buffer length in bytes + * Returns: Pointer to the public key or %NULL on failure + * + * This function can just return %NULL if the crypto library supports X.509 + * parsing. In that case, crypto_public_key_from_cert() is used to import the + * public key from a certificate. + * + * This function is only used with internal TLSv1 implementation + * (CONFIG_TLS=internal). If that is not used, the crypto wrapper does not need + * to implement this. + */ +struct crypto_public_key * crypto_public_key_import(const u8 *key, size_t len); + +/** + * crypto_private_key_import - Import an RSA private key + * @key: Key buffer (DER encoded RSA private key) + * @len: Key buffer length in bytes + * Returns: Pointer to the private key or %NULL on failure + * + * This function is only used with internal TLSv1 implementation + * (CONFIG_TLS=internal). If that is not used, the crypto wrapper does not need + * to implement this. + */ +struct crypto_private_key * crypto_private_key_import(const u8 *key, + size_t len); + +/** + * crypto_public_key_from_cert - Import an RSA public key from a certificate + * @buf: DER encoded X.509 certificate + * @len: Certificate buffer length in bytes + * Returns: Pointer to public key or %NULL on failure + * + * This function can just return %NULL if the crypto library does not support + * X.509 parsing. In that case, internal code will be used to parse the + * certificate and public key is imported using crypto_public_key_import(). + * + * This function is only used with internal TLSv1 implementation + * (CONFIG_TLS=internal). If that is not used, the crypto wrapper does not need + * to implement this. + */ +struct crypto_public_key * crypto_public_key_from_cert(const u8 *buf, + size_t len); + +/** + * crypto_public_key_encrypt_pkcs1_v15 - Public key encryption (PKCS #1 v1.5) + * @key: Public key + * @in: Plaintext buffer + * @inlen: Length of plaintext buffer in bytes + * @out: Output buffer for encrypted data + * @outlen: Length of output buffer in bytes; set to used length on success + * Returns: 0 on success, -1 on failure + * + * This function is only used with internal TLSv1 implementation + * (CONFIG_TLS=internal). If that is not used, the crypto wrapper does not need + * to implement this. + */ +int crypto_public_key_encrypt_pkcs1_v15(struct crypto_public_key *key, + const u8 *in, size_t inlen, + u8 *out, size_t *outlen); + +/** + * crypto_private_key_sign_pkcs1 - Sign with private key (PKCS #1) + * @key: Private key from crypto_private_key_import() + * @in: Plaintext buffer + * @inlen: Length of plaintext buffer in bytes + * @out: Output buffer for encrypted (signed) data + * @outlen: Length of output buffer in bytes; set to used length on success + * Returns: 0 on success, -1 on failure + * + * This function is only used with internal TLSv1 implementation + * (CONFIG_TLS=internal). If that is not used, the crypto wrapper does not need + * to implement this. + */ +int crypto_private_key_sign_pkcs1(struct crypto_private_key *key, + const u8 *in, size_t inlen, + u8 *out, size_t *outlen); + +/** + * crypto_public_key_free - Free public key + * @key: Public key + * + * This function is only used with internal TLSv1 implementation + * (CONFIG_TLS=internal). If that is not used, the crypto wrapper does not need + * to implement this. + */ +void crypto_public_key_free(struct crypto_public_key *key); + +/** + * crypto_private_key_free - Free private key + * @key: Private key from crypto_private_key_import() + * + * This function is only used with internal TLSv1 implementation + * (CONFIG_TLS=internal). If that is not used, the crypto wrapper does not need + * to implement this. + */ +void crypto_private_key_free(struct crypto_private_key *key); + +/** + * crypto_public_key_decrypt_pkcs1 - Decrypt PKCS #1 signature + * @key: Public key + * @crypt: Encrypted signature data (using the private key) + * @crypt_len: Encrypted signature data length + * @plain: Buffer for plaintext (at least crypt_len bytes) + * @plain_len: Plaintext length (max buffer size on input, real len on output); + * Returns: 0 on success, -1 on failure + */ +int crypto_public_key_decrypt_pkcs1(struct crypto_public_key *key, + const u8 *crypt, size_t crypt_len, + u8 *plain, size_t *plain_len); + +/** + * crypto_global_init - Initialize crypto wrapper + * + * This function is only used with internal TLSv1 implementation + * (CONFIG_TLS=internal). If that is not used, the crypto wrapper does not need + * to implement this. + */ +int crypto_global_init(void); + +/** + * crypto_global_deinit - Deinitialize crypto wrapper + * + * This function is only used with internal TLSv1 implementation + * (CONFIG_TLS=internal). If that is not used, the crypto wrapper does not need + * to implement this. + */ +void crypto_global_deinit(void); + +/** + * crypto_mod_exp - Modular exponentiation of large integers + * @base: Base integer (big endian byte array) + * @base_len: Length of base integer in bytes + * @power: Power integer (big endian byte array) + * @power_len: Length of power integer in bytes + * @modulus: Modulus integer (big endian byte array) + * @modulus_len: Length of modulus integer in bytes + * @result: Buffer for the result + * @result_len: Result length (max buffer size on input, real len on output) + * Returns: 0 on success, -1 on failure + * + * This function calculates result = base ^ power mod modulus. modules_len is + * used as the maximum size of modulus buffer. It is set to the used size on + * success. + * + * This function is only used with internal TLSv1 implementation + * (CONFIG_TLS=internal). If that is not used, the crypto wrapper does not need + * to implement this. + */ +int crypto_mod_exp(const u8 *base, size_t base_len, + const u8 *power, size_t power_len, + const u8 *modulus, size_t modulus_len, + u8 *result, size_t *result_len); + #endif /* CRYPTO_H */ diff --git a/contrib/wpa_supplicant/crypto_cryptoapi.c b/contrib/wpa_supplicant/crypto_cryptoapi.c new file mode 100644 index 000000000000..bb0573078d24 --- /dev/null +++ b/contrib/wpa_supplicant/crypto_cryptoapi.c @@ -0,0 +1,801 @@ +/* + * WPA Supplicant / Crypto wrapper for Microsoft CryptoAPI + * Copyright (c) 2005-2006, Jouni Malinen <j@w1.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 "includes.h" +#include <windows.h> +#include <wincrypt.h> + +#include "common.h" +#include "crypto.h" + +#ifndef MS_ENH_RSA_AES_PROV +#ifdef UNICODE +#define MS_ENH_RSA_AES_PROV \ +L"Microsoft Enhanced RSA and AES Cryptographic Provider (Prototype)" +#else +#define MS_ENH_RSA_AES_PROV \ +"Microsoft Enhanced RSA and AES Cryptographic Provider (Prototype)" +#endif +#endif /* MS_ENH_RSA_AES_PROV */ + +#ifndef CALG_HMAC +#define CALG_HMAC (ALG_CLASS_HASH | ALG_TYPE_ANY | ALG_SID_HMAC) +#endif + +#ifdef CONFIG_TLS_INTERNAL +#ifdef __MINGW32_VERSION +/* + * MinGW does not yet include all the needed definitions for CryptoAPI, so + * define here whatever extra is needed. + */ + +static PCCERT_CONTEXT WINAPI +(*CertCreateCertificateContext)(DWORD dwCertEncodingType, + const BYTE *pbCertEncoded, + DWORD cbCertEncoded) += NULL; /* to be loaded from crypt32.dll */ + +static BOOL WINAPI +(*CryptImportPublicKeyInfo)(HCRYPTPROV hCryptProv, DWORD dwCertEncodingType, + PCERT_PUBLIC_KEY_INFO pInfo, HCRYPTKEY *phKey) += NULL; /* to be loaded from crypt32.dll */ + + +static int mingw_load_crypto_func(void) +{ + HINSTANCE dll; + + /* MinGW does not yet have full CryptoAPI support, so load the needed + * function here. */ + + if (CertCreateCertificateContext) + return 0; + + dll = LoadLibrary("crypt32"); + if (dll == NULL) { + wpa_printf(MSG_DEBUG, "CryptoAPI: Could not load crypt32 " + "library"); + return -1; + } + + CertCreateCertificateContext = (void *) GetProcAddress( + dll, "CertCreateCertificateContext"); + if (CertCreateCertificateContext == NULL) { + wpa_printf(MSG_DEBUG, "CryptoAPI: Could not get " + "CertCreateCertificateContext() address from " + "crypt32 library"); + return -1; + } + + CryptImportPublicKeyInfo = GetProcAddress( + dll, "CryptImportPublicKeyInfo"); + if (CryptImportPublicKeyInfo == NULL) { + wpa_printf(MSG_DEBUG, "CryptoAPI: Could not get " + "CryptImportPublicKeyInfo() address from " + "crypt32 library"); + return -1; + } + + return 0; +} + +#else /* __MINGW32_VERSION */ + +static int mingw_load_crypto_func(void) +{ + return 0; +} + +#endif /* __MINGW32_VERSION */ +#endif /* CONFIG_TLS_INTERNAL */ + + +static void cryptoapi_report_error(const char *msg) +{ + char *s, *pos; + DWORD err = GetLastError(); + + if (FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER | + FORMAT_MESSAGE_FROM_SYSTEM, + NULL, err, 0, (LPTSTR) &s, 0, NULL) == 0) { + wpa_printf(MSG_DEBUG, "CryptoAPI: %s: %d", msg, (int) err); + } + + pos = s; + while (*pos) { + if (*pos == '\n' || *pos == '\r') { + *pos = '\0'; + break; + } + pos++; + } + + wpa_printf(MSG_DEBUG, "CryptoAPI: %s: %d: (%s)", msg, (int) err, s); + LocalFree(s); +} + + +int cryptoapi_hash_vector(ALG_ID alg, size_t hash_len, size_t num_elem, + const u8 *addr[], const size_t *len, u8 *mac) +{ + HCRYPTPROV prov; + HCRYPTHASH hash; + size_t i; + DWORD hlen; + int ret = 0; + + if (!CryptAcquireContext(&prov, NULL, NULL, PROV_RSA_FULL, 0)) { + cryptoapi_report_error("CryptAcquireContext"); + return -1; + } + + if (!CryptCreateHash(prov, alg, 0, 0, &hash)) { + cryptoapi_report_error("CryptCreateHash"); + CryptReleaseContext(prov, 0); + return -1; + } + + for (i = 0; i < num_elem; i++) { + if (!CryptHashData(hash, (BYTE *) addr[i], len[i], 0)) { + cryptoapi_report_error("CryptHashData"); + CryptDestroyHash(hash); + CryptReleaseContext(prov, 0); + } + } + + hlen = hash_len; + if (!CryptGetHashParam(hash, HP_HASHVAL, mac, &hlen, 0)) { + cryptoapi_report_error("CryptGetHashParam"); + ret = -1; + } + + CryptDestroyHash(hash); + CryptReleaseContext(prov, 0); + + return ret; +} + + +void md4_vector(size_t num_elem, const u8 *addr[], const size_t *len, u8 *mac) +{ + cryptoapi_hash_vector(CALG_MD4, 16, num_elem, addr, len, mac); +} + + +void des_encrypt(const u8 *clear, const u8 *key, u8 *cypher) +{ + u8 next, tmp; + int i; + HCRYPTPROV prov; + HCRYPTKEY ckey; + DWORD dlen; + struct { + BLOBHEADER hdr; + DWORD len; + BYTE key[8]; + } key_blob; + DWORD mode = CRYPT_MODE_ECB; + + key_blob.hdr.bType = PLAINTEXTKEYBLOB; + key_blob.hdr.bVersion = CUR_BLOB_VERSION; + key_blob.hdr.reserved = 0; + key_blob.hdr.aiKeyAlg = CALG_DES; + key_blob.len = 8; + + /* Add parity bits to the key */ + next = 0; + for (i = 0; i < 7; i++) { + tmp = key[i]; + key_blob.key[i] = (tmp >> i) | next | 1; + next = tmp << (7 - i); + } + key_blob.key[i] = next | 1; + + if (!CryptAcquireContext(&prov, NULL, MS_ENHANCED_PROV, PROV_RSA_FULL, + CRYPT_VERIFYCONTEXT)) { + wpa_printf(MSG_DEBUG, "CryptoAPI: CryptAcquireContext failed: " + "%d", (int) GetLastError()); + return; + } + + if (!CryptImportKey(prov, (BYTE *) &key_blob, sizeof(key_blob), 0, 0, + &ckey)) { + wpa_printf(MSG_DEBUG, "CryptoAPI: CryptImportKey failed: %d", + (int) GetLastError()); + CryptReleaseContext(prov, 0); + return; + } + + if (!CryptSetKeyParam(ckey, KP_MODE, (BYTE *) &mode, 0)) { + wpa_printf(MSG_DEBUG, "CryptoAPI: CryptSetKeyParam(KP_MODE) " + "failed: %d", (int) GetLastError()); + CryptDestroyKey(ckey); + CryptReleaseContext(prov, 0); + return; + } + + os_memcpy(cypher, clear, 8); + dlen = 8; + if (!CryptEncrypt(ckey, 0, FALSE, 0, cypher, &dlen, 8)) { + wpa_printf(MSG_DEBUG, "CryptoAPI: CryptEncrypt failed: %d", + (int) GetLastError()); + os_memset(cypher, 0, 8); + } + + CryptDestroyKey(ckey); + CryptReleaseContext(prov, 0); +} + + +#ifdef EAP_TLS_FUNCS +void md5_vector(size_t num_elem, const u8 *addr[], const size_t *len, u8 *mac) +{ + cryptoapi_hash_vector(CALG_MD5, 16, num_elem, addr, len, mac); +} + + +void sha1_vector(size_t num_elem, const u8 *addr[], const size_t *len, u8 *mac) +{ + cryptoapi_hash_vector(CALG_SHA, 20, num_elem, addr, len, mac); +} + + +struct aes_context { + HCRYPTPROV prov; + HCRYPTKEY ckey; +}; + + +void * aes_encrypt_init(const u8 *key, size_t len) +{ + struct aes_context *akey; + struct { + BLOBHEADER hdr; + DWORD len; + BYTE key[16]; + } key_blob; + DWORD mode = CRYPT_MODE_ECB; + + if (len != 16) + return NULL; + + key_blob.hdr.bType = PLAINTEXTKEYBLOB; + key_blob.hdr.bVersion = CUR_BLOB_VERSION; + key_blob.hdr.reserved = 0; + key_blob.hdr.aiKeyAlg = CALG_AES_128; + key_blob.len = len; + os_memcpy(key_blob.key, key, len); + + akey = os_zalloc(sizeof(*akey)); + if (akey == NULL) + return NULL; + + if (!CryptAcquireContext(&akey->prov, NULL, + MS_ENH_RSA_AES_PROV, PROV_RSA_AES, + CRYPT_VERIFYCONTEXT)) { + wpa_printf(MSG_DEBUG, "CryptoAPI: CryptAcquireContext failed: " + "%d", (int) GetLastError()); + os_free(akey); + return NULL; + } + + if (!CryptImportKey(akey->prov, (BYTE *) &key_blob, sizeof(key_blob), + 0, 0, &akey->ckey)) { + wpa_printf(MSG_DEBUG, "CryptoAPI: CryptImportKey failed: %d", + (int) GetLastError()); + CryptReleaseContext(akey->prov, 0); + os_free(akey); + return NULL; + } + + if (!CryptSetKeyParam(akey->ckey, KP_MODE, (BYTE *) &mode, 0)) { + wpa_printf(MSG_DEBUG, "CryptoAPI: CryptSetKeyParam(KP_MODE) " + "failed: %d", (int) GetLastError()); + CryptDestroyKey(akey->ckey); + CryptReleaseContext(akey->prov, 0); + os_free(akey); + return NULL; + } + + return akey; +} + + +void aes_encrypt(void *ctx, const u8 *plain, u8 *crypt) +{ + struct aes_context *akey = ctx; + DWORD dlen; + + os_memcpy(crypt, plain, 16); + dlen = 16; + if (!CryptEncrypt(akey->ckey, 0, FALSE, 0, crypt, &dlen, 16)) { + wpa_printf(MSG_DEBUG, "CryptoAPI: CryptEncrypt failed: %d", + (int) GetLastError()); + os_memset(crypt, 0, 16); + } +} + + +void aes_encrypt_deinit(void *ctx) +{ + struct aes_context *akey = ctx; + if (akey) { + CryptDestroyKey(akey->ckey); + CryptReleaseContext(akey->prov, 0); + os_free(akey); + } +} + + +void * aes_decrypt_init(const u8 *key, size_t len) +{ + return aes_encrypt_init(key, len); +} + + +void aes_decrypt(void *ctx, const u8 *crypt, u8 *plain) +{ + struct aes_context *akey = ctx; + DWORD dlen; + + os_memcpy(plain, crypt, 16); + dlen = 16; + + if (!CryptDecrypt(akey->ckey, 0, FALSE, 0, plain, &dlen)) { + wpa_printf(MSG_DEBUG, "CryptoAPI: CryptDecrypt failed: %d", + (int) GetLastError()); + } +} + + +void aes_decrypt_deinit(void *ctx) +{ + aes_encrypt_deinit(ctx); +} + +#ifdef CONFIG_TLS_INTERNAL + +struct crypto_hash { + enum crypto_hash_alg alg; + int error; + HCRYPTPROV prov; + HCRYPTHASH hash; + HCRYPTKEY key; +}; + +struct crypto_hash * crypto_hash_init(enum crypto_hash_alg alg, const u8 *key, + size_t key_len) +{ + struct crypto_hash *ctx; + ALG_ID calg; + struct { + BLOBHEADER hdr; + DWORD len; + BYTE key[32]; + } key_blob; + + os_memset(&key_blob, 0, sizeof(key_blob)); + switch (alg) { + case CRYPTO_HASH_ALG_MD5: + calg = CALG_MD5; + break; + case CRYPTO_HASH_ALG_SHA1: + calg = CALG_SHA; + break; + case CRYPTO_HASH_ALG_HMAC_MD5: + case CRYPTO_HASH_ALG_HMAC_SHA1: + calg = CALG_HMAC; + key_blob.hdr.bType = PLAINTEXTKEYBLOB; + key_blob.hdr.bVersion = CUR_BLOB_VERSION; + key_blob.hdr.reserved = 0; + /* + * Note: RC2 is not really used, but that can be used to + * import HMAC keys of up to 16 byte long. + * CRYPT_IPSEC_HMAC_KEY flag for CryptImportKey() is needed to + * be able to import longer keys (HMAC-SHA1 uses 20-byte key). + */ + key_blob.hdr.aiKeyAlg = CALG_RC2; + key_blob.len = key_len; + if (key_len > sizeof(key_blob.key)) + return NULL; + os_memcpy(key_blob.key, key, key_len); + break; + default: + return NULL; + } + + ctx = os_zalloc(sizeof(*ctx)); + if (ctx == NULL) + return NULL; + + ctx->alg = alg; + + if (!CryptAcquireContext(&ctx->prov, NULL, NULL, PROV_RSA_FULL, 0)) { + cryptoapi_report_error("CryptAcquireContext"); + os_free(ctx); + return NULL; + } + + if (calg == CALG_HMAC) { +#ifndef CRYPT_IPSEC_HMAC_KEY +#define CRYPT_IPSEC_HMAC_KEY 0x00000100 +#endif + if (!CryptImportKey(ctx->prov, (BYTE *) &key_blob, + sizeof(key_blob), 0, CRYPT_IPSEC_HMAC_KEY, + &ctx->key)) { + cryptoapi_report_error("CryptImportKey"); + CryptReleaseContext(ctx->prov, 0); + os_free(ctx); + return NULL; + } + } + + if (!CryptCreateHash(ctx->prov, calg, ctx->key, 0, &ctx->hash)) { + cryptoapi_report_error("CryptCreateHash"); + CryptReleaseContext(ctx->prov, 0); + os_free(ctx); + return NULL; + } + + if (calg == CALG_HMAC) { + HMAC_INFO info; + os_memset(&info, 0, sizeof(info)); + switch (alg) { + case CRYPTO_HASH_ALG_HMAC_MD5: + info.HashAlgid = CALG_MD5; + break; + case CRYPTO_HASH_ALG_HMAC_SHA1: + info.HashAlgid = CALG_SHA; + break; + default: + /* unreachable */ + break; + } + + if (!CryptSetHashParam(ctx->hash, HP_HMAC_INFO, (BYTE *) &info, + 0)) { + cryptoapi_report_error("CryptSetHashParam"); + CryptDestroyHash(ctx->hash); + CryptReleaseContext(ctx->prov, 0); + os_free(ctx); + return NULL; + } + } + + return ctx; +} + + +void crypto_hash_update(struct crypto_hash *ctx, const u8 *data, size_t len) +{ + if (ctx == NULL || ctx->error) + return; + + if (!CryptHashData(ctx->hash, (BYTE *) data, len, 0)) { + cryptoapi_report_error("CryptHashData"); + ctx->error = 1; + } +} + + +int crypto_hash_finish(struct crypto_hash *ctx, u8 *mac, size_t *len) +{ + int ret = 0; + DWORD hlen; + + if (ctx == NULL) + return -2; + + if (mac == NULL || len == NULL) + goto done; + + if (ctx->error) { + ret = -2; + goto done; + } + + hlen = *len; + if (!CryptGetHashParam(ctx->hash, HP_HASHVAL, mac, &hlen, 0)) { + cryptoapi_report_error("CryptGetHashParam"); + ret = -2; + } + *len = hlen; + +done: + if (ctx->alg == CRYPTO_HASH_ALG_HMAC_SHA1 || + ctx->alg == CRYPTO_HASH_ALG_HMAC_MD5) + CryptDestroyKey(ctx->key); + + os_free(ctx); + + return ret; +} + + +struct crypto_cipher { + HCRYPTPROV prov; + HCRYPTKEY key; +}; + + +struct crypto_cipher * crypto_cipher_init(enum crypto_cipher_alg alg, + const u8 *iv, const u8 *key, + size_t key_len) +{ + struct crypto_cipher *ctx; + struct { + BLOBHEADER hdr; + DWORD len; + BYTE key[32]; + } key_blob; + DWORD mode = CRYPT_MODE_CBC; + + key_blob.hdr.bType = PLAINTEXTKEYBLOB; + key_blob.hdr.bVersion = CUR_BLOB_VERSION; + key_blob.hdr.reserved = 0; + key_blob.len = key_len; + if (key_len > sizeof(key_blob.key)) + return NULL; + os_memcpy(key_blob.key, key, key_len); + + switch (alg) { + case CRYPTO_CIPHER_ALG_AES: + if (key_len == 32) + key_blob.hdr.aiKeyAlg = CALG_AES_256; + else if (key_len == 24) + key_blob.hdr.aiKeyAlg = CALG_AES_192; + else + key_blob.hdr.aiKeyAlg = CALG_AES_128; + break; + case CRYPTO_CIPHER_ALG_3DES: + key_blob.hdr.aiKeyAlg = CALG_3DES; + break; + case CRYPTO_CIPHER_ALG_DES: + key_blob.hdr.aiKeyAlg = CALG_DES; + break; + case CRYPTO_CIPHER_ALG_RC2: + key_blob.hdr.aiKeyAlg = CALG_RC2; + break; + case CRYPTO_CIPHER_ALG_RC4: + key_blob.hdr.aiKeyAlg = CALG_RC4; + break; + default: + return NULL; + } + + ctx = os_zalloc(sizeof(*ctx)); + if (ctx == NULL) + return NULL; + + if (!CryptAcquireContext(&ctx->prov, NULL, MS_ENH_RSA_AES_PROV, + PROV_RSA_AES, CRYPT_VERIFYCONTEXT)) { + cryptoapi_report_error("CryptAcquireContext"); + goto fail1; + } + + if (!CryptImportKey(ctx->prov, (BYTE *) &key_blob, + sizeof(key_blob), 0, 0, &ctx->key)) { + cryptoapi_report_error("CryptImportKey"); + goto fail2; + } + + if (!CryptSetKeyParam(ctx->key, KP_MODE, (BYTE *) &mode, 0)) { + cryptoapi_report_error("CryptSetKeyParam(KP_MODE)"); + goto fail3; + } + + if (iv && !CryptSetKeyParam(ctx->key, KP_IV, (BYTE *) iv, 0)) { + cryptoapi_report_error("CryptSetKeyParam(KP_IV)"); + goto fail3; + } + + return ctx; + +fail3: + CryptDestroyKey(ctx->key); +fail2: + CryptReleaseContext(ctx->prov, 0); +fail1: + os_free(ctx); + return NULL; +} + + +int crypto_cipher_encrypt(struct crypto_cipher *ctx, const u8 *plain, + u8 *crypt, size_t len) +{ + DWORD dlen; + + os_memcpy(crypt, plain, len); + dlen = len; + if (!CryptEncrypt(ctx->key, 0, FALSE, 0, crypt, &dlen, len)) { + cryptoapi_report_error("CryptEncrypt"); + os_memset(crypt, 0, len); + return -1; + } + + return 0; +} + + +int crypto_cipher_decrypt(struct crypto_cipher *ctx, const u8 *crypt, + u8 *plain, size_t len) +{ + DWORD dlen; + + os_memcpy(plain, crypt, len); + dlen = len; + if (!CryptDecrypt(ctx->key, 0, FALSE, 0, plain, &dlen)) { + cryptoapi_report_error("CryptDecrypt"); + return -1; + } + + return 0; +} + + +void crypto_cipher_deinit(struct crypto_cipher *ctx) +{ + CryptDestroyKey(ctx->key); + CryptReleaseContext(ctx->prov, 0); + os_free(ctx); +} + + +struct crypto_public_key { + HCRYPTPROV prov; + HCRYPTKEY rsa; +}; + +struct crypto_private_key { + HCRYPTPROV prov; + HCRYPTKEY rsa; +}; + + +struct crypto_public_key * crypto_public_key_import(const u8 *key, size_t len) +{ + /* Use crypto_public_key_from_cert() instead. */ + return NULL; +} + + +struct crypto_private_key * crypto_private_key_import(const u8 *key, + size_t len) +{ + /* TODO */ + return NULL; +} + + +struct crypto_public_key * crypto_public_key_from_cert(const u8 *buf, + size_t len) +{ + struct crypto_public_key *pk; + PCCERT_CONTEXT cc; + + pk = os_zalloc(sizeof(*pk)); + if (pk == NULL) + return NULL; + + cc = CertCreateCertificateContext(X509_ASN_ENCODING | + PKCS_7_ASN_ENCODING, buf, len); + if (!cc) { + cryptoapi_report_error("CryptCreateCertificateContext"); + os_free(pk); + return NULL; + } + + if (!CryptAcquireContext(&pk->prov, NULL, MS_DEF_PROV, PROV_RSA_FULL, + 0)) { + cryptoapi_report_error("CryptAcquireContext"); + os_free(pk); + CertFreeCertificateContext(cc); + return NULL; + } + + if (!CryptImportPublicKeyInfo(pk->prov, X509_ASN_ENCODING | + PKCS_7_ASN_ENCODING, + &cc->pCertInfo->SubjectPublicKeyInfo, + &pk->rsa)) { + cryptoapi_report_error("CryptImportPublicKeyInfo"); + CryptReleaseContext(pk->prov, 0); + os_free(pk); + CertFreeCertificateContext(cc); + return NULL; + } + + CertFreeCertificateContext(cc); + + return pk; +} + + +int crypto_public_key_encrypt_pkcs1_v15(struct crypto_public_key *key, + const u8 *in, size_t inlen, + u8 *out, size_t *outlen) +{ + DWORD clen; + u8 *tmp; + size_t i; + + if (*outlen < inlen) + return -1; + tmp = malloc(*outlen); + if (tmp == NULL) + return -1; + + os_memcpy(tmp, in, inlen); + clen = inlen; + if (!CryptEncrypt(key->rsa, 0, TRUE, 0, tmp, &clen, *outlen)) { + wpa_printf(MSG_DEBUG, "CryptoAPI: Failed to encrypt using " + "public key: %d", (int) GetLastError()); + os_free(tmp); + return -1; + } + + *outlen = clen; + + /* Reverse the output */ + for (i = 0; i < *outlen; i++) + out[i] = tmp[*outlen - 1 - i]; + + os_free(tmp); + + return 0; +} + + +int crypto_private_key_sign_pkcs1(struct crypto_private_key *key, + const u8 *in, size_t inlen, + u8 *out, size_t *outlen) +{ + /* TODO */ + return -1; +} + + +void crypto_public_key_free(struct crypto_public_key *key) +{ + if (key) { + CryptDestroyKey(key->rsa); + CryptReleaseContext(key->prov, 0); + os_free(key); + } +} + + +void crypto_private_key_free(struct crypto_private_key *key) +{ + if (key) { + CryptDestroyKey(key->rsa); + CryptReleaseContext(key->prov, 0); + os_free(key); + } +} + + +int crypto_global_init(void) +{ + return mingw_load_crypto_func(); +} + + +void crypto_global_deinit(void) +{ +} + +#endif /* CONFIG_TLS_INTERNAL */ + +#endif /* EAP_TLS_FUNCS */ diff --git a/contrib/wpa_supplicant/crypto_gnutls.c b/contrib/wpa_supplicant/crypto_gnutls.c index 15f9b54ae804..4bf75f132a00 100644 --- a/contrib/wpa_supplicant/crypto_gnutls.c +++ b/contrib/wpa_supplicant/crypto_gnutls.c @@ -1,6 +1,6 @@ /* * WPA Supplicant / wrapper functions for libgcrypt - * Copyright (c) 2004-2005, Jouni Malinen <jkmaline@cc.hut.fi> + * Copyright (c) 2004-2005, Jouni Malinen <j@w1.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 @@ -12,8 +12,7 @@ * See README and COPYING for more details. */ -#include <stdio.h> -#include <sys/types.h> +#include "includes.h" #include <gcrypt.h> #include "common.h" @@ -23,7 +22,7 @@ void md4_vector(size_t num_elem, const u8 *addr[], const size_t *len, u8 *mac) { gcry_md_hd_t hd; unsigned char *p; - int i; + size_t i; if (gcry_md_open(&hd, GCRY_MD_MD4, 0) != GPG_ERR_NO_ERROR) return; @@ -63,7 +62,7 @@ void md5_vector(size_t num_elem, const u8 *addr[], const size_t *len, u8 *mac) { gcry_md_hd_t hd; unsigned char *p; - int i; + size_t i; if (gcry_md_open(&hd, GCRY_MD_MD5, 0) != GPG_ERR_NO_ERROR) return; @@ -80,7 +79,7 @@ void sha1_vector(size_t num_elem, const u8 *addr[], const size_t *len, u8 *mac) { gcry_md_hd_t hd; unsigned char *p; - int i; + size_t i; if (gcry_md_open(&hd, GCRY_MD_SHA1, 0) != GPG_ERR_NO_ERROR) return; @@ -93,9 +92,10 @@ void sha1_vector(size_t num_elem, const u8 *addr[], const size_t *len, u8 *mac) } -void sha1_transform(u8 *state, const u8 data[64]) +int fips186_2_prf(const u8 *seed, size_t seed_len, u8 *x, size_t xlen) { /* FIX: how to do this with libgcrypt? */ + return -1; } diff --git a/contrib/wpa_supplicant/crypto_internal.c b/contrib/wpa_supplicant/crypto_internal.c new file mode 100644 index 000000000000..d0c20371a73d --- /dev/null +++ b/contrib/wpa_supplicant/crypto_internal.c @@ -0,0 +1,670 @@ +/* + * WPA Supplicant / Crypto wrapper for internal crypto implementation + * Copyright (c) 2006, Jouni Malinen <j@w1.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 "includes.h" + +#include "common.h" +#include "crypto.h" +#include "md5.h" +#include "sha1.h" +#include "rc4.h" +#include "aes.h" +#include "rsa.h" +#include "bignum.h" + + +#ifdef EAP_TLS_FUNCS + +#ifdef CONFIG_TLS_INTERNAL + +/* from des.c */ +struct des3_key_s { + u32 ek[3][32]; + u32 dk[3][32]; +}; + +void des3_key_setup(const u8 *key, struct des3_key_s *dkey); +void des3_encrypt(const u8 *plain, const struct des3_key_s *key, u8 *crypt); +void des3_decrypt(const u8 *crypt, const struct des3_key_s *key, u8 *plain); + + +struct MD5Context { + u32 buf[4]; + u32 bits[2]; + u8 in[64]; +}; + +struct SHA1Context { + u32 state[5]; + u32 count[2]; + unsigned char buffer[64]; +}; + + +struct crypto_hash { + enum crypto_hash_alg alg; + union { + struct MD5Context md5; + struct SHA1Context sha1; + } u; + u8 key[64]; + size_t key_len; +}; + + +struct crypto_hash * crypto_hash_init(enum crypto_hash_alg alg, const u8 *key, + size_t key_len) +{ + struct crypto_hash *ctx; + u8 k_pad[64]; + u8 tk[20]; + size_t i; + + ctx = os_zalloc(sizeof(*ctx)); + if (ctx == NULL) + return NULL; + + ctx->alg = alg; + + switch (alg) { + case CRYPTO_HASH_ALG_MD5: + MD5Init(&ctx->u.md5); + break; + case CRYPTO_HASH_ALG_SHA1: + SHA1Init(&ctx->u.sha1); + break; + case CRYPTO_HASH_ALG_HMAC_MD5: + if (key_len > sizeof(k_pad)) { + MD5Init(&ctx->u.md5); + MD5Update(&ctx->u.md5, key, key_len); + MD5Final(tk, &ctx->u.md5); + key = tk; + key_len = 16; + } + os_memcpy(ctx->key, key, key_len); + ctx->key_len = key_len; + + os_memcpy(k_pad, key, key_len); + os_memset(k_pad + key_len, 0, sizeof(k_pad) - key_len); + for (i = 0; i < sizeof(k_pad); i++) + k_pad[i] ^= 0x36; + MD5Init(&ctx->u.md5); + MD5Update(&ctx->u.md5, k_pad, sizeof(k_pad)); + break; + case CRYPTO_HASH_ALG_HMAC_SHA1: + if (key_len > sizeof(k_pad)) { + SHA1Init(&ctx->u.sha1); + SHA1Update(&ctx->u.sha1, key, key_len); + SHA1Final(tk, &ctx->u.sha1); + key = tk; + key_len = 20; + } + os_memcpy(ctx->key, key, key_len); + ctx->key_len = key_len; + + os_memcpy(k_pad, key, key_len); + os_memset(k_pad + key_len, 0, sizeof(k_pad) - key_len); + for (i = 0; i < sizeof(k_pad); i++) + k_pad[i] ^= 0x36; + SHA1Init(&ctx->u.sha1); + SHA1Update(&ctx->u.sha1, k_pad, sizeof(k_pad)); + break; + default: + os_free(ctx); + return NULL; + } + + return ctx; +} + + +void crypto_hash_update(struct crypto_hash *ctx, const u8 *data, size_t len) +{ + if (ctx == NULL) + return; + + switch (ctx->alg) { + case CRYPTO_HASH_ALG_MD5: + case CRYPTO_HASH_ALG_HMAC_MD5: + MD5Update(&ctx->u.md5, data, len); + break; + case CRYPTO_HASH_ALG_SHA1: + case CRYPTO_HASH_ALG_HMAC_SHA1: + SHA1Update(&ctx->u.sha1, data, len); + break; + } +} + + +int crypto_hash_finish(struct crypto_hash *ctx, u8 *mac, size_t *len) +{ + u8 k_pad[64]; + size_t i; + + if (ctx == NULL) + return -2; + + if (mac == NULL || len == NULL) { + os_free(ctx); + return 0; + } + + switch (ctx->alg) { + case CRYPTO_HASH_ALG_MD5: + if (*len < 16) { + *len = 16; + os_free(ctx); + return -1; + } + *len = 16; + MD5Final(mac, &ctx->u.md5); + break; + case CRYPTO_HASH_ALG_SHA1: + if (*len < 20) { + *len = 20; + os_free(ctx); + return -1; + } + *len = 20; + SHA1Final(mac, &ctx->u.sha1); + break; + case CRYPTO_HASH_ALG_HMAC_MD5: + if (*len < 16) { + *len = 16; + os_free(ctx); + return -1; + } + *len = 16; + + MD5Final(mac, &ctx->u.md5); + + os_memcpy(k_pad, ctx->key, ctx->key_len); + os_memset(k_pad + ctx->key_len, 0, + sizeof(k_pad) - ctx->key_len); + for (i = 0; i < sizeof(k_pad); i++) + k_pad[i] ^= 0x5c; + MD5Init(&ctx->u.md5); + MD5Update(&ctx->u.md5, k_pad, sizeof(k_pad)); + MD5Update(&ctx->u.md5, mac, 16); + MD5Final(mac, &ctx->u.md5); + break; + case CRYPTO_HASH_ALG_HMAC_SHA1: + if (*len < 20) { + *len = 20; + os_free(ctx); + return -1; + } + *len = 20; + + SHA1Final(mac, &ctx->u.sha1); + + os_memcpy(k_pad, ctx->key, ctx->key_len); + os_memset(k_pad + ctx->key_len, 0, + sizeof(k_pad) - ctx->key_len); + for (i = 0; i < sizeof(k_pad); i++) + k_pad[i] ^= 0x5c; + SHA1Init(&ctx->u.sha1); + SHA1Update(&ctx->u.sha1, k_pad, sizeof(k_pad)); + SHA1Update(&ctx->u.sha1, mac, 20); + SHA1Final(mac, &ctx->u.sha1); + break; + } + + os_free(ctx); + + return 0; +} + + +struct crypto_cipher { + enum crypto_cipher_alg alg; + union { + struct { + size_t used_bytes; + u8 key[16]; + size_t keylen; + } rc4; + struct { + u8 cbc[32]; + size_t block_size; + void *ctx_enc; + void *ctx_dec; + } aes; + struct { + struct des3_key_s key; + u8 cbc[8]; + } des3; + } u; +}; + + +struct crypto_cipher * crypto_cipher_init(enum crypto_cipher_alg alg, + const u8 *iv, const u8 *key, + size_t key_len) +{ + struct crypto_cipher *ctx; + + ctx = os_zalloc(sizeof(*ctx)); + if (ctx == NULL) + return NULL; + + ctx->alg = alg; + + switch (alg) { + case CRYPTO_CIPHER_ALG_RC4: + if (key_len > sizeof(ctx->u.rc4.key)) { + os_free(ctx); + return NULL; + } + ctx->u.rc4.keylen = key_len; + os_memcpy(ctx->u.rc4.key, key, key_len); + break; + case CRYPTO_CIPHER_ALG_AES: + if (key_len > sizeof(ctx->u.aes.cbc)) { + os_free(ctx); + return NULL; + } + ctx->u.aes.ctx_enc = aes_encrypt_init(key, key_len); + if (ctx->u.aes.ctx_enc == NULL) { + os_free(ctx); + return NULL; + } + ctx->u.aes.ctx_dec = aes_decrypt_init(key, key_len); + if (ctx->u.aes.ctx_dec == NULL) { + aes_encrypt_deinit(ctx->u.aes.ctx_enc); + os_free(ctx); + return NULL; + } + ctx->u.aes.block_size = key_len; + os_memcpy(ctx->u.aes.cbc, iv, ctx->u.aes.block_size); + break; + case CRYPTO_CIPHER_ALG_3DES: + if (key_len != 24) { + os_free(ctx); + return NULL; + } + des3_key_setup(key, &ctx->u.des3.key); + os_memcpy(ctx->u.des3.cbc, iv, 8); + break; + default: + os_free(ctx); + return NULL; + } + + return ctx; +} + + +int crypto_cipher_encrypt(struct crypto_cipher *ctx, const u8 *plain, + u8 *crypt, size_t len) +{ + size_t i, j, blocks; + + switch (ctx->alg) { + case CRYPTO_CIPHER_ALG_RC4: + if (plain != crypt) + os_memcpy(crypt, plain, len); + rc4_skip(ctx->u.rc4.key, ctx->u.rc4.keylen, + ctx->u.rc4.used_bytes, crypt, len); + ctx->u.rc4.used_bytes += len; + break; + case CRYPTO_CIPHER_ALG_AES: + if (len % ctx->u.aes.block_size) + return -1; + blocks = len / ctx->u.aes.block_size; + for (i = 0; i < blocks; i++) { + for (j = 0; j < ctx->u.aes.block_size; j++) + ctx->u.aes.cbc[j] ^= plain[j]; + aes_encrypt(ctx->u.aes.ctx_enc, ctx->u.aes.cbc, + ctx->u.aes.cbc); + os_memcpy(crypt, ctx->u.aes.cbc, + ctx->u.aes.block_size); + plain += ctx->u.aes.block_size; + crypt += ctx->u.aes.block_size; + } + break; + case CRYPTO_CIPHER_ALG_3DES: + if (len % 8) + return -1; + blocks = len / 8; + for (i = 0; i < blocks; i++) { + for (j = 0; j < 8; j++) + ctx->u.des3.cbc[j] ^= plain[j]; + des3_encrypt(ctx->u.des3.cbc, &ctx->u.des3.key, + ctx->u.des3.cbc); + os_memcpy(crypt, ctx->u.des3.cbc, 8); + plain += 8; + crypt += 8; + } + break; + default: + return -1; + } + + return 0; +} + + +int crypto_cipher_decrypt(struct crypto_cipher *ctx, const u8 *crypt, + u8 *plain, size_t len) +{ + size_t i, j, blocks; + u8 tmp[32]; + + switch (ctx->alg) { + case CRYPTO_CIPHER_ALG_RC4: + if (plain != crypt) + os_memcpy(plain, crypt, len); + rc4_skip(ctx->u.rc4.key, ctx->u.rc4.keylen, + ctx->u.rc4.used_bytes, plain, len); + ctx->u.rc4.used_bytes += len; + break; + case CRYPTO_CIPHER_ALG_AES: + if (len % ctx->u.aes.block_size) + return -1; + blocks = len / ctx->u.aes.block_size; + for (i = 0; i < blocks; i++) { + os_memcpy(tmp, crypt, ctx->u.aes.block_size); + aes_decrypt(ctx->u.aes.ctx_dec, crypt, plain); + for (j = 0; j < ctx->u.aes.block_size; j++) + plain[j] ^= ctx->u.aes.cbc[j]; + os_memcpy(ctx->u.aes.cbc, tmp, ctx->u.aes.block_size); + plain += ctx->u.aes.block_size; + crypt += ctx->u.aes.block_size; + } + break; + case CRYPTO_CIPHER_ALG_3DES: + if (len % 8) + return -1; + blocks = len / 8; + for (i = 0; i < blocks; i++) { + os_memcpy(tmp, crypt, 8); + des3_decrypt(crypt, &ctx->u.des3.key, plain); + for (j = 0; j < 8; j++) + plain[j] ^= ctx->u.des3.cbc[j]; + os_memcpy(ctx->u.des3.cbc, tmp, 8); + plain += 8; + crypt += 8; + } + break; + default: + return -1; + } + + return 0; +} + + +void crypto_cipher_deinit(struct crypto_cipher *ctx) +{ + switch (ctx->alg) { + case CRYPTO_CIPHER_ALG_AES: + aes_encrypt_deinit(ctx->u.aes.ctx_enc); + aes_decrypt_deinit(ctx->u.aes.ctx_dec); + break; + case CRYPTO_CIPHER_ALG_3DES: + break; + default: + break; + } + os_free(ctx); +} + + +/* Dummy structures; these are just typecast to struct crypto_rsa_key */ +struct crypto_public_key; +struct crypto_private_key; + + +struct crypto_public_key * crypto_public_key_import(const u8 *key, size_t len) +{ + return (struct crypto_public_key *) + crypto_rsa_import_public_key(key, len); +} + + +struct crypto_private_key * crypto_private_key_import(const u8 *key, + size_t len) +{ + return (struct crypto_private_key *) + crypto_rsa_import_private_key(key, len); +} + + +struct crypto_public_key * crypto_public_key_from_cert(const u8 *buf, + size_t len) +{ + /* No X.509 support in crypto_internal.c */ + return NULL; +} + + +static int pkcs1_generate_encryption_block(u8 block_type, size_t modlen, + const u8 *in, size_t inlen, + u8 *out, size_t *outlen) +{ + size_t ps_len; + u8 *pos; + + /* + * PKCS #1 v1.5, 8.1: + * + * EB = 00 || BT || PS || 00 || D + * BT = 00 or 01 for private-key operation; 02 for public-key operation + * PS = k-3-||D||; at least eight octets + * (BT=0: PS=0x00, BT=1: PS=0xff, BT=2: PS=pseudorandom non-zero) + * k = length of modulus in octets (modlen) + */ + + if (modlen < 12 || modlen > *outlen || inlen > modlen - 11) { + wpa_printf(MSG_DEBUG, "PKCS #1: %s - Invalid buffer " + "lengths (modlen=%lu outlen=%lu inlen=%lu)", + __func__, (unsigned long) modlen, + (unsigned long) *outlen, + (unsigned long) inlen); + return -1; + } + + pos = out; + *pos++ = 0x00; + *pos++ = block_type; /* BT */ + ps_len = modlen - inlen - 3; + switch (block_type) { + case 0: + os_memset(pos, 0x00, ps_len); + pos += ps_len; + break; + case 1: + os_memset(pos, 0xff, ps_len); + pos += ps_len; + break; + case 2: + if (os_get_random(pos, ps_len) < 0) { + wpa_printf(MSG_DEBUG, "PKCS #1: %s - Failed to get " + "random data for PS", __func__); + return -1; + } + while (ps_len--) { + if (*pos == 0x00) + *pos = 0x01; + pos++; + } + break; + default: + wpa_printf(MSG_DEBUG, "PKCS #1: %s - Unsupported block type " + "%d", __func__, block_type); + return -1; + } + *pos++ = 0x00; + os_memcpy(pos, in, inlen); /* D */ + + return 0; +} + + +static int crypto_rsa_encrypt_pkcs1(int block_type, struct crypto_rsa_key *key, + int use_private, + const u8 *in, size_t inlen, + u8 *out, size_t *outlen) +{ + size_t modlen; + + modlen = crypto_rsa_get_modulus_len(key); + + if (pkcs1_generate_encryption_block(block_type, modlen, in, inlen, + out, outlen) < 0) + return -1; + + return crypto_rsa_exptmod(out, modlen, out, outlen, key, use_private); +} + + +int crypto_public_key_encrypt_pkcs1_v15(struct crypto_public_key *key, + const u8 *in, size_t inlen, + u8 *out, size_t *outlen) +{ + return crypto_rsa_encrypt_pkcs1(2, (struct crypto_rsa_key *) key, + 0, in, inlen, out, outlen); +} + + +int crypto_private_key_sign_pkcs1(struct crypto_private_key *key, + const u8 *in, size_t inlen, + u8 *out, size_t *outlen) +{ + return crypto_rsa_encrypt_pkcs1(1, (struct crypto_rsa_key *) key, + 1, in, inlen, out, outlen); +} + + +void crypto_public_key_free(struct crypto_public_key *key) +{ + crypto_rsa_free((struct crypto_rsa_key *) key); +} + + +void crypto_private_key_free(struct crypto_private_key *key) +{ + crypto_rsa_free((struct crypto_rsa_key *) key); +} + + +int crypto_public_key_decrypt_pkcs1(struct crypto_public_key *key, + const u8 *crypt, size_t crypt_len, + u8 *plain, size_t *plain_len) +{ + size_t len; + u8 *pos; + + len = *plain_len; + if (crypto_rsa_exptmod(crypt, crypt_len, plain, &len, + (struct crypto_rsa_key *) key, 0) < 0) + return -1; + + /* + * PKCS #1 v1.5, 8.1: + * + * EB = 00 || BT || PS || 00 || D + * BT = 01 + * PS = k-3-||D|| times FF + * k = length of modulus in octets + */ + + if (len < 3 + 8 + 16 /* min hash len */ || + plain[0] != 0x00 || plain[1] != 0x01 || plain[2] != 0xff) { + wpa_printf(MSG_INFO, "LibTomCrypt: Invalid signature EB " + "structure"); + return -1; + } + + pos = plain + 3; + while (pos < plain + len && *pos == 0xff) + pos++; + if (pos - plain - 2 < 8) { + /* PKCS #1 v1.5, 8.1: At least eight octets long PS */ + wpa_printf(MSG_INFO, "LibTomCrypt: Too short signature " + "padding"); + return -1; + } + + if (pos + 16 /* min hash len */ >= plain + len || *pos != 0x00) { + wpa_printf(MSG_INFO, "LibTomCrypt: Invalid signature EB " + "structure (2)"); + return -1; + } + pos++; + len -= pos - plain; + + /* Strip PKCS #1 header */ + os_memmove(plain, pos, len); + *plain_len = len; + + return 0; +} + + +int crypto_global_init(void) +{ + return 0; +} + + +void crypto_global_deinit(void) +{ +} + + +#ifdef EAP_FAST + +int crypto_mod_exp(const u8 *base, size_t base_len, + const u8 *power, size_t power_len, + const u8 *modulus, size_t modulus_len, + u8 *result, size_t *result_len) +{ + struct bignum *bn_base, *bn_exp, *bn_modulus, *bn_result; + int ret = 0; + + bn_base = bignum_init(); + bn_exp = bignum_init(); + bn_modulus = bignum_init(); + bn_result = bignum_init(); + + if (bn_base == NULL || bn_exp == NULL || bn_modulus == NULL || + bn_result == NULL) + goto error; + + if (bignum_set_unsigned_bin(bn_base, base, base_len) < 0 || + bignum_set_unsigned_bin(bn_exp, power, power_len) < 0 || + bignum_set_unsigned_bin(bn_modulus, modulus, modulus_len) < 0) + goto error; + + if (bignum_exptmod(bn_base, bn_exp, bn_modulus, bn_result) < 0) + goto error; + + ret = bignum_get_unsigned_bin(bn_result, result, result_len); + +error: + bignum_deinit(bn_base); + bignum_deinit(bn_exp); + bignum_deinit(bn_modulus); + bignum_deinit(bn_result); + return ret; +} + +#endif /* EAP_FAST */ + + +#endif /* CONFIG_TLS_INTERNAL */ + +#endif /* EAP_TLS_FUNCS */ diff --git a/contrib/wpa_supplicant/crypto_libtomcrypt.c b/contrib/wpa_supplicant/crypto_libtomcrypt.c new file mode 100644 index 000000000000..e82097f10a00 --- /dev/null +++ b/contrib/wpa_supplicant/crypto_libtomcrypt.c @@ -0,0 +1,736 @@ +/* + * WPA Supplicant / Crypto wrapper for LibTomCrypt (for internal TLSv1) + * Copyright (c) 2005-2006, Jouni Malinen <j@w1.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 "includes.h" +#include <tomcrypt.h> + +#include "common.h" +#include "rc4.h" +#include "crypto.h" + +#ifndef mp_init_multi +#define mp_init_multi ltc_init_multi +#define mp_clear_multi ltc_deinit_multi +#define mp_unsigned_bin_size(a) ltc_mp.unsigned_size(a) +#define mp_to_unsigned_bin(a, b) ltc_mp.unsigned_write(a, b) +#define mp_read_unsigned_bin(a, b, c) ltc_mp.unsigned_read(a, b, c) +#define mp_exptmod(a,b,c,d) ltc_mp.exptmod(a,b,c,d) +#endif + + +void md4_vector(size_t num_elem, const u8 *addr[], const size_t *len, u8 *mac) +{ + hash_state md; + size_t i; + + md4_init(&md); + for (i = 0; i < num_elem; i++) + md4_process(&md, addr[i], len[i]); + md4_done(&md, mac); +} + + +void des_encrypt(const u8 *clear, const u8 *key, u8 *cypher) +{ + u8 pkey[8], next, tmp; + int i; + symmetric_key skey; + + /* Add parity bits to the key */ + next = 0; + for (i = 0; i < 7; i++) { + tmp = key[i]; + pkey[i] = (tmp >> i) | next | 1; + next = tmp << (7 - i); + } + pkey[i] = next | 1; + + des_setup(pkey, 8, 0, &skey); + des_ecb_encrypt(clear, cypher, &skey); + des_done(&skey); +} + + +#ifdef EAP_TLS_FUNCS +void md5_vector(size_t num_elem, const u8 *addr[], const size_t *len, u8 *mac) +{ + hash_state md; + size_t i; + + md5_init(&md); + for (i = 0; i < num_elem; i++) + md5_process(&md, addr[i], len[i]); + md5_done(&md, mac); +} + + +void sha1_vector(size_t num_elem, const u8 *addr[], const size_t *len, u8 *mac) +{ + hash_state md; + size_t i; + + sha1_init(&md); + for (i = 0; i < num_elem; i++) + sha1_process(&md, addr[i], len[i]); + sha1_done(&md, mac); +} + + +void * aes_encrypt_init(const u8 *key, size_t len) +{ + symmetric_key *skey; + skey = os_malloc(sizeof(*skey)); + if (skey == NULL) + return NULL; + if (aes_setup(key, len, 0, skey) != CRYPT_OK) { + os_free(skey); + return NULL; + } + return skey; +} + + +void aes_encrypt(void *ctx, const u8 *plain, u8 *crypt) +{ + symmetric_key *skey = ctx; + aes_ecb_encrypt(plain, crypt, skey); +} + + +void aes_encrypt_deinit(void *ctx) +{ + symmetric_key *skey = ctx; + aes_done(skey); + os_free(skey); +} + + +void * aes_decrypt_init(const u8 *key, size_t len) +{ + symmetric_key *skey; + skey = os_malloc(sizeof(*skey)); + if (skey == NULL) + return NULL; + if (aes_setup(key, len, 0, skey) != CRYPT_OK) { + os_free(skey); + return NULL; + } + return skey; +} + + +void aes_decrypt(void *ctx, const u8 *crypt, u8 *plain) +{ + symmetric_key *skey = ctx; + aes_ecb_encrypt(plain, (u8 *) crypt, skey); +} + + +void aes_decrypt_deinit(void *ctx) +{ + symmetric_key *skey = ctx; + aes_done(skey); + os_free(skey); +} + + +#ifdef CONFIG_TLS_INTERNAL + +struct crypto_hash { + enum crypto_hash_alg alg; + int error; + union { + hash_state md; + hmac_state hmac; + } u; +}; + + +struct crypto_hash * crypto_hash_init(enum crypto_hash_alg alg, const u8 *key, + size_t key_len) +{ + struct crypto_hash *ctx; + + ctx = os_zalloc(sizeof(*ctx)); + if (ctx == NULL) + return NULL; + + ctx->alg = alg; + + switch (alg) { + case CRYPTO_HASH_ALG_MD5: + if (md5_init(&ctx->u.md) != CRYPT_OK) + goto fail; + break; + case CRYPTO_HASH_ALG_SHA1: + if (sha1_init(&ctx->u.md) != CRYPT_OK) + goto fail; + break; + case CRYPTO_HASH_ALG_HMAC_MD5: + if (hmac_init(&ctx->u.hmac, find_hash("md5"), key, key_len) != + CRYPT_OK) + goto fail; + break; + case CRYPTO_HASH_ALG_HMAC_SHA1: + if (hmac_init(&ctx->u.hmac, find_hash("sha1"), key, key_len) != + CRYPT_OK) + goto fail; + break; + default: + goto fail; + } + + return ctx; + +fail: + os_free(ctx); + return NULL; +} + +void crypto_hash_update(struct crypto_hash *ctx, const u8 *data, size_t len) +{ + if (ctx == NULL || ctx->error) + return; + + switch (ctx->alg) { + case CRYPTO_HASH_ALG_MD5: + ctx->error = md5_process(&ctx->u.md, data, len) != CRYPT_OK; + break; + case CRYPTO_HASH_ALG_SHA1: + ctx->error = sha1_process(&ctx->u.md, data, len) != CRYPT_OK; + break; + case CRYPTO_HASH_ALG_HMAC_MD5: + case CRYPTO_HASH_ALG_HMAC_SHA1: + ctx->error = hmac_process(&ctx->u.hmac, data, len) != CRYPT_OK; + break; + } +} + + +int crypto_hash_finish(struct crypto_hash *ctx, u8 *mac, size_t *len) +{ + int ret = 0; + unsigned long clen; + + if (ctx == NULL) + return -2; + + if (mac == NULL || len == NULL) { + os_free(ctx); + return 0; + } + + if (ctx->error) { + os_free(ctx); + return -2; + } + + switch (ctx->alg) { + case CRYPTO_HASH_ALG_MD5: + if (*len < 16) { + *len = 16; + os_free(ctx); + return -1; + } + *len = 16; + if (md5_done(&ctx->u.md, mac) != CRYPT_OK) + ret = -2; + break; + case CRYPTO_HASH_ALG_SHA1: + if (*len < 20) { + *len = 20; + os_free(ctx); + return -1; + } + *len = 20; + if (sha1_done(&ctx->u.md, mac) != CRYPT_OK) + ret = -2; + break; + case CRYPTO_HASH_ALG_HMAC_SHA1: + if (*len < 20) { + *len = 20; + os_free(ctx); + return -1; + } + /* continue */ + case CRYPTO_HASH_ALG_HMAC_MD5: + if (*len < 16) { + *len = 16; + os_free(ctx); + return -1; + } + clen = *len; + if (hmac_done(&ctx->u.hmac, mac, &clen) != CRYPT_OK) { + os_free(ctx); + return -1; + } + *len = clen; + break; + default: + ret = -2; + break; + } + + os_free(ctx); + + return ret; +} + + +struct crypto_cipher { + int rc4; + union { + symmetric_CBC cbc; + struct { + size_t used_bytes; + u8 key[16]; + size_t keylen; + } rc4; + } u; +}; + + +struct crypto_cipher * crypto_cipher_init(enum crypto_cipher_alg alg, + const u8 *iv, const u8 *key, + size_t key_len) +{ + struct crypto_cipher *ctx; + int idx, res, rc4 = 0; + + switch (alg) { + case CRYPTO_CIPHER_ALG_AES: + idx = find_cipher("aes"); + break; + case CRYPTO_CIPHER_ALG_3DES: + idx = find_cipher("3des"); + break; + case CRYPTO_CIPHER_ALG_DES: + idx = find_cipher("des"); + break; + case CRYPTO_CIPHER_ALG_RC2: + idx = find_cipher("rc2"); + break; + case CRYPTO_CIPHER_ALG_RC4: + idx = -1; + rc4 = 1; + break; + default: + return NULL; + } + + ctx = os_zalloc(sizeof(*ctx)); + if (ctx == NULL) + return NULL; + + if (rc4) { + ctx->rc4 = 1; + if (key_len > sizeof(ctx->u.rc4.key)) { + os_free(ctx); + return NULL; + } + ctx->u.rc4.keylen = key_len; + os_memcpy(ctx->u.rc4.key, key, key_len); + } else { + res = cbc_start(idx, iv, key, key_len, 0, &ctx->u.cbc); + if (res != CRYPT_OK) { + wpa_printf(MSG_DEBUG, "LibTomCrypt: Cipher start " + "failed: %s", error_to_string(res)); + os_free(ctx); + return NULL; + } + } + + return ctx; +} + +int crypto_cipher_encrypt(struct crypto_cipher *ctx, const u8 *plain, + u8 *crypt, size_t len) +{ + int res; + + if (ctx->rc4) { + if (plain != crypt) + os_memcpy(crypt, plain, len); + rc4_skip(ctx->u.rc4.key, ctx->u.rc4.keylen, + ctx->u.rc4.used_bytes, crypt, len); + ctx->u.rc4.used_bytes += len; + return 0; + } + + res = cbc_encrypt(plain, crypt, len, &ctx->u.cbc); + if (res != CRYPT_OK) { + wpa_printf(MSG_DEBUG, "LibTomCrypt: CBC encryption " + "failed: %s", error_to_string(res)); + return -1; + } + return 0; +} + + +int crypto_cipher_decrypt(struct crypto_cipher *ctx, const u8 *crypt, + u8 *plain, size_t len) +{ + int res; + + if (ctx->rc4) { + if (plain != crypt) + os_memcpy(plain, crypt, len); + rc4_skip(ctx->u.rc4.key, ctx->u.rc4.keylen, + ctx->u.rc4.used_bytes, plain, len); + ctx->u.rc4.used_bytes += len; + return 0; + } + + res = cbc_decrypt(crypt, plain, len, &ctx->u.cbc); + if (res != CRYPT_OK) { + wpa_printf(MSG_DEBUG, "LibTomCrypt: CBC decryption " + "failed: %s", error_to_string(res)); + return -1; + } + + return 0; +} + + +void crypto_cipher_deinit(struct crypto_cipher *ctx) +{ + if (!ctx->rc4) + cbc_done(&ctx->u.cbc); + os_free(ctx); +} + + +struct crypto_public_key { + rsa_key rsa; +}; + +struct crypto_private_key { + rsa_key rsa; +}; + + +struct crypto_public_key * crypto_public_key_import(const u8 *key, size_t len) +{ + int res; + struct crypto_public_key *pk; + + pk = os_zalloc(sizeof(*pk)); + if (pk == NULL) + return NULL; + + res = rsa_import(key, len, &pk->rsa); + if (res != CRYPT_OK) { + wpa_printf(MSG_ERROR, "LibTomCrypt: Failed to import " + "public key (res=%d '%s')", + res, error_to_string(res)); + os_free(pk); + return NULL; + } + + if (pk->rsa.type != PK_PUBLIC) { + wpa_printf(MSG_ERROR, "LibTomCrypt: Public key was not of " + "correct type"); + rsa_free(&pk->rsa); + os_free(pk); + return NULL; + } + + return pk; +} + + +struct crypto_private_key * crypto_private_key_import(const u8 *key, + size_t len) +{ + int res; + struct crypto_private_key *pk; + + pk = os_zalloc(sizeof(*pk)); + if (pk == NULL) + return NULL; + + res = rsa_import(key, len, &pk->rsa); + if (res != CRYPT_OK) { + wpa_printf(MSG_ERROR, "LibTomCrypt: Failed to import " + "private key (res=%d '%s')", + res, error_to_string(res)); + os_free(pk); + return NULL; + } + + if (pk->rsa.type != PK_PRIVATE) { + wpa_printf(MSG_ERROR, "LibTomCrypt: Private key was not of " + "correct type"); + rsa_free(&pk->rsa); + os_free(pk); + return NULL; + } + + return pk; +} + + +struct crypto_public_key * crypto_public_key_from_cert(const u8 *buf, + size_t len) +{ + /* No X.509 support in LibTomCrypt */ + return NULL; +} + + +static int pkcs1_generate_encryption_block(u8 block_type, size_t modlen, + const u8 *in, size_t inlen, + u8 *out, size_t *outlen) +{ + size_t ps_len; + u8 *pos; + + /* + * PKCS #1 v1.5, 8.1: + * + * EB = 00 || BT || PS || 00 || D + * BT = 00 or 01 for private-key operation; 02 for public-key operation + * PS = k-3-||D||; at least eight octets + * (BT=0: PS=0x00, BT=1: PS=0xff, BT=2: PS=pseudorandom non-zero) + * k = length of modulus in octets (modlen) + */ + + if (modlen < 12 || modlen > *outlen || inlen > modlen - 11) { + wpa_printf(MSG_DEBUG, "PKCS #1: %s - Invalid buffer " + "lengths (modlen=%lu outlen=%lu inlen=%lu)", + __func__, (unsigned long) modlen, + (unsigned long) *outlen, + (unsigned long) inlen); + return -1; + } + + pos = out; + *pos++ = 0x00; + *pos++ = block_type; /* BT */ + ps_len = modlen - inlen - 3; + switch (block_type) { + case 0: + os_memset(pos, 0x00, ps_len); + pos += ps_len; + break; + case 1: + os_memset(pos, 0xff, ps_len); + pos += ps_len; + break; + case 2: + if (os_get_random(pos, ps_len) < 0) { + wpa_printf(MSG_DEBUG, "PKCS #1: %s - Failed to get " + "random data for PS", __func__); + return -1; + } + while (ps_len--) { + if (*pos == 0x00) + *pos = 0x01; + pos++; + } + break; + default: + wpa_printf(MSG_DEBUG, "PKCS #1: %s - Unsupported block type " + "%d", __func__, block_type); + return -1; + } + *pos++ = 0x00; + os_memcpy(pos, in, inlen); /* D */ + + return 0; +} + + +static int crypto_rsa_encrypt_pkcs1(int block_type, rsa_key *key, int key_type, + const u8 *in, size_t inlen, + u8 *out, size_t *outlen) +{ + unsigned long len, modlen; + int res; + + modlen = mp_unsigned_bin_size(key->N); + + if (pkcs1_generate_encryption_block(block_type, modlen, in, inlen, + out, outlen) < 0) + return -1; + + len = *outlen; + res = rsa_exptmod(out, modlen, out, &len, key_type, key); + if (res != CRYPT_OK) { + wpa_printf(MSG_DEBUG, "LibTomCrypt: rsa_exptmod failed: %s", + error_to_string(res)); + return -1; + } + *outlen = len; + + return 0; +} + + +int crypto_public_key_encrypt_pkcs1_v15(struct crypto_public_key *key, + const u8 *in, size_t inlen, + u8 *out, size_t *outlen) +{ + return crypto_rsa_encrypt_pkcs1(2, &key->rsa, PK_PUBLIC, in, inlen, + out, outlen); +} + + +int crypto_private_key_sign_pkcs1(struct crypto_private_key *key, + const u8 *in, size_t inlen, + u8 *out, size_t *outlen) +{ + return crypto_rsa_encrypt_pkcs1(1, &key->rsa, PK_PRIVATE, in, inlen, + out, outlen); +} + + +void crypto_public_key_free(struct crypto_public_key *key) +{ + if (key) { + rsa_free(&key->rsa); + os_free(key); + } +} + + +void crypto_private_key_free(struct crypto_private_key *key) +{ + if (key) { + rsa_free(&key->rsa); + os_free(key); + } +} + + +int crypto_public_key_decrypt_pkcs1(struct crypto_public_key *key, + const u8 *crypt, size_t crypt_len, + u8 *plain, size_t *plain_len) +{ + int res; + unsigned long len; + u8 *pos; + + len = *plain_len; + res = rsa_exptmod(crypt, crypt_len, plain, &len, PK_PUBLIC, + &key->rsa); + if (res != CRYPT_OK) { + wpa_printf(MSG_DEBUG, "LibTomCrypt: rsa_exptmod failed: %s", + error_to_string(res)); + return -1; + } + + /* + * PKCS #1 v1.5, 8.1: + * + * EB = 00 || BT || PS || 00 || D + * BT = 01 + * PS = k-3-||D|| times FF + * k = length of modulus in octets + */ + + if (len < 3 + 8 + 16 /* min hash len */ || + plain[0] != 0x00 || plain[1] != 0x01 || plain[2] != 0xff) { + wpa_printf(MSG_INFO, "LibTomCrypt: Invalid signature EB " + "structure"); + return -1; + } + + pos = plain + 3; + while (pos < plain + len && *pos == 0xff) + pos++; + if (pos - plain - 2 < 8) { + /* PKCS #1 v1.5, 8.1: At least eight octets long PS */ + wpa_printf(MSG_INFO, "LibTomCrypt: Too short signature " + "padding"); + return -1; + } + + if (pos + 16 /* min hash len */ >= plain + len || *pos != 0x00) { + wpa_printf(MSG_INFO, "LibTomCrypt: Invalid signature EB " + "structure (2)"); + return -1; + } + pos++; + len -= pos - plain; + + /* Strip PKCS #1 header */ + os_memmove(plain, pos, len); + *plain_len = len; + + return 0; +} + + +int crypto_global_init(void) +{ + ltc_mp = tfm_desc; + /* TODO: only register algorithms that are really needed */ + if (register_hash(&md4_desc) < 0 || + register_hash(&md5_desc) < 0 || + register_hash(&sha1_desc) < 0 || + register_cipher(&aes_desc) < 0 || + register_cipher(&des_desc) < 0 || + register_cipher(&des3_desc) < 0) { + wpa_printf(MSG_ERROR, "TLSv1: Failed to register " + "hash/cipher functions"); + return -1; + } + + return 0; +} + + +void crypto_global_deinit(void) +{ +} + + +#ifdef EAP_FAST + +int crypto_mod_exp(const u8 *base, size_t base_len, + const u8 *power, size_t power_len, + const u8 *modulus, size_t modulus_len, + u8 *result, size_t *result_len) +{ + void *b, *p, *m, *r; + + if (mp_init_multi(&b, &p, &m, &r, NULL) != CRYPT_OK) + return -1; + + if (mp_read_unsigned_bin(b, (u8 *) base, base_len) != CRYPT_OK || + mp_read_unsigned_bin(p, (u8 *) power, power_len) != CRYPT_OK || + mp_read_unsigned_bin(m, (u8 *) modulus, modulus_len) != CRYPT_OK) + goto fail; + + if (mp_exptmod(b, p, m, r) != CRYPT_OK) + goto fail; + + *result_len = mp_unsigned_bin_size(r); + if (mp_to_unsigned_bin(r, result) != CRYPT_OK) + goto fail; + + mp_clear_multi(b, p, m, r, NULL); + return 0; + +fail: + mp_clear_multi(b, p, m, r, NULL); + return -1; +} + +#endif /* EAP_FAST */ + +#endif /* CONFIG_TLS_INTERNAL */ + +#endif /* EAP_TLS_FUNCS */ diff --git a/contrib/wpa_supplicant/crypto_none.c b/contrib/wpa_supplicant/crypto_none.c new file mode 100644 index 000000000000..f18c2a8ded95 --- /dev/null +++ b/contrib/wpa_supplicant/crypto_none.c @@ -0,0 +1,28 @@ +/* + * WPA Supplicant / Empty template functions for crypto wrapper + * Copyright (c) 2005, Jouni Malinen <j@w1.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 "includes.h" + +#include "common.h" +#include "crypto.h" + + +void md4_vector(size_t num_elem, const u8 *addr[], const size_t *len, u8 *mac) +{ +} + + +void des_encrypt(const u8 *clear, const u8 *key, u8 *cypher) +{ +} diff --git a/contrib/wpa_supplicant/ctrl_iface.c b/contrib/wpa_supplicant/ctrl_iface.c index 01ea456af134..c864c91c5e03 100644 --- a/contrib/wpa_supplicant/ctrl_iface.c +++ b/contrib/wpa_supplicant/ctrl_iface.c @@ -1,6 +1,6 @@ /* - * WPA Supplicant / UNIX domain and UDP socket -based control interface - * Copyright (c) 2004-2005, Jouni Malinen <jkmaline@cc.hut.fi> + * WPA Supplicant / Control interface (shared code for all backends) + * Copyright (c) 2004-2006, Jouni Malinen <j@w1.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 @@ -12,20 +12,7 @@ * See README and COPYING for more details. */ -#include <stdlib.h> -#include <stdio.h> -#include <string.h> -#include <unistd.h> -#include <sys/types.h> -#include <sys/stat.h> -#include <errno.h> -#ifndef CONFIG_NATIVE_WINDOWS -#include <sys/socket.h> -#include <netinet/in.h> -#include <arpa/inet.h> -#include <sys/un.h> -#include <sys/uio.h> -#endif /* CONFIG_NATIVE_WINDOWS */ +#include "includes.h" #include "common.h" #include "eloop.h" @@ -37,31 +24,13 @@ #include "ctrl_iface.h" #include "l2_packet.h" #include "preauth.h" +#include "pmksa_cache.h" #include "wpa_ctrl.h" #include "eap.h" -#ifdef CONFIG_CTRL_IFACE_UDP -#define CTRL_IFACE_SOCK struct sockaddr_in -#else /* CONFIG_CTRL_IFACE_UDP */ -#define CTRL_IFACE_SOCK struct sockaddr_un -#endif /* CONFIG_CTRL_IFACE_UDP */ - - -/** - * struct wpa_ctrl_dst - Internal data structure of control interface monitors - * - * This structure is used to store information about registered control - * interface monitors into struct wpa_supplicant. This data is private to - * ctrl_iface.c and should not be touched directly from other files. - */ -struct wpa_ctrl_dst { - struct wpa_ctrl_dst *next; - CTRL_IFACE_SOCK addr; - socklen_t addrlen; - int debug_level; - int errors; -}; +static int wpa_supplicant_global_iface_interfaces(struct wpa_global *global, + char *buf, int len); static int wpa_supplicant_ctrl_iface_set(struct wpa_supplicant *wpa_s, @@ -70,33 +39,34 @@ static int wpa_supplicant_ctrl_iface_set(struct wpa_supplicant *wpa_s, char *value; int ret = 0; - value = strchr(cmd, ' '); + value = os_strchr(cmd, ' '); if (value == NULL) return -1; *value++ = '\0'; wpa_printf(MSG_DEBUG, "CTRL_IFACE SET '%s'='%s'", cmd, value); - if (strcasecmp(cmd, "EAPOL::heldPeriod") == 0) { + if (os_strcasecmp(cmd, "EAPOL::heldPeriod") == 0) { eapol_sm_configure(wpa_s->eapol, atoi(value), -1, -1, -1); - } else if (strcasecmp(cmd, "EAPOL::authPeriod") == 0) { + } else if (os_strcasecmp(cmd, "EAPOL::authPeriod") == 0) { eapol_sm_configure(wpa_s->eapol, -1, atoi(value), -1, -1); - } else if (strcasecmp(cmd, "EAPOL::startPeriod") == 0) { + } else if (os_strcasecmp(cmd, "EAPOL::startPeriod") == 0) { eapol_sm_configure(wpa_s->eapol, -1, -1, atoi(value), -1); - } else if (strcasecmp(cmd, "EAPOL::maxStart") == 0) { + } else if (os_strcasecmp(cmd, "EAPOL::maxStart") == 0) { eapol_sm_configure(wpa_s->eapol, -1, -1, -1, atoi(value)); - } else if (strcasecmp(cmd, "dot11RSNAConfigPMKLifetime") == 0) { + } else if (os_strcasecmp(cmd, "dot11RSNAConfigPMKLifetime") == 0) { if (wpa_sm_set_param(wpa_s->wpa, RSNA_PMK_LIFETIME, atoi(value))) ret = -1; - } else if (strcasecmp(cmd, "dot11RSNAConfigPMKReauthThreshold") == 0) { + } else if (os_strcasecmp(cmd, "dot11RSNAConfigPMKReauthThreshold") == + 0) { if (wpa_sm_set_param(wpa_s->wpa, RSNA_PMK_REAUTH_THRESHOLD, atoi(value))) ret = -1; - } else if (strcasecmp(cmd, "dot11RSNAConfigSATimeout") == 0) { + } else if (os_strcasecmp(cmd, "dot11RSNAConfigSATimeout") == 0) { if (wpa_sm_set_param(wpa_s->wpa, RSNA_SA_TIMEOUT, atoi(value))) ret = -1; } else @@ -126,129 +96,48 @@ static int wpa_supplicant_ctrl_iface_preauth(struct wpa_supplicant *wpa_s, } -static int wpa_supplicant_ctrl_iface_attach(struct wpa_supplicant *wpa_s, - CTRL_IFACE_SOCK *from, - socklen_t fromlen) +#ifdef CONFIG_PEERKEY +/* MLME-STKSTART.request(peer) */ +static int wpa_supplicant_ctrl_iface_stkstart( + struct wpa_supplicant *wpa_s, char *addr) { - struct wpa_ctrl_dst *dst; + u8 peer[ETH_ALEN]; - dst = malloc(sizeof(*dst)); - if (dst == NULL) + if (hwaddr_aton(addr, peer)) { + wpa_printf(MSG_DEBUG, "CTRL_IFACE STKSTART: invalid " + "address '%s'", peer); return -1; - memset(dst, 0, sizeof(*dst)); - memcpy(&dst->addr, from, sizeof(CTRL_IFACE_SOCK)); - dst->addrlen = fromlen; - dst->debug_level = MSG_INFO; - dst->next = wpa_s->ctrl_dst; - wpa_s->ctrl_dst = dst; -#ifdef CONFIG_CTRL_IFACE_UDP - wpa_printf(MSG_DEBUG, "CTRL_IFACE monitor attached %s:%d", - inet_ntoa(from->sin_addr), ntohs(from->sin_port)); -#else /* CONFIG_CTRL_IFACE_UDP */ - wpa_hexdump(MSG_DEBUG, "CTRL_IFACE monitor attached", - (u8 *) from->sun_path, fromlen); -#endif /* CONFIG_CTRL_IFACE_UDP */ - return 0; -} - - -static int wpa_supplicant_ctrl_iface_detach(struct wpa_supplicant *wpa_s, - CTRL_IFACE_SOCK *from, - socklen_t fromlen) -{ - struct wpa_ctrl_dst *dst, *prev = NULL; - - dst = wpa_s->ctrl_dst; - while (dst) { -#ifdef CONFIG_CTRL_IFACE_UDP - if (from->sin_addr.s_addr == dst->addr.sin_addr.s_addr && - from->sin_port == dst->addr.sin_port) { - if (prev == NULL) - wpa_s->ctrl_dst = dst->next; - else - prev->next = dst->next; - free(dst); - wpa_printf(MSG_DEBUG, "CTRL_IFACE monitor detached " - "%s:%d", inet_ntoa(from->sin_addr), - ntohs(from->sin_port)); - return 0; - } -#else /* CONFIG_CTRL_IFACE_UDP */ - if (fromlen == dst->addrlen && - memcmp(from->sun_path, dst->addr.sun_path, fromlen) == 0) { - if (prev == NULL) - wpa_s->ctrl_dst = dst->next; - else - prev->next = dst->next; - free(dst); - wpa_hexdump(MSG_DEBUG, "CTRL_IFACE monitor detached", - (u8 *) from->sun_path, fromlen); - return 0; - } -#endif /* CONFIG_CTRL_IFACE_UDP */ - prev = dst; - dst = dst->next; } - return -1; -} + wpa_printf(MSG_DEBUG, "CTRL_IFACE STKSTART " MACSTR, + MAC2STR(peer)); -static int wpa_supplicant_ctrl_iface_level(struct wpa_supplicant *wpa_s, - CTRL_IFACE_SOCK *from, - socklen_t fromlen, - char *level) -{ - struct wpa_ctrl_dst *dst; - - wpa_printf(MSG_DEBUG, "CTRL_IFACE LEVEL %s", level); - - dst = wpa_s->ctrl_dst; - while (dst) { -#ifdef CONFIG_CTRL_IFACE_UDP - if (from->sin_addr.s_addr == dst->addr.sin_addr.s_addr && - from->sin_port == dst->addr.sin_port) { - wpa_printf(MSG_DEBUG, "CTRL_IFACE changed monitor " - "level %s:%d", inet_ntoa(from->sin_addr), - ntohs(from->sin_port)); - dst->debug_level = atoi(level); - return 0; - } -#else /* CONFIG_CTRL_IFACE_UDP */ - if (fromlen == dst->addrlen && - memcmp(from->sun_path, dst->addr.sun_path, fromlen) == 0) { - wpa_hexdump(MSG_DEBUG, "CTRL_IFACE changed monitor " - "level", (u8 *) from->sun_path, fromlen); - dst->debug_level = atoi(level); - return 0; - } -#endif /* CONFIG_CTRL_IFACE_UDP */ - dst = dst->next; - } - - return -1; + return wpa_sm_stkstart(wpa_s->wpa, peer); } +#endif /* CONFIG_PEERKEY */ static int wpa_supplicant_ctrl_iface_ctrl_rsp(struct wpa_supplicant *wpa_s, char *rsp) { +#ifdef IEEE8021X_EAPOL char *pos, *id_pos; int id; struct wpa_ssid *ssid; - pos = strchr(rsp, '-'); + pos = os_strchr(rsp, '-'); if (pos == NULL) return -1; *pos++ = '\0'; id_pos = pos; - pos = strchr(pos, ':'); + pos = os_strchr(pos, ':'); if (pos == NULL) return -1; *pos++ = '\0'; id = atoi(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)); + (u8 *) pos, os_strlen(pos)); ssid = wpa_config_get_network(wpa_s->conf, id); if (ssid == NULL) { @@ -257,43 +146,43 @@ static int wpa_supplicant_ctrl_iface_ctrl_rsp(struct wpa_supplicant *wpa_s, return -1; } - if (strcmp(rsp, "IDENTITY") == 0) { - free(ssid->identity); - ssid->identity = (u8 *) strdup(pos); - ssid->identity_len = strlen(pos); + if (os_strcmp(rsp, "IDENTITY") == 0) { + os_free(ssid->identity); + ssid->identity = (u8 *) os_strdup(pos); + ssid->identity_len = os_strlen(pos); ssid->pending_req_identity = 0; if (ssid == wpa_s->current_ssid) wpa_s->reassociate = 1; - } else if (strcmp(rsp, "PASSWORD") == 0) { - free(ssid->password); - ssid->password = (u8 *) strdup(pos); - ssid->password_len = strlen(pos); + } else if (os_strcmp(rsp, "PASSWORD") == 0) { + os_free(ssid->password); + ssid->password = (u8 *) os_strdup(pos); + ssid->password_len = os_strlen(pos); ssid->pending_req_password = 0; if (ssid == wpa_s->current_ssid) wpa_s->reassociate = 1; - } else if (strcmp(rsp, "NEW_PASSWORD") == 0) { - free(ssid->new_password); - ssid->new_password = (u8 *) strdup(pos); - ssid->new_password_len = strlen(pos); + } else if (os_strcmp(rsp, "NEW_PASSWORD") == 0) { + os_free(ssid->new_password); + ssid->new_password = (u8 *) os_strdup(pos); + ssid->new_password_len = os_strlen(pos); ssid->pending_req_new_password = 0; if (ssid == wpa_s->current_ssid) wpa_s->reassociate = 1; - } else if (strcmp(rsp, "PIN") == 0) { - free(ssid->pin); - ssid->pin = strdup(pos); + } else if (os_strcmp(rsp, "PIN") == 0) { + os_free(ssid->pin); + ssid->pin = os_strdup(pos); ssid->pending_req_pin = 0; if (ssid == wpa_s->current_ssid) wpa_s->reassociate = 1; - } else if (strcmp(rsp, "OTP") == 0) { - free(ssid->otp); - ssid->otp = (u8 *) strdup(pos); - ssid->otp_len = strlen(pos); - free(ssid->pending_req_otp); + } else if (os_strcmp(rsp, "OTP") == 0) { + os_free(ssid->otp); + ssid->otp = (u8 *) os_strdup(pos); + ssid->otp_len = os_strlen(pos); + os_free(ssid->pending_req_otp); ssid->pending_req_otp = NULL; ssid->pending_req_otp_len = 0; - } else if (strcmp(rsp, "PASSPHRASE") == 0) { - free(ssid->private_key_passwd); - ssid->private_key_passwd = (u8 *) strdup(pos); + } else if (os_strcmp(rsp, "PASSPHRASE") == 0) { + os_free(ssid->private_key_passwd); + ssid->private_key_passwd = (u8 *) os_strdup(pos); ssid->pending_req_passphrase = 0; if (ssid == wpa_s->current_ssid) wpa_s->reassociate = 1; @@ -303,6 +192,10 @@ static int wpa_supplicant_ctrl_iface_ctrl_rsp(struct wpa_supplicant *wpa_s, } return 0; +#else /* IEEE8021X_EAPOL */ + wpa_printf(MSG_DEBUG, "CTRL_IFACE: 802.1X not included"); + return -1; +#endif /* IEEE8021X_EAPOL */ } @@ -311,29 +204,62 @@ static int wpa_supplicant_ctrl_iface_status(struct wpa_supplicant *wpa_s, char *buf, size_t buflen) { char *pos, *end, tmp[30]; - int res, verbose; + int res, verbose, ret; - verbose = strcmp(params, "-VERBOSE") == 0; + verbose = os_strcmp(params, "-VERBOSE") == 0; pos = buf; end = buf + buflen; if (wpa_s->wpa_state >= WPA_ASSOCIATED) { - pos += snprintf(pos, end - pos, "bssid=" MACSTR "\n", - MAC2STR(wpa_s->bssid)); - if (wpa_s->current_ssid) { - pos += snprintf(pos, end - pos, "ssid=%s\n", - wpa_ssid_txt(wpa_s->current_ssid->ssid, - wpa_s->current_ssid-> - ssid_len)); + struct wpa_ssid *ssid = wpa_s->current_ssid; + ret = os_snprintf(pos, end - pos, "bssid=" MACSTR "\n", + MAC2STR(wpa_s->bssid)); + if (ret < 0 || ret >= end - pos) + return pos - buf; + pos += ret; + if (ssid) { + u8 *_ssid = ssid->ssid; + size_t ssid_len = ssid->ssid_len; + u8 ssid_buf[MAX_SSID_LEN]; + if (ssid_len == 0) { + int _res = wpa_drv_get_ssid(wpa_s, ssid_buf); + if (_res < 0) + ssid_len = 0; + else + ssid_len = _res; + _ssid = ssid_buf; + } + ret = os_snprintf(pos, end - pos, "ssid=%s\nid=%d\n", + wpa_ssid_txt(_ssid, ssid_len), + ssid->id); + if (ret < 0 || ret >= end - pos) + return pos - buf; + pos += ret; + + if (ssid->id_str) { + ret = os_snprintf(pos, end - pos, + "id_str=%s\n", + ssid->id_str); + if (ret < 0 || ret >= end - pos) + return pos - buf; + pos += ret; + } } pos += wpa_sm_get_status(wpa_s->wpa, pos, end - pos, verbose); } - pos += snprintf(pos, end - pos, "wpa_state=%s\n", - wpa_supplicant_state_txt(wpa_s->wpa_state)); + ret = os_snprintf(pos, end - pos, "wpa_state=%s\n", + wpa_supplicant_state_txt(wpa_s->wpa_state)); + if (ret < 0 || ret >= end - pos) + return pos - buf; + pos += ret; if (wpa_s->l2 && - l2_packet_get_ip_addr(wpa_s->l2, tmp, sizeof(tmp)) >= 0) - pos += snprintf(pos, end - pos, "ip_address=%s\n", tmp); + l2_packet_get_ip_addr(wpa_s->l2, tmp, sizeof(tmp)) >= 0) { + ret = os_snprintf(pos, end - pos, "ip_address=%s\n", tmp); + if (ret < 0 || ret >= end - pos) + return pos - buf; + pos += ret; + } if (wpa_s->key_mgmt == WPA_KEY_MGMT_IEEE8021X || wpa_s->key_mgmt == WPA_KEY_MGMT_IEEE8021X_NO_WPA) { @@ -360,7 +286,7 @@ static int wpa_supplicant_ctrl_iface_bssid(struct wpa_supplicant *wpa_s, u8 bssid[ETH_ALEN]; /* cmd: "<network id> <BSSID>" */ - pos = strchr(cmd, ' '); + pos = os_strchr(cmd, ' '); if (pos == NULL) return -1; *pos++ = '\0'; @@ -378,9 +304,9 @@ static int wpa_supplicant_ctrl_iface_bssid(struct wpa_supplicant *wpa_s, return -1; } - memcpy(ssid->bssid, bssid, ETH_ALEN); + os_memcpy(ssid->bssid, bssid, ETH_ALEN); ssid->bssid_set = - memcmp(bssid, "\x00\x00\x00\x00\x00\x00", ETH_ALEN) != 0; + os_memcmp(bssid, "\x00\x00\x00\x00\x00\x00", ETH_ALEN) != 0; return 0; @@ -392,26 +318,44 @@ static int wpa_supplicant_ctrl_iface_list_networks( { char *pos, *end; struct wpa_ssid *ssid; + int ret; pos = buf; end = buf + buflen; - pos += snprintf(pos, end - pos, "network id / ssid / bssid / flags\n"); + ret = os_snprintf(pos, end - pos, + "network id / ssid / bssid / flags\n"); + if (ret < 0 || ret >= end - pos) + return pos - buf; + pos += ret; ssid = wpa_s->conf->ssid; while (ssid) { - pos += snprintf(pos, end - pos, "%d\t%s", - ssid->id, - wpa_ssid_txt(ssid->ssid, ssid->ssid_len)); + ret = os_snprintf(pos, end - pos, "%d\t%s", + ssid->id, + wpa_ssid_txt(ssid->ssid, ssid->ssid_len)); + if (ret < 0 || ret >= end - pos) + return pos - buf; + pos += ret; if (ssid->bssid_set) { - pos += snprintf(pos, end - pos, "\t" MACSTR, - MAC2STR(ssid->bssid)); + ret = os_snprintf(pos, end - pos, "\t" MACSTR, + MAC2STR(ssid->bssid)); } else { - pos += snprintf(pos, end - pos, "\tany"); + ret = os_snprintf(pos, end - pos, "\tany"); } - pos += snprintf(pos, end - pos, "\t%s%s", - ssid == wpa_s->current_ssid ? "[CURRENT]" : "", - ssid->disabled ? "[DISABLED]" : ""); - pos += snprintf(pos, end - pos, "\n"); + if (ret < 0 || ret >= end - pos) + return pos - buf; + pos += ret; + ret = os_snprintf(pos, end - pos, "\t%s%s", + ssid == wpa_s->current_ssid ? + "[CURRENT]" : "", + ssid->disabled ? "[DISABLED]" : ""); + if (ret < 0 || ret >= end - pos) + return pos - buf; + pos += ret; + ret = os_snprintf(pos, end - pos, "\n"); + if (ret < 0 || ret >= end - pos) + return pos - buf; + pos += ret; ssid = ssid->next; } @@ -422,66 +366,106 @@ static int wpa_supplicant_ctrl_iface_list_networks( static char * wpa_supplicant_cipher_txt(char *pos, char *end, int cipher) { - int first = 1; - pos += snprintf(pos, end - pos, "-"); + int first = 1, ret; + ret = os_snprintf(pos, end - pos, "-"); + if (ret < 0 || ret >= end - pos) + return pos; + pos += ret; if (cipher & WPA_CIPHER_NONE) { - pos += snprintf(pos, end - pos, "%sNONE", first ? "" : "+"); + ret = os_snprintf(pos, end - pos, "%sNONE", first ? "" : "+"); + if (ret < 0 || ret >= end - pos) + return pos; + pos += ret; first = 0; } if (cipher & WPA_CIPHER_WEP40) { - pos += snprintf(pos, end - pos, "%sWEP40", first ? "" : "+"); + ret = os_snprintf(pos, end - pos, "%sWEP40", first ? "" : "+"); + if (ret < 0 || ret >= end - pos) + return pos; + pos += ret; first = 0; } if (cipher & WPA_CIPHER_WEP104) { - pos += snprintf(pos, end - pos, "%sWEP104", first ? "" : "+"); + ret = os_snprintf(pos, end - pos, "%sWEP104", + first ? "" : "+"); + if (ret < 0 || ret >= end - pos) + return pos; + pos += ret; first = 0; } if (cipher & WPA_CIPHER_TKIP) { - pos += snprintf(pos, end - pos, "%sTKIP", first ? "" : "+"); + ret = os_snprintf(pos, end - pos, "%sTKIP", first ? "" : "+"); + if (ret < 0 || ret >= end - pos) + return pos; + pos += ret; first = 0; } if (cipher & WPA_CIPHER_CCMP) { - pos += snprintf(pos, end - pos, "%sCCMP", first ? "" : "+"); + ret = os_snprintf(pos, end - pos, "%sCCMP", first ? "" : "+"); + if (ret < 0 || ret >= end - pos) + return pos; + pos += ret; first = 0; } return pos; } -static char * wpa_supplicant_ie_txt(struct wpa_supplicant *wpa_s, - char *pos, char *end, const char *proto, +static char * wpa_supplicant_ie_txt(char *pos, char *end, const char *proto, const u8 *ie, size_t ie_len) { struct wpa_ie_data data; - int first; + int first, ret; - pos += snprintf(pos, end - pos, "[%s-", proto); + ret = os_snprintf(pos, end - pos, "[%s-", proto); + if (ret < 0 || ret >= end - pos) + return pos; + pos += ret; if (wpa_parse_wpa_ie(ie, ie_len, &data) < 0) { - pos += snprintf(pos, end - pos, "?]"); + ret = os_snprintf(pos, end - pos, "?]"); + if (ret < 0 || ret >= end - pos) + return pos; + pos += ret; return pos; } first = 1; if (data.key_mgmt & WPA_KEY_MGMT_IEEE8021X) { - pos += snprintf(pos, end - pos, "%sEAP", first ? "" : "+"); + ret = os_snprintf(pos, end - pos, "%sEAP", first ? "" : "+"); + if (ret < 0 || ret >= end - pos) + return pos; + pos += ret; first = 0; } if (data.key_mgmt & WPA_KEY_MGMT_PSK) { - pos += snprintf(pos, end - pos, "%sPSK", first ? "" : "+"); + ret = os_snprintf(pos, end - pos, "%sPSK", first ? "" : "+"); + if (ret < 0 || ret >= end - pos) + return pos; + pos += ret; first = 0; } if (data.key_mgmt & WPA_KEY_MGMT_WPA_NONE) { - pos += snprintf(pos, end - pos, "%sNone", first ? "" : "+"); + ret = os_snprintf(pos, end - pos, "%sNone", first ? "" : "+"); + if (ret < 0 || ret >= end - pos) + return pos; + pos += ret; first = 0; } pos = wpa_supplicant_cipher_txt(pos, end, data.pairwise_cipher); - if (data.capabilities & WPA_CAPABILITY_PREAUTH) - pos += snprintf(pos, end - pos, "-preauth"); + if (data.capabilities & WPA_CAPABILITY_PREAUTH) { + ret = os_snprintf(pos, end - pos, "-preauth"); + if (ret < 0 || ret >= end - pos) + return pos; + pos += ret; + } - pos += snprintf(pos, end - pos, "]"); + ret = os_snprintf(pos, end - pos, "]"); + if (ret < 0 || ret >= end - pos) + return pos; + pos += ret; return pos; } @@ -492,41 +476,63 @@ static int wpa_supplicant_ctrl_iface_scan_results( { char *pos, *end; struct wpa_scan_result *res; - int i; + int i, ret; if (wpa_s->scan_results == NULL && wpa_supplicant_get_scan_results(wpa_s) < 0) return 0; + if (wpa_s->scan_results == NULL) + return 0; pos = buf; end = buf + buflen; - pos += snprintf(pos, end - pos, "bssid / frequency / signal level / " - "flags / ssid\n"); + ret = os_snprintf(pos, end - pos, "bssid / frequency / signal level / " + "flags / ssid\n"); + if (ret < 0 || ret >= end - pos) + return pos - buf; + pos += ret; for (i = 0; i < wpa_s->num_scan_results; i++) { res = &wpa_s->scan_results[i]; - pos += snprintf(pos, end - pos, MACSTR "\t%d\t%d\t", - MAC2STR(res->bssid), res->freq, res->level); + ret = os_snprintf(pos, end - pos, MACSTR "\t%d\t%d\t", + MAC2STR(res->bssid), res->freq, res->level); + if (ret < 0 || ret >= end - pos) + return pos - buf; + pos += ret; if (res->wpa_ie_len) { - pos = wpa_supplicant_ie_txt(wpa_s, pos, end, "WPA", + pos = wpa_supplicant_ie_txt(pos, end, "WPA", res->wpa_ie, res->wpa_ie_len); } if (res->rsn_ie_len) { - pos = wpa_supplicant_ie_txt(wpa_s, pos, end, "WPA2", + pos = wpa_supplicant_ie_txt(pos, end, "WPA2", res->rsn_ie, res->rsn_ie_len); } if (!res->wpa_ie_len && !res->rsn_ie_len && - res->caps & IEEE80211_CAP_PRIVACY) - pos += snprintf(pos, end - pos, "[WEP]"); - if (res->caps & IEEE80211_CAP_IBSS) - pos += snprintf(pos, end - pos, "[IBSS]"); + res->caps & IEEE80211_CAP_PRIVACY) { + ret = os_snprintf(pos, end - pos, "[WEP]"); + if (ret < 0 || ret >= end - pos) + return pos - buf; + pos += ret; + } + if (res->caps & IEEE80211_CAP_IBSS) { + ret = os_snprintf(pos, end - pos, "[IBSS]"); + if (ret < 0 || ret >= end - pos) + return pos - buf; + pos += ret; + } - pos += snprintf(pos, end - pos, "\t%s", - wpa_ssid_txt(res->ssid, res->ssid_len)); + ret = os_snprintf(pos, end - pos, "\t%s", + wpa_ssid_txt(res->ssid, res->ssid_len)); + if (ret < 0 || ret >= end - pos) + return pos - buf; + pos += ret; - pos += snprintf(pos, end - pos, "\n"); + ret = os_snprintf(pos, end - pos, "\n"); + if (ret < 0 || ret >= end - pos) + return pos - buf; + pos += ret; } return pos - buf; @@ -540,7 +546,7 @@ static int wpa_supplicant_ctrl_iface_select_network( struct wpa_ssid *ssid; /* cmd: "<network id>" or "any" */ - if (strcmp(cmd, "any") == 0) { + if (os_strcmp(cmd, "any") == 0) { wpa_printf(MSG_DEBUG, "CTRL_IFACE: SELECT_NETWORK any"); ssid = wpa_s->conf->ssid; while (ssid) { @@ -637,6 +643,7 @@ static int wpa_supplicant_ctrl_iface_add_network( struct wpa_supplicant *wpa_s, char *buf, size_t buflen) { struct wpa_ssid *ssid; + int ret; wpa_printf(MSG_DEBUG, "CTRL_IFACE: ADD_NETWORK"); @@ -646,7 +653,10 @@ static int wpa_supplicant_ctrl_iface_add_network( ssid->disabled = 1; wpa_config_set_network_defaults(ssid); - return snprintf(buf, buflen, "%d\n", ssid->id); + ret = os_snprintf(buf, buflen, "%d\n", ssid->id); + if (ret < 0 || (size_t) ret >= buflen) + return -1; + return ret; } @@ -668,8 +678,15 @@ static int wpa_supplicant_ctrl_iface_remove_network( return -1; } - if (ssid == wpa_s->current_ssid) + if (ssid == wpa_s->current_ssid) { + /* + * Invalidate the EAP session cache if the current network is + * removed. + */ + eapol_sm_invalidate_cached_session(wpa_s->eapol); + wpa_supplicant_disassociate(wpa_s, REASON_DEAUTH_LEAVING); + } return 0; } @@ -683,19 +700,21 @@ static int wpa_supplicant_ctrl_iface_set_network( char *name, *value; /* cmd: "<network id> <variable name> <value>" */ - name = strchr(cmd, ' '); + name = os_strchr(cmd, ' '); if (name == NULL) return -1; *name++ = '\0'; - value = strchr(name, ' '); + value = os_strchr(name, ' '); if (value == NULL) return -1; *value++ = '\0'; id = atoi(cmd); - wpa_printf(MSG_DEBUG, "CTRL_IFACE: SET_NETWORK id=%d name='%s' " - "value='%s'", id, name, value); + wpa_printf(MSG_DEBUG, "CTRL_IFACE: SET_NETWORK id=%d name='%s'", + id, name); + wpa_hexdump_ascii_key(MSG_DEBUG, "CTRL_IFACE: value", + (u8 *) value, os_strlen(value)); ssid = wpa_config_get_network(wpa_s->conf, id); if (ssid == NULL) { @@ -706,12 +725,21 @@ static int wpa_supplicant_ctrl_iface_set_network( if (wpa_config_set(ssid, name, value, 0) < 0) { wpa_printf(MSG_DEBUG, "CTRL_IFACE: Failed to set network " - "variable '%s' to '%s'", name, value); + "variable '%s'", name); return -1; } - if ((strcmp(name, "psk") == 0 && value[0] == '"' && ssid->ssid_len) || - (strcmp(name, "ssid") == 0 && ssid->passphrase)) + if (wpa_s->current_ssid == ssid) { + /* + * Invalidate the EAP session cache if anything in the current + * configuration changes. + */ + eapol_sm_invalidate_cached_session(wpa_s->eapol); + } + + if ((os_strcmp(name, "psk") == 0 && + value[0] == '"' && ssid->ssid_len) || + (os_strcmp(name, "ssid") == 0 && ssid->passphrase)) wpa_config_update_psk(ssid); return 0; @@ -726,8 +754,8 @@ static int wpa_supplicant_ctrl_iface_get_network( char *name, *value; /* cmd: "<network id> <variable name>" */ - name = strchr(cmd, ' '); - if (name == NULL) + name = os_strchr(cmd, ' '); + if (name == NULL || buflen == 0) return -1; *name++ = '\0'; @@ -742,18 +770,19 @@ static int wpa_supplicant_ctrl_iface_get_network( return -1; } - value = wpa_config_get(ssid, name); + value = wpa_config_get_no_key(ssid, name); if (value == NULL) { wpa_printf(MSG_DEBUG, "CTRL_IFACE: Failed to get network " "variable '%s'", name); return -1; } - snprintf(buf, buflen, "%s", value); + os_snprintf(buf, buflen, "%s", value); + buf[buflen - 1] = '\0'; - free(value); + os_free(value); - return strlen(buf); + return os_strlen(buf); } @@ -781,16 +810,28 @@ static int wpa_supplicant_ctrl_iface_save_config(struct wpa_supplicant *wpa_s) static int wpa_supplicant_ctrl_iface_get_capability( - struct wpa_supplicant *wpa_s, const char *field, char *buf, + struct wpa_supplicant *wpa_s, const char *_field, char *buf, size_t buflen) { struct wpa_driver_capa capa; - int res, first = 1; - char *pos, *end; + int res, first = 1, ret; + char *pos, *end, *strict; + char field[30]; + + /* Determine whether or not strict checking was requested */ + os_snprintf(field, sizeof(field), "%s", _field); + field[sizeof(field) - 1] = '\0'; + strict = os_strchr(field, ' '); + if (strict != NULL) { + *strict++ = '\0'; + if (os_strcmp(strict, "strict") != 0) + return -1; + } - wpa_printf(MSG_DEBUG, "CTRL_IFACE: GET_CAPABILITY '%s'", field); + wpa_printf(MSG_DEBUG, "CTRL_IFACE: GET_CAPABILITY '%s' %s", + field, strict ? strict : ""); - if (strcmp(field, "eap") == 0) { + if (os_strcmp(field, "eap") == 0) { return eap_get_names(buf, buflen); } @@ -799,124 +840,205 @@ static int wpa_supplicant_ctrl_iface_get_capability( pos = buf; end = pos + buflen; - if (strcmp(field, "pairwise") == 0) { - if (res < 0) - return snprintf(buf, buflen, "CCMP TKIP NONE"); + if (os_strcmp(field, "pairwise") == 0) { + if (res < 0) { + if (strict) + return 0; + ret = os_snprintf(buf, buflen, "CCMP TKIP NONE"); + if (ret < 0 || (size_t) ret >= buflen) + return -1; + return ret; + } if (capa.enc & WPA_DRIVER_CAPA_ENC_CCMP) { - pos += snprintf(pos, end - pos, "%sCCMP", - first ? "" : " "); + ret = os_snprintf(pos, end - pos, "%sCCMP", + first ? "" : " "); + if (ret < 0 || ret >= end - pos) + return pos - buf; + pos += ret; first = 0; } if (capa.enc & WPA_DRIVER_CAPA_ENC_TKIP) { - pos += snprintf(pos, end - pos, "%sTKIP", - first ? "" : " "); + ret = os_snprintf(pos, end - pos, "%sTKIP", + first ? "" : " "); + if (ret < 0 || ret >= end - pos) + return pos - buf; + pos += ret; first = 0; } if (capa.key_mgmt & WPA_DRIVER_CAPA_KEY_MGMT_WPA_NONE) { - pos += snprintf(pos, end - pos, "%sNONE", - first ? "" : " "); + ret = os_snprintf(pos, end - pos, "%sNONE", + first ? "" : " "); + if (ret < 0 || ret >= end - pos) + return pos - buf; + pos += ret; first = 0; } return pos - buf; } - if (strcmp(field, "group") == 0) { - if (res < 0) - return snprintf(buf, buflen, "CCMP TKIP WEP104 WEP40"); + if (os_strcmp(field, "group") == 0) { + if (res < 0) { + if (strict) + return 0; + ret = os_snprintf(buf, buflen, + "CCMP TKIP WEP104 WEP40"); + if (ret < 0 || (size_t) ret >= buflen) + return -1; + return ret; + } if (capa.enc & WPA_DRIVER_CAPA_ENC_CCMP) { - pos += snprintf(pos, end - pos, "%sCCMP", - first ? "" : " "); + ret = os_snprintf(pos, end - pos, "%sCCMP", + first ? "" : " "); + if (ret < 0 || ret >= end - pos) + return pos - buf; + pos += ret; first = 0; } if (capa.enc & WPA_DRIVER_CAPA_ENC_TKIP) { - pos += snprintf(pos, end - pos, "%sTKIP", - first ? "" : " "); + ret = os_snprintf(pos, end - pos, "%sTKIP", + first ? "" : " "); + if (ret < 0 || ret >= end - pos) + return pos - buf; + pos += ret; first = 0; } if (capa.enc & WPA_DRIVER_CAPA_ENC_WEP104) { - pos += snprintf(pos, end - pos, "%sWEP104", - first ? "" : " "); + ret = os_snprintf(pos, end - pos, "%sWEP104", + first ? "" : " "); + if (ret < 0 || ret >= end - pos) + return pos - buf; + pos += ret; first = 0; } if (capa.enc & WPA_DRIVER_CAPA_ENC_WEP40) { - pos += snprintf(pos, end - pos, "%sWEP40", - first ? "" : " "); + ret = os_snprintf(pos, end - pos, "%sWEP40", + first ? "" : " "); + if (ret < 0 || ret >= end - pos) + return pos - buf; + pos += ret; first = 0; } return pos - buf; } - if (strcmp(field, "key_mgmt") == 0) { + if (os_strcmp(field, "key_mgmt") == 0) { if (res < 0) { - return snprintf(buf, buflen, "WPA-PSK WPA-EAP " - "IEEE8021X WPA-NONE NONE"); + if (strict) + return 0; + ret = os_snprintf(buf, buflen, "WPA-PSK WPA-EAP " + "IEEE8021X WPA-NONE NONE"); + if (ret < 0 || (size_t) ret >= buflen) + return -1; + return ret; } - pos += snprintf(pos, end - pos, "NONE IEEE8021X"); + ret = os_snprintf(pos, end - pos, "NONE IEEE8021X"); + if (ret < 0 || ret >= end - pos) + return pos - buf; + pos += ret; if (capa.key_mgmt & (WPA_DRIVER_CAPA_KEY_MGMT_WPA | - WPA_DRIVER_CAPA_KEY_MGMT_WPA2)) - pos += snprintf(pos, end - pos, " WPA-EAP"); + WPA_DRIVER_CAPA_KEY_MGMT_WPA2)) { + ret = os_snprintf(pos, end - pos, " WPA-EAP"); + if (ret < 0 || ret >= end - pos) + return pos - buf; + pos += ret; + } if (capa.key_mgmt & (WPA_DRIVER_CAPA_KEY_MGMT_WPA_PSK | - WPA_DRIVER_CAPA_KEY_MGMT_WPA2_PSK)) - pos += snprintf(pos, end - pos, " WPA-PSK"); + WPA_DRIVER_CAPA_KEY_MGMT_WPA2_PSK)) { + ret = os_snprintf(pos, end - pos, " WPA-PSK"); + if (ret < 0 || ret >= end - pos) + return pos - buf; + pos += ret; + } - if (capa.key_mgmt & WPA_DRIVER_CAPA_KEY_MGMT_WPA_NONE) - pos += snprintf(pos, end - pos, " WPA-NONE"); + if (capa.key_mgmt & WPA_DRIVER_CAPA_KEY_MGMT_WPA_NONE) { + ret = os_snprintf(pos, end - pos, " WPA-NONE"); + if (ret < 0 || ret >= end - pos) + return pos - buf; + pos += ret; + } return pos - buf; } - if (strcmp(field, "proto") == 0) { - if (res < 0) - return snprintf(buf, buflen, "RSN WPA"); + if (os_strcmp(field, "proto") == 0) { + if (res < 0) { + if (strict) + return 0; + ret = os_snprintf(buf, buflen, "RSN WPA"); + if (ret < 0 || (size_t) ret >= buflen) + return -1; + return ret; + } if (capa.key_mgmt & (WPA_DRIVER_CAPA_KEY_MGMT_WPA2 | WPA_DRIVER_CAPA_KEY_MGMT_WPA2_PSK)) { - pos += snprintf(pos, end - pos, "%sRSN", - first ? "" : " "); + ret = os_snprintf(pos, end - pos, "%sRSN", + first ? "" : " "); + if (ret < 0 || ret >= end - pos) + return pos - buf; + pos += ret; first = 0; } if (capa.key_mgmt & (WPA_DRIVER_CAPA_KEY_MGMT_WPA | WPA_DRIVER_CAPA_KEY_MGMT_WPA_PSK)) { - pos += snprintf(pos, end - pos, "%sWPA", - first ? "" : " "); + ret = os_snprintf(pos, end - pos, "%sWPA", + first ? "" : " "); + if (ret < 0 || ret >= end - pos) + return pos - buf; + pos += ret; first = 0; } return pos - buf; } - if (strcmp(field, "auth_alg") == 0) { - if (res < 0) - return snprintf(buf, buflen, "OPEN SHARED LEAP"); + if (os_strcmp(field, "auth_alg") == 0) { + if (res < 0) { + if (strict) + return 0; + ret = os_snprintf(buf, buflen, "OPEN SHARED LEAP"); + if (ret < 0 || (size_t) ret >= buflen) + return -1; + return ret; + } if (capa.auth & (WPA_DRIVER_AUTH_OPEN)) { - pos += snprintf(pos, end - pos, "%sOPEN", - first ? "" : " "); + ret = os_snprintf(pos, end - pos, "%sOPEN", + first ? "" : " "); + if (ret < 0 || ret >= end - pos) + return pos - buf; + pos += ret; first = 0; } if (capa.auth & (WPA_DRIVER_AUTH_SHARED)) { - pos += snprintf(pos, end - pos, "%sSHARED", - first ? "" : " "); + ret = os_snprintf(pos, end - pos, "%sSHARED", + first ? "" : " "); + if (ret < 0 || ret >= end - pos) + return pos - buf; + pos += ret; first = 0; } if (capa.auth & (WPA_DRIVER_AUTH_LEAP)) { - pos += snprintf(pos, end - pos, "%sLEAP", - first ? "" : " "); + ret = os_snprintf(pos, end - pos, "%sLEAP", + first ? "" : " "); + if (ret < 0 || ret >= end - pos) + return pos - buf; + pos += ret; first = 0; } @@ -930,49 +1052,51 @@ static int wpa_supplicant_ctrl_iface_get_capability( } -static void wpa_supplicant_ctrl_iface_receive(int sock, void *eloop_ctx, - void *sock_ctx) +static int wpa_supplicant_ctrl_iface_ap_scan( + struct wpa_supplicant *wpa_s, char *cmd) +{ + int ap_scan = atoi(cmd); + + if (ap_scan < 0 || ap_scan > 2) + return -1; + wpa_s->conf->ap_scan = ap_scan; + return 0; +} + + +char * wpa_supplicant_ctrl_iface_process(struct wpa_supplicant *wpa_s, + char *buf, size_t *resp_len) { - struct wpa_supplicant *wpa_s = eloop_ctx; - char buf[256]; - int res; - CTRL_IFACE_SOCK from; - socklen_t fromlen = sizeof(from); char *reply; const int reply_size = 2048; + int ctrl_rsp = 0; int reply_len; - int new_attached = 0, ctrl_rsp = 0; - res = recvfrom(sock, buf, sizeof(buf) - 1, 0, - (struct sockaddr *) &from, &fromlen); - if (res < 0) { - perror("recvfrom(ctrl_iface)"); - return; - } - buf[res] = '\0'; - if (strncmp(buf, WPA_CTRL_RSP, strlen(WPA_CTRL_RSP)) == 0) { + if (os_strncmp(buf, WPA_CTRL_RSP, os_strlen(WPA_CTRL_RSP)) == 0 || + os_strncmp(buf, "SET_NETWORK ", 12) == 0) { wpa_hexdump_ascii_key(MSG_DEBUG, "RX ctrl_iface", - (u8 *) buf, res); + (const u8 *) buf, os_strlen(buf)); } else { - wpa_hexdump_ascii(MSG_DEBUG, "RX ctrl_iface", (u8 *) buf, res); + wpa_hexdump_ascii(MSG_DEBUG, "RX ctrl_iface", + (const u8 *) buf, os_strlen(buf)); } - reply = malloc(reply_size); + reply = os_malloc(reply_size); if (reply == NULL) { - sendto(sock, "FAIL\n", 5, 0, (struct sockaddr *) &from, - fromlen); - return; + *resp_len = 1; + return NULL; } - memcpy(reply, "OK\n", 3); + os_memcpy(reply, "OK\n", 3); reply_len = 3; - if (strcmp(buf, "PING") == 0) { - memcpy(reply, "PONG\n", 5); + if (os_strcmp(buf, "PING") == 0) { + os_memcpy(reply, "PONG\n", 5); reply_len = 5; - } else if (strcmp(buf, "MIB") == 0) { + } else if (os_strcmp(buf, "MIB") == 0) { reply_len = wpa_sm_get_mib(wpa_s->wpa, reply, reply_size); if (reply_len >= 0) { + int res; res = eapol_sm_get_mib(wpa_s->eapol, reply + reply_len, reply_size - reply_len); if (res < 0) @@ -980,452 +1104,105 @@ static void wpa_supplicant_ctrl_iface_receive(int sock, void *eloop_ctx, else reply_len += res; } - } else if (strncmp(buf, "STATUS", 6) == 0) { + } else if (os_strncmp(buf, "STATUS", 6) == 0) { reply_len = wpa_supplicant_ctrl_iface_status( wpa_s, buf + 6, reply, reply_size); - } else if (strcmp(buf, "PMKSA") == 0) { + } else if (os_strcmp(buf, "PMKSA") == 0) { reply_len = pmksa_cache_list(wpa_s->wpa, reply, reply_size); - } else if (strncmp(buf, "SET ", 4) == 0) { + } else if (os_strncmp(buf, "SET ", 4) == 0) { if (wpa_supplicant_ctrl_iface_set(wpa_s, buf + 4)) reply_len = -1; - } else if (strcmp(buf, "LOGON") == 0) { + } else if (os_strcmp(buf, "LOGON") == 0) { eapol_sm_notify_logoff(wpa_s->eapol, FALSE); - } else if (strcmp(buf, "LOGOFF") == 0) { + } else if (os_strcmp(buf, "LOGOFF") == 0) { eapol_sm_notify_logoff(wpa_s->eapol, TRUE); - } else if (strcmp(buf, "REASSOCIATE") == 0) { + } else if (os_strcmp(buf, "REASSOCIATE") == 0) { wpa_s->disconnected = 0; wpa_s->reassociate = 1; wpa_supplicant_req_scan(wpa_s, 0, 0); - } else if (strncmp(buf, "PREAUTH ", 8) == 0) { + } else if (os_strncmp(buf, "PREAUTH ", 8) == 0) { if (wpa_supplicant_ctrl_iface_preauth(wpa_s, buf + 8)) reply_len = -1; - } else if (strcmp(buf, "ATTACH") == 0) { - if (wpa_supplicant_ctrl_iface_attach(wpa_s, &from, fromlen)) - reply_len = -1; - else - new_attached = 1; - } else if (strcmp(buf, "DETACH") == 0) { - if (wpa_supplicant_ctrl_iface_detach(wpa_s, &from, fromlen)) - reply_len = -1; - } else if (strncmp(buf, "LEVEL ", 6) == 0) { - if (wpa_supplicant_ctrl_iface_level(wpa_s, &from, fromlen, - buf + 6)) +#ifdef CONFIG_PEERKEY + } else if (os_strncmp(buf, "STKSTART ", 9) == 0) { + if (wpa_supplicant_ctrl_iface_stkstart(wpa_s, buf + 9)) reply_len = -1; - } else if (strncmp(buf, WPA_CTRL_RSP, strlen(WPA_CTRL_RSP)) == 0) { +#endif /* CONFIG_PEERKEY */ + } else if (os_strncmp(buf, WPA_CTRL_RSP, os_strlen(WPA_CTRL_RSP)) == 0) + { if (wpa_supplicant_ctrl_iface_ctrl_rsp( - wpa_s, buf + strlen(WPA_CTRL_RSP))) + wpa_s, buf + os_strlen(WPA_CTRL_RSP))) reply_len = -1; else ctrl_rsp = 1; - } else if (strcmp(buf, "RECONFIGURE") == 0) { + } else if (os_strcmp(buf, "RECONFIGURE") == 0) { if (wpa_supplicant_reload_configuration(wpa_s)) reply_len = -1; - } else if (strcmp(buf, "TERMINATE") == 0) { + } else if (os_strcmp(buf, "TERMINATE") == 0) { eloop_terminate(); - } else if (strncmp(buf, "BSSID ", 6) == 0) { + } else if (os_strncmp(buf, "BSSID ", 6) == 0) { if (wpa_supplicant_ctrl_iface_bssid(wpa_s, buf + 6)) reply_len = -1; - } else if (strcmp(buf, "LIST_NETWORKS") == 0) { + } else if (os_strcmp(buf, "LIST_NETWORKS") == 0) { reply_len = wpa_supplicant_ctrl_iface_list_networks( wpa_s, reply, reply_size); - } else if (strcmp(buf, "DISCONNECT") == 0) { + } else if (os_strcmp(buf, "DISCONNECT") == 0) { wpa_s->disconnected = 1; wpa_supplicant_disassociate(wpa_s, REASON_DEAUTH_LEAVING); - } else if (strcmp(buf, "SCAN") == 0) { + } else if (os_strcmp(buf, "SCAN") == 0) { wpa_s->scan_req = 2; wpa_supplicant_req_scan(wpa_s, 0, 0); - } else if (strcmp(buf, "SCAN_RESULTS") == 0) { + } else if (os_strcmp(buf, "SCAN_RESULTS") == 0) { reply_len = wpa_supplicant_ctrl_iface_scan_results( wpa_s, reply, reply_size); - } else if (strncmp(buf, "SELECT_NETWORK ", 15) == 0) { + } else if (os_strncmp(buf, "SELECT_NETWORK ", 15) == 0) { if (wpa_supplicant_ctrl_iface_select_network(wpa_s, buf + 15)) reply_len = -1; - } else if (strncmp(buf, "ENABLE_NETWORK ", 15) == 0) { + } else if (os_strncmp(buf, "ENABLE_NETWORK ", 15) == 0) { if (wpa_supplicant_ctrl_iface_enable_network(wpa_s, buf + 15)) reply_len = -1; - } else if (strncmp(buf, "DISABLE_NETWORK ", 16) == 0) { + } else if (os_strncmp(buf, "DISABLE_NETWORK ", 16) == 0) { if (wpa_supplicant_ctrl_iface_disable_network(wpa_s, buf + 16)) reply_len = -1; - } else if (strcmp(buf, "ADD_NETWORK") == 0) { + } else if (os_strcmp(buf, "ADD_NETWORK") == 0) { reply_len = wpa_supplicant_ctrl_iface_add_network( wpa_s, reply, reply_size); - } else if (strncmp(buf, "REMOVE_NETWORK ", 15) == 0) { + } else if (os_strncmp(buf, "REMOVE_NETWORK ", 15) == 0) { if (wpa_supplicant_ctrl_iface_remove_network(wpa_s, buf + 15)) reply_len = -1; - } else if (strncmp(buf, "SET_NETWORK ", 12) == 0) { + } else if (os_strncmp(buf, "SET_NETWORK ", 12) == 0) { if (wpa_supplicant_ctrl_iface_set_network(wpa_s, buf + 12)) reply_len = -1; - } else if (strncmp(buf, "GET_NETWORK ", 12) == 0) { + } else if (os_strncmp(buf, "GET_NETWORK ", 12) == 0) { reply_len = wpa_supplicant_ctrl_iface_get_network( wpa_s, buf + 12, reply, reply_size); - } else if (strcmp(buf, "SAVE_CONFIG") == 0) { + } else if (os_strcmp(buf, "SAVE_CONFIG") == 0) { if (wpa_supplicant_ctrl_iface_save_config(wpa_s)) reply_len = -1; - } else if (strncmp(buf, "GET_CAPABILITY ", 15) == 0) { + } else if (os_strncmp(buf, "GET_CAPABILITY ", 15) == 0) { reply_len = wpa_supplicant_ctrl_iface_get_capability( wpa_s, buf + 15, reply, reply_size); + } else if (os_strncmp(buf, "AP_SCAN ", 8) == 0) { + if (wpa_supplicant_ctrl_iface_ap_scan(wpa_s, buf + 8)) + reply_len = -1; + } else if (os_strcmp(buf, "INTERFACES") == 0) { + reply_len = wpa_supplicant_global_iface_interfaces( + wpa_s->global, reply, reply_size); } else { - memcpy(reply, "UNKNOWN COMMAND\n", 16); + os_memcpy(reply, "UNKNOWN COMMAND\n", 16); reply_len = 16; } if (reply_len < 0) { - memcpy(reply, "FAIL\n", 5); + os_memcpy(reply, "FAIL\n", 5); reply_len = 5; } - sendto(sock, reply, reply_len, 0, (struct sockaddr *) &from, fromlen); - free(reply); - if (new_attached) - eapol_sm_notify_ctrl_attached(wpa_s->eapol); if (ctrl_rsp) eapol_sm_notify_ctrl_response(wpa_s->eapol); -} - - -#ifndef CONFIG_CTRL_IFACE_UDP -static char * wpa_supplicant_ctrl_iface_path(struct wpa_supplicant *wpa_s) -{ - char *buf; - size_t len; - - if (wpa_s->conf->ctrl_interface == NULL) - return NULL; - - len = strlen(wpa_s->conf->ctrl_interface) + strlen(wpa_s->ifname) + 2; - buf = malloc(len); - if (buf == NULL) - return NULL; - - snprintf(buf, len, "%s/%s", - wpa_s->conf->ctrl_interface, wpa_s->ifname); -#ifdef __CYGWIN__ - { - /* Windows/WinPcap uses interface names that are not suitable - * as a file name - convert invalid chars to underscores */ - char *pos = buf; - while (*pos) { - if (*pos == '\\') - *pos = '_'; - pos++; - } - } -#endif /* __CYGWIN__ */ - return buf; -} -#endif /* CONFIG_CTRL_IFACE_UDP */ - - -/** - * wpa_supplicant_ctrl_iface_init - Initialize control interface - * @wpa_s: Pointer to wpa_supplicant data - * Returns: 0 on success, -1 on failure - * - * Initialize the control interface and start receiving commands from external - * programs. - */ -int wpa_supplicant_ctrl_iface_init(struct wpa_supplicant *wpa_s) -{ - CTRL_IFACE_SOCK addr; - int s = -1; -#ifndef CONFIG_CTRL_IFACE_UDP - char *fname = NULL; -#endif /* CONFIG_CTRL_IFACE_UDP */ - - wpa_s->ctrl_sock = -1; - - if (wpa_s->conf->ctrl_interface == NULL) - return 0; - -#ifdef CONFIG_CTRL_IFACE_UDP - s = socket(PF_INET, SOCK_DGRAM, 0); - if (s < 0) { - perror("socket(PF_INET)"); - goto fail; - } - - memset(&addr, 0, sizeof(addr)); - addr.sin_family = AF_INET; - addr.sin_addr.s_addr = htonl((127 << 24) | 1); - addr.sin_port = htons(WPA_CTRL_IFACE_PORT); - if (bind(s, (struct sockaddr *) &addr, sizeof(addr)) < 0) { - perror("bind(AF_INET)"); - goto fail; - } -#else /* CONFIG_CTRL_IFACE_UDP */ - if (mkdir(wpa_s->conf->ctrl_interface, S_IRWXU | S_IRWXG) < 0) { - if (errno == EEXIST) { - wpa_printf(MSG_DEBUG, "Using existing control " - "interface directory."); - } else { - perror("mkdir[ctrl_interface]"); - goto fail; - } - } - - if (wpa_s->conf->ctrl_interface_gid_set && - chown(wpa_s->conf->ctrl_interface, 0, - wpa_s->conf->ctrl_interface_gid) < 0) { - perror("chown[ctrl_interface]"); - return -1; - } - - if (strlen(wpa_s->conf->ctrl_interface) + 1 + strlen(wpa_s->ifname) >= - sizeof(addr.sun_path)) - goto fail; - - s = socket(PF_UNIX, SOCK_DGRAM, 0); - if (s < 0) { - perror("socket(PF_UNIX)"); - goto fail; - } - - memset(&addr, 0, sizeof(addr)); - addr.sun_family = AF_UNIX; - fname = wpa_supplicant_ctrl_iface_path(wpa_s); - if (fname == NULL) - goto fail; - strncpy(addr.sun_path, fname, sizeof(addr.sun_path)); - if (bind(s, (struct sockaddr *) &addr, sizeof(addr)) < 0) { - perror("bind(PF_UNIX)"); - if (connect(s, (struct sockaddr *) &addr, sizeof(addr)) < 0) { - wpa_printf(MSG_DEBUG, "ctrl_iface exists, but does not" - " allow connections - assuming it was left" - "over from forced program termination"); - if (unlink(fname) < 0) { - perror("unlink[ctrl_iface]"); - wpa_printf(MSG_ERROR, "Could not unlink " - "existing ctrl_iface socket '%s'", - fname); - goto fail; - } - if (bind(s, (struct sockaddr *) &addr, sizeof(addr)) < - 0) { - perror("bind(PF_UNIX)"); - goto fail; - } - wpa_printf(MSG_DEBUG, "Successfully replaced leftover " - "ctrl_iface socket '%s'", fname); - } else { - wpa_printf(MSG_INFO, "ctrl_iface exists and seems to " - "be in use - cannot override it"); - wpa_printf(MSG_INFO, "Delete '%s' manually if it is " - "not used anymore", fname); - free(fname); - fname = NULL; - goto fail; - } - } - - if (wpa_s->conf->ctrl_interface_gid_set && - chown(fname, 0, wpa_s->conf->ctrl_interface_gid) < 0) { - perror("chown[ctrl_interface/ifname]"); - goto fail; - } - - if (chmod(fname, S_IRWXU | S_IRWXG) < 0) { - perror("chmod[ctrl_interface/ifname]"); - goto fail; - } - free(fname); -#endif /* CONFIG_CTRL_IFACE_UDP */ - - wpa_s->ctrl_sock = s; - eloop_register_read_sock(s, wpa_supplicant_ctrl_iface_receive, wpa_s, - NULL); - return 0; - -fail: - if (s >= 0) - close(s); -#ifndef CONFIG_CTRL_IFACE_UDP - if (fname) { - unlink(fname); - free(fname); - } -#endif /* CONFIG_CTRL_IFACE_UDP */ - return -1; -} - - -/** - * wpa_supplicant_ctrl_iface_deinit - Deinitialize control interface - * @wpa_s: Pointer to wpa_supplicant data - * - * Deinitialize the control interface that was initialized with - * wpa_supplicant_ctrl_iface_init(). - */ -void wpa_supplicant_ctrl_iface_deinit(struct wpa_supplicant *wpa_s) -{ - struct wpa_ctrl_dst *dst, *prev; - - if (wpa_s->ctrl_sock > -1) { -#ifndef CONFIG_CTRL_IFACE_UDP - char *fname; -#endif /* CONFIG_CTRL_IFACE_UDP */ - 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; -#ifndef CONFIG_CTRL_IFACE_UDP - fname = wpa_supplicant_ctrl_iface_path(wpa_s); - if (fname) - unlink(fname); - free(fname); - - if (rmdir(wpa_s->conf->ctrl_interface) < 0) { - if (errno == ENOTEMPTY) { - wpa_printf(MSG_DEBUG, "Control interface " - "directory not empty - leaving it " - "behind"); - } else { - perror("rmdir[ctrl_interface]"); - } - } -#endif /* CONFIG_CTRL_IFACE_UDP */ - } - - dst = wpa_s->ctrl_dst; - while (dst) { - prev = dst; - dst = dst->next; - free(prev); - } -} - - -/** - * wpa_supplicant_ctrl_iface_send - Send a control interface packet to monitors - * @wpa_s: Pointer to wpa_supplicant data - * @level: Priority level of the message - * @buf: Message data - * @len: Message length - * - * Send a packet to all monitor programs attached to the control interface. - */ -void wpa_supplicant_ctrl_iface_send(struct wpa_supplicant *wpa_s, int level, - char *buf, size_t len) -{ - struct wpa_ctrl_dst *dst, *next; - char levelstr[10]; - int idx; -#ifdef CONFIG_CTRL_IFACE_UDP - char *sbuf; - int llen; - - dst = wpa_s->ctrl_dst; - if (wpa_s->ctrl_sock < 0 || dst == NULL) - return; - - snprintf(levelstr, sizeof(levelstr), "<%d>", level); - - llen = strlen(levelstr); - sbuf = malloc(llen + len); - if (sbuf == NULL) - return; - - memcpy(sbuf, levelstr, llen); - memcpy(sbuf + llen, buf, len); - - idx = 0; - while (dst) { - next = dst->next; - if (level >= dst->debug_level) { - wpa_printf(MSG_DEBUG, "CTRL_IFACE monitor send %s:%d", - inet_ntoa(dst->addr.sin_addr), - ntohs(dst->addr.sin_port)); - if (sendto(wpa_s->ctrl_sock, sbuf, llen + len, 0, - (struct sockaddr *) &dst->addr, - sizeof(dst->addr)) < 0) { - perror("sendto(CTRL_IFACE monitor)"); - dst->errors++; - if (dst->errors > 10) { - wpa_supplicant_ctrl_iface_detach( - wpa_s, &dst->addr, - dst->addrlen); - } - } else - dst->errors = 0; - } - idx++; - dst = next; - } - free(sbuf); -#else /* CONFIG_CTRL_IFACE_UDP */ - struct msghdr msg; - struct iovec io[2]; - - dst = wpa_s->ctrl_dst; - if (wpa_s->ctrl_sock < 0 || dst == NULL) - return; - - snprintf(levelstr, sizeof(levelstr), "<%d>", level); - io[0].iov_base = levelstr; - io[0].iov_len = strlen(levelstr); - io[1].iov_base = buf; - io[1].iov_len = len; - memset(&msg, 0, sizeof(msg)); - msg.msg_iov = io; - msg.msg_iovlen = 2; - - idx = 0; - while (dst) { - next = dst->next; - if (level >= dst->debug_level) { - wpa_hexdump(MSG_DEBUG, "CTRL_IFACE monitor send", - (u8 *) dst->addr.sun_path, dst->addrlen); - msg.msg_name = &dst->addr; - msg.msg_namelen = dst->addrlen; - if (sendmsg(wpa_s->ctrl_sock, &msg, 0) < 0) { - perror("sendmsg(CTRL_IFACE monitor)"); - dst->errors++; - if (dst->errors > 10) { - wpa_supplicant_ctrl_iface_detach( - wpa_s, &dst->addr, - dst->addrlen); - } - } else - dst->errors = 0; - } - idx++; - dst = next; - } -#endif /* CONFIG_CTRL_IFACE_UDP */ -} - - -/** - * wpa_supplicant_ctrl_iface_wait - Wait for ctrl_iface monitor - * @wpa_s: Pointer to wpa_supplicant data - * - * Wait until the first message from an external program using the control - * interface is received. This function can be used to delay normal startup - * processing to allow control interface programs to attach with - * %wpa_supplicant before normal operations are started. - */ -void wpa_supplicant_ctrl_iface_wait(struct wpa_supplicant *wpa_s) -{ - fd_set rfds; - - if (wpa_s->ctrl_sock < 0) - return; - - wpa_printf(MSG_DEBUG, "CTRL_IFACE - %s - wait for monitor", - wpa_s->ifname); - - FD_ZERO(&rfds); - FD_SET(wpa_s->ctrl_sock, &rfds); - select(wpa_s->ctrl_sock + 1, &rfds, NULL, NULL, NULL); + *resp_len = reply_len; + return reply; } @@ -1437,14 +1214,15 @@ static int wpa_supplicant_global_iface_add(struct wpa_global *global, /* * <ifname>TAB<confname>TAB<driver>TAB<ctrl_interface>TAB<driver_param> + * TAB<bridge_ifname> */ wpa_printf(MSG_DEBUG, "CTRL_IFACE GLOBAL INTERFACE_ADD '%s'", cmd); - memset(&iface, 0, sizeof(iface)); + os_memset(&iface, 0, sizeof(iface)); do { iface.ifname = pos = cmd; - pos = strchr(pos, '\t'); + pos = os_strchr(pos, '\t'); if (pos) *pos++ = '\0'; if (iface.ifname[0] == '\0') @@ -1453,7 +1231,7 @@ static int wpa_supplicant_global_iface_add(struct wpa_global *global, break; iface.confname = pos; - pos = strchr(pos, '\t'); + pos = os_strchr(pos, '\t'); if (pos) *pos++ = '\0'; if (iface.confname[0] == '\0') @@ -1462,7 +1240,7 @@ static int wpa_supplicant_global_iface_add(struct wpa_global *global, break; iface.driver = pos; - pos = strchr(pos, '\t'); + pos = os_strchr(pos, '\t'); if (pos) *pos++ = '\0'; if (iface.driver[0] == '\0') @@ -1471,7 +1249,7 @@ static int wpa_supplicant_global_iface_add(struct wpa_global *global, break; iface.ctrl_interface = pos; - pos = strchr(pos, '\t'); + pos = os_strchr(pos, '\t'); if (pos) *pos++ = '\0'; if (iface.ctrl_interface[0] == '\0') @@ -1480,13 +1258,22 @@ static int wpa_supplicant_global_iface_add(struct wpa_global *global, break; iface.driver_param = pos; - pos = strchr(pos, '\t'); + pos = os_strchr(pos, '\t'); if (pos) *pos++ = '\0'; if (iface.driver_param[0] == '\0') iface.driver_param = NULL; if (pos == NULL) break; + + iface.bridge_ifname = pos; + pos = os_strchr(pos, '\t'); + if (pos) + *pos++ = '\0'; + if (iface.bridge_ifname[0] == '\0') + iface.bridge_ifname = NULL; + if (pos == NULL) + break; } while (0); if (wpa_supplicant_get_iface(global, iface.ifname)) @@ -1510,179 +1297,73 @@ static int wpa_supplicant_global_iface_remove(struct wpa_global *global, } -static void wpa_supplicant_global_ctrl_iface_receive(int sock, void *eloop_ctx, - void *sock_ctx) +static int wpa_supplicant_global_iface_interfaces(struct wpa_global *global, + char *buf, int len) { - struct wpa_global *global = eloop_ctx; - char buf[256]; int res; - CTRL_IFACE_SOCK from; - socklen_t fromlen = sizeof(from); + char *pos, *end; + struct wpa_supplicant *wpa_s; + + wpa_s = global->ifaces; + pos = buf; + end = buf + len; + + while (wpa_s) { + res = os_snprintf(pos, end - pos, "%s\n", wpa_s->ifname); + if (res < 0 || res >= end - pos) { + *pos = '\0'; + break; + } + pos += res; + wpa_s = wpa_s->next; + } + return pos - buf; +} + + +char * wpa_supplicant_global_ctrl_iface_process(struct wpa_global *global, + char *buf, size_t *resp_len) +{ char *reply; const int reply_size = 2048; int reply_len; - res = recvfrom(sock, buf, sizeof(buf) - 1, 0, - (struct sockaddr *) &from, &fromlen); - if (res < 0) { - perror("recvfrom(ctrl_iface)"); - return; - } - buf[res] = '\0'; - wpa_hexdump_ascii(MSG_DEBUG, "RX global ctrl_iface", (u8 *) buf, res); + wpa_hexdump_ascii(MSG_DEBUG, "RX global ctrl_iface", + (const u8 *) buf, os_strlen(buf)); - reply = malloc(reply_size); + reply = os_malloc(reply_size); if (reply == NULL) { - sendto(sock, "FAIL\n", 5, 0, (struct sockaddr *) &from, - fromlen); - return; + *resp_len = 1; + return NULL; } - memcpy(reply, "OK\n", 3); + os_memcpy(reply, "OK\n", 3); reply_len = 3; - if (strcmp(buf, "PING") == 0) { - memcpy(reply, "PONG\n", 5); + if (os_strcmp(buf, "PING") == 0) { + os_memcpy(reply, "PONG\n", 5); reply_len = 5; - } else if (strncmp(buf, "INTERFACE_ADD ", 14) == 0) { + } else if (os_strncmp(buf, "INTERFACE_ADD ", 14) == 0) { if (wpa_supplicant_global_iface_add(global, buf + 14)) reply_len = -1; - } else if (strncmp(buf, "INTERFACE_REMOVE ", 17) == 0) { + } else if (os_strncmp(buf, "INTERFACE_REMOVE ", 17) == 0) { if (wpa_supplicant_global_iface_remove(global, buf + 17)) reply_len = -1; + } else if (os_strcmp(buf, "INTERFACES") == 0) { + reply_len = wpa_supplicant_global_iface_interfaces( + global, reply, reply_size); + } else if (os_strcmp(buf, "TERMINATE") == 0) { + eloop_terminate(); } else { - memcpy(reply, "UNKNOWN COMMAND\n", 16); + os_memcpy(reply, "UNKNOWN COMMAND\n", 16); reply_len = 16; } if (reply_len < 0) { - memcpy(reply, "FAIL\n", 5); + os_memcpy(reply, "FAIL\n", 5); reply_len = 5; } - sendto(sock, reply, reply_len, 0, (struct sockaddr *) &from, fromlen); - free(reply); -} - - -/** - * wpa_supplicant_global_ctrl_iface_init - Initialize global control interface - * @global: Pointer to global data from wpa_supplicant_init() - * Returns: 0 on success, -1 on failure - * - * Initialize the global control interface and start receiving commands from - * external programs. - */ -int wpa_supplicant_global_ctrl_iface_init(struct wpa_global *global) -{ - CTRL_IFACE_SOCK addr; - int s = -1; -#ifndef CONFIG_CTRL_IFACE_UDP - char *fname = NULL; -#endif /* CONFIG_CTRL_IFACE_UDP */ - - global->ctrl_sock = -1; - - if (global->params.ctrl_interface == NULL) - return 0; - - wpa_printf(MSG_DEBUG, "Global control interface '%s'", - global->params.ctrl_interface); - -#ifdef CONFIG_CTRL_IFACE_UDP - s = socket(PF_INET, SOCK_DGRAM, 0); - if (s < 0) { - perror("socket(PF_INET)"); - goto fail; - } - - memset(&addr, 0, sizeof(addr)); - addr.sin_family = AF_INET; - addr.sin_addr.s_addr = htonl((127 << 24) | 1); - addr.sin_port = htons(WPA_GLOBAL_CTRL_IFACE_PORT); - if (bind(s, (struct sockaddr *) &addr, sizeof(addr)) < 0) { - perror("bind(AF_INET)"); - goto fail; - } -#else /* CONFIG_CTRL_IFACE_UDP */ - s = socket(PF_UNIX, SOCK_DGRAM, 0); - if (s < 0) { - perror("socket(PF_UNIX)"); - goto fail; - } - - memset(&addr, 0, sizeof(addr)); - addr.sun_family = AF_UNIX; - strncpy(addr.sun_path, global->params.ctrl_interface, - sizeof(addr.sun_path)); - if (bind(s, (struct sockaddr *) &addr, sizeof(addr)) < 0) { - perror("bind(PF_UNIX)"); - if (connect(s, (struct sockaddr *) &addr, sizeof(addr)) < 0) { - wpa_printf(MSG_DEBUG, "ctrl_iface exists, but does not" - " allow connections - assuming it was left" - "over from forced program termination"); - if (unlink(global->params.ctrl_interface) < 0) { - perror("unlink[ctrl_iface]"); - wpa_printf(MSG_ERROR, "Could not unlink " - "existing ctrl_iface socket '%s'", - global->params.ctrl_interface); - goto fail; - } - if (bind(s, (struct sockaddr *) &addr, sizeof(addr)) < - 0) { - perror("bind(PF_UNIX)"); - goto fail; - } - wpa_printf(MSG_DEBUG, "Successfully replaced leftover " - "ctrl_iface socket '%s'", - global->params.ctrl_interface); - } else { - wpa_printf(MSG_INFO, "ctrl_iface exists and seems to " - "be in use - cannot override it"); - wpa_printf(MSG_INFO, "Delete '%s' manually if it is " - "not used anymore", - global->params.ctrl_interface); - goto fail; - } - } -#endif /* CONFIG_CTRL_IFACE_UDP */ - - global->ctrl_sock = s; - eloop_register_read_sock(s, wpa_supplicant_global_ctrl_iface_receive, - global, NULL); - - return 0; - -fail: - if (s >= 0) - close(s); -#ifndef CONFIG_CTRL_IFACE_UDP - if (fname) { - unlink(fname); - free(fname); - } -#endif /* CONFIG_CTRL_IFACE_UDP */ - return -1; -} - - -/** - * wpa_supplicant_global_ctrl_iface_deinit - Deinitialize global ctrl interface - * @global: Pointer to global data from wpa_supplicant_init() - * - * Deinitialize the global control interface that was initialized with - * wpa_supplicant_global_ctrl_iface_init(). - */ -void wpa_supplicant_global_ctrl_iface_deinit(struct wpa_global *global) -{ - if (global->ctrl_sock < 0) - return; - - eloop_unregister_read_sock(global->ctrl_sock); - close(global->ctrl_sock); - global->ctrl_sock = -1; -#ifndef CONFIG_CTRL_IFACE_UDP - if (global->params.ctrl_interface) - unlink(global->params.ctrl_interface); -#endif /* CONFIG_CTRL_IFACE_UDP */ + *resp_len = reply_len; + return reply; } diff --git a/contrib/wpa_supplicant/ctrl_iface.h b/contrib/wpa_supplicant/ctrl_iface.h index affa6040a7e8..051d99a67dc6 100644 --- a/contrib/wpa_supplicant/ctrl_iface.h +++ b/contrib/wpa_supplicant/ctrl_iface.h @@ -1,6 +1,6 @@ /* * WPA Supplicant / UNIX domain socket -based control interface - * Copyright (c) 2004-2005, Jouni Malinen <jkmaline@cc.hut.fi> + * Copyright (c) 2004-2005, Jouni Malinen <j@w1.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 @@ -17,45 +17,140 @@ #ifdef CONFIG_CTRL_IFACE -int wpa_supplicant_ctrl_iface_init(struct wpa_supplicant *wpa_s); -void wpa_supplicant_ctrl_iface_deinit(struct wpa_supplicant *wpa_s); -void wpa_supplicant_ctrl_iface_send(struct wpa_supplicant *wpa_s, int level, - char *buf, size_t len); -void wpa_supplicant_ctrl_iface_wait(struct wpa_supplicant *wpa_s); -int wpa_supplicant_global_ctrl_iface_init(struct wpa_global *global); -void wpa_supplicant_global_ctrl_iface_deinit(struct wpa_global *global); +/* Shared functions from ctrl_iface.c; to be called by ctrl_iface backends */ + +/** + * wpa_supplicant_ctrl_iface_process - Process ctrl_iface command + * @wpa_s: Pointer to wpa_supplicant data + * @buf: Received command buffer (nul terminated string) + * @resp_len: Variable to be set to the response length + * Returns: Response (*resp_len bytes) or %NULL on failure + * + * Control interface backends call this function when receiving a message that + * they do not process internally, i.e., anything else than ATTACH, DETACH, + * and LEVEL. The return response value is then sent to the external program + * that sent the command. Caller is responsible for freeing the buffer after + * this. If %NULL is returned, *resp_len can be set to two special values: + * 1 = send "FAIL\n" response, 2 = send "OK\n" response. If *resp_len has any + * other value, no response is sent. + */ +char * wpa_supplicant_ctrl_iface_process(struct wpa_supplicant *wpa_s, + char *buf, size_t *resp_len); + +/** + * wpa_supplicant_ctrl_iface_process - Process global ctrl_iface command + * @global: Pointer to global data from wpa_supplicant_init() + * @buf: Received command buffer (nul terminated string) + * @resp_len: Variable to be set to the response length + * Returns: Response (*resp_len bytes) or %NULL on failure + * + * Control interface backends call this function when receiving a message from + * the global ctrl_iface connection. The return response value is then sent to + * the external program that sent the command. Caller is responsible for + * freeing the buffer after this. If %NULL is returned, *resp_len can be set to + * two special values: 1 = send "FAIL\n" response, 2 = send "OK\n" response. If + * *resp_len has any other value, no response is sent. + */ +char * wpa_supplicant_global_ctrl_iface_process(struct wpa_global *global, + char *buf, size_t *resp_len); + + +/* Functions that each ctrl_iface backend must implement */ + +/** + * wpa_supplicant_ctrl_iface_init - Initialize control interface + * @wpa_s: Pointer to wpa_supplicant data + * Returns: Pointer to private data on success, %NULL on failure + * + * Initialize the control interface and start receiving commands from external + * programs. + * + * Required to be implemented in each control interface backend. + */ +struct ctrl_iface_priv * +wpa_supplicant_ctrl_iface_init(struct wpa_supplicant *wpa_s); + +/** + * wpa_supplicant_ctrl_iface_deinit - Deinitialize control interface + * @priv: Pointer to private data from wpa_supplicant_ctrl_iface_init() + * + * Deinitialize the control interface that was initialized with + * wpa_supplicant_ctrl_iface_init(). + * + * Required to be implemented in each control interface backend. + */ +void wpa_supplicant_ctrl_iface_deinit(struct ctrl_iface_priv *priv); + +/** + * wpa_supplicant_ctrl_iface_wait - Wait for ctrl_iface monitor + * @priv: Pointer to private data from wpa_supplicant_ctrl_iface_init() + * + * Wait until the first message from an external program using the control + * interface is received. This function can be used to delay normal startup + * processing to allow control interface programs to attach with + * %wpa_supplicant before normal operations are started. + * + * Required to be implemented in each control interface backend. + */ +void wpa_supplicant_ctrl_iface_wait(struct ctrl_iface_priv *priv); + +/** + * wpa_supplicant_global_ctrl_iface_init - Initialize global control interface + * @global: Pointer to global data from wpa_supplicant_init() + * Returns: Pointer to private data on success, %NULL on failure + * + * Initialize the global control interface and start receiving commands from + * external programs. + * + * Required to be implemented in each control interface backend. + */ +struct ctrl_iface_global_priv * +wpa_supplicant_global_ctrl_iface_init(struct wpa_global *global); + +/** + * wpa_supplicant_global_ctrl_iface_deinit - Deinitialize global ctrl interface + * @priv: Pointer to private data from wpa_supplicant_global_ctrl_iface_init() + * + * Deinitialize the global control interface that was initialized with + * wpa_supplicant_global_ctrl_iface_init(). + * + * Required to be implemented in each control interface backend. + */ +void wpa_supplicant_global_ctrl_iface_deinit( + struct ctrl_iface_global_priv *priv); #else /* CONFIG_CTRL_IFACE */ -static inline int wpa_supplicant_ctrl_iface_init(struct wpa_supplicant *wpa_s) +static inline struct ctrl_iface_priv * +wpa_supplicant_ctrl_iface_init(struct wpa_supplicant *wpa_s) { - return 0; + return (void *) -1; } static inline void -wpa_supplicant_ctrl_iface_deinit(struct wpa_supplicant *wpa_s) +wpa_supplicant_ctrl_iface_deinit(struct ctrl_iface_priv *priv) { } static inline void -wpa_supplicant_ctrl_iface_send(struct wpa_supplicant *wpa_s, int level, +wpa_supplicant_ctrl_iface_send(struct ctrl_iface_priv *priv, int level, char *buf, size_t len) { } static inline void -wpa_supplicant_ctrl_iface_wait(struct wpa_supplicant *wpa_s) +wpa_supplicant_ctrl_iface_wait(struct ctrl_iface_priv *priv) { } -static inline int +static inline struct ctrl_iface_global_priv * wpa_supplicant_global_ctrl_iface_init(struct wpa_global *global) { - return 0; + return (void *) 1; } static inline void -wpa_supplicant_global_ctrl_iface_deinit(struct wpa_global *global) +wpa_supplicant_global_ctrl_iface_deinit(struct ctrl_iface_global_priv *priv) { } diff --git a/contrib/wpa_supplicant/ctrl_iface_dbus.c b/contrib/wpa_supplicant/ctrl_iface_dbus.c new file mode 100644 index 000000000000..1d66c9633d5c --- /dev/null +++ b/contrib/wpa_supplicant/ctrl_iface_dbus.c @@ -0,0 +1,1043 @@ +/* + * WPA Supplicant / dbus-based control interface + * Copyright (c) 2006, Dan Williams <dcbw@redhat.com> and Red Hat, Inc. + * + * 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 "includes.h" + +#include <dbus/dbus.h> + +#include "common.h" +#include "eloop.h" +#include "wpa.h" +#include "wpa_supplicant.h" +#include "config.h" +#include "eapol_sm.h" +#include "wpa_supplicant_i.h" +#include "ctrl_iface_dbus.h" +#include "ctrl_iface_dbus_handlers.h" +#include "l2_packet.h" +#include "preauth.h" +#include "wpa_ctrl.h" +#include "eap.h" + +struct ctrl_iface_dbus_priv { + DBusConnection *con; + int should_dispatch; + struct wpa_global *global; + + u32 next_objid; +}; + + +static void process_watch(struct ctrl_iface_dbus_priv *iface, + DBusWatch *watch, eloop_event_type type) +{ + dbus_connection_ref(iface->con); + + iface->should_dispatch = 0; + + if (type == EVENT_TYPE_READ) + dbus_watch_handle(watch, DBUS_WATCH_READABLE); + else if (type == EVENT_TYPE_WRITE) + dbus_watch_handle(watch, DBUS_WATCH_WRITABLE); + else if (type == EVENT_TYPE_EXCEPTION) + dbus_watch_handle(watch, DBUS_WATCH_ERROR); + + if (iface->should_dispatch) { + while (dbus_connection_get_dispatch_status(iface->con) == + DBUS_DISPATCH_DATA_REMAINS) + dbus_connection_dispatch(iface->con); + iface->should_dispatch = 0; + } + + dbus_connection_unref(iface->con); +} + + +static void process_watch_exception(int sock, void *eloop_ctx, void *sock_ctx) +{ + process_watch(eloop_ctx, sock_ctx, EVENT_TYPE_EXCEPTION); +} + + +static void process_watch_read(int sock, void *eloop_ctx, void *sock_ctx) +{ + process_watch(eloop_ctx, sock_ctx, EVENT_TYPE_READ); +} + + +static void process_watch_write(int sock, void *eloop_ctx, void *sock_ctx) +{ + process_watch(eloop_ctx, sock_ctx, EVENT_TYPE_WRITE); +} + + +static void connection_setup_add_watch(struct ctrl_iface_dbus_priv *iface, + DBusWatch *watch) +{ + unsigned int flags; + int fd; + + if (!dbus_watch_get_enabled(watch)) + return; + + flags = dbus_watch_get_flags(watch); + fd = dbus_watch_get_fd(watch); + + eloop_register_sock(fd, EVENT_TYPE_EXCEPTION, process_watch_exception, + iface, watch); + + if (flags & DBUS_WATCH_READABLE) { + eloop_register_sock(fd, EVENT_TYPE_READ, process_watch_read, + iface, watch); + } + if (flags & DBUS_WATCH_WRITABLE) { + eloop_register_sock(fd, EVENT_TYPE_WRITE, process_watch_write, + iface, watch); + } + + dbus_watch_set_data(watch, iface, NULL); +} + + +static void connection_setup_remove_watch(struct ctrl_iface_dbus_priv *iface, + DBusWatch *watch) +{ + unsigned int flags; + int fd; + + flags = dbus_watch_get_flags(watch); + fd = dbus_watch_get_fd(watch); + + eloop_unregister_sock(fd, EVENT_TYPE_EXCEPTION); + + if (flags & DBUS_WATCH_READABLE) + eloop_unregister_sock(fd, EVENT_TYPE_READ); + if (flags & DBUS_WATCH_WRITABLE) + eloop_unregister_sock(fd, EVENT_TYPE_WRITE); + + dbus_watch_set_data(watch, NULL, NULL); +} + + +static dbus_bool_t add_watch(DBusWatch *watch, void *data) +{ + connection_setup_add_watch(data, watch); + return TRUE; +} + + +static void remove_watch(DBusWatch *watch, void *data) +{ + connection_setup_remove_watch(data, watch); +} + + +static void watch_toggled(DBusWatch *watch, void *data) +{ + if (dbus_watch_get_enabled(watch)) + add_watch(watch, data); + else + remove_watch(watch, data); +} + + +static void process_timeout(void *eloop_ctx, void *sock_ctx) +{ + DBusTimeout *timeout = sock_ctx; + + dbus_timeout_handle(timeout); +} + + +static void connection_setup_add_timeout(struct ctrl_iface_dbus_priv *iface, + DBusTimeout *timeout) +{ + if (!dbus_timeout_get_enabled(timeout)) + return; + + eloop_register_timeout(0, dbus_timeout_get_interval(timeout) * 1000, + process_timeout, iface, timeout); + + dbus_timeout_set_data(timeout, iface, NULL); +} + + +static void connection_setup_remove_timeout(struct ctrl_iface_dbus_priv *iface, + DBusTimeout *timeout) +{ + eloop_cancel_timeout(process_timeout, iface, timeout); + dbus_timeout_set_data(timeout, NULL, NULL); +} + + +static dbus_bool_t add_timeout(DBusTimeout *timeout, void *data) +{ + if (!dbus_timeout_get_enabled(timeout)) + return TRUE; + + connection_setup_add_timeout(data, timeout); + + return TRUE; +} + + +static void remove_timeout(DBusTimeout *timeout, void *data) +{ + connection_setup_remove_timeout(data, timeout); +} + + +static void timeout_toggled(DBusTimeout *timeout, void *data) +{ + if (dbus_timeout_get_enabled(timeout)) + add_timeout(timeout, data); + else + remove_timeout(timeout, data); +} + + +static void process_wakeup_main(int sig, void *eloop_ctx, void *signal_ctx) +{ + struct ctrl_iface_dbus_priv *iface = signal_ctx; + + if (sig != SIGPOLL || !iface->con) + return; + + if (dbus_connection_get_dispatch_status(iface->con) != + DBUS_DISPATCH_DATA_REMAINS) + return; + + /* Only dispatch once - we do not want to starve other events */ + dbus_connection_ref(iface->con); + dbus_connection_dispatch(iface->con); + dbus_connection_unref(iface->con); +} + + +/** + * wakeup_main - Attempt to wake our mainloop up + * @data: dbus control interface private data + * + * Try to wake up the main eloop so it will process + * dbus events that may have happened. + */ +static void wakeup_main(void *data) +{ + struct ctrl_iface_dbus_priv *iface = data; + + /* Use SIGPOLL to break out of the eloop select() */ + raise(SIGPOLL); + iface->should_dispatch = 1; +} + + +/** + * connection_setup_wakeup_main - Tell dbus about our wakeup_main function + * @iface: dbus control interface private data + * Returns: 0 on success, -1 on failure + * + * Register our wakeup_main handler with dbus + */ +static int connection_setup_wakeup_main(struct ctrl_iface_dbus_priv *iface) +{ + if (eloop_register_signal(SIGPOLL, process_wakeup_main, iface)) + return -1; + + dbus_connection_set_wakeup_main_function(iface->con, wakeup_main, + iface, NULL); + + return 0; +} + + +/** + * wpa_supplicant_dbus_next_objid - Return next available object id + * @iface: dbus control interface private data + * Returns: Object id + */ +u32 wpa_supplicant_dbus_next_objid (struct ctrl_iface_dbus_priv *iface) +{ + return iface->next_objid++; +} + + +/** + * wpas_dbus_decompose_object_path - Decompose an interface object path into parts + * @path: The dbus object path + * @network: (out) the configured network this object path refers to, if any + * @bssid: (out) the scanned bssid this object path refers to, if any + * Returns: The object path of the network interface this path refers to + * + * For a given object path, decomposes the object path into object id, network, + * and BSSID parts, if those parts exist. + */ +char * wpas_dbus_decompose_object_path(const char *path, char **network, + char **bssid) +{ + const unsigned int dev_path_prefix_len = + strlen(WPAS_DBUS_PATH_INTERFACES "/"); + char *obj_path_only; + char *next_sep; + + /* Be a bit paranoid about path */ + if (!path || strncmp(path, WPAS_DBUS_PATH_INTERFACES "/", + dev_path_prefix_len)) + return NULL; + + /* Ensure there's something at the end of the path */ + if ((path + dev_path_prefix_len)[0] == '\0') + return NULL; + + obj_path_only = strdup(path); + if (obj_path_only == NULL) + return NULL; + + next_sep = strchr(obj_path_only + dev_path_prefix_len, '/'); + if (next_sep != NULL) { + const char *net_part = strstr(next_sep, + WPAS_DBUS_NETWORKS_PART "/"); + const char *bssid_part = strstr(next_sep, + WPAS_DBUS_BSSIDS_PART "/"); + + if (network && net_part) { + /* Deal with a request for a configured network */ + const char *net_name = net_part + + strlen(WPAS_DBUS_NETWORKS_PART "/"); + *network = NULL; + if (strlen(net_name)) + *network = strdup(net_name); + } else if (bssid && bssid_part) { + /* Deal with a request for a scanned BSSID */ + const char *bssid_name = bssid_part + + strlen(WPAS_DBUS_BSSIDS_PART "/"); + if (strlen(bssid_name)) + *bssid = strdup(bssid_name); + else + *bssid = NULL; + } + + /* Cut off interface object path before "/" */ + *next_sep = '\0'; + } + + return obj_path_only; +} + + +/** + * wpas_dbus_new_invalid_iface_error - Return a new invalid interface error message + * @message: Pointer to incoming dbus message this error refers to + * Returns: A dbus error message + * + * Convenience function to create and return an invalid interface error + */ +DBusMessage * wpas_dbus_new_invalid_iface_error(DBusMessage *message) +{ + return dbus_message_new_error(message, WPAS_ERROR_INVALID_IFACE, + "wpa_supplicant knows nothing about " + "this interface."); +} + + +/** + * wpas_dbus_new_invalid_network_error - Return a new invalid network error message + * @message: Pointer to incoming dbus message this error refers to + * Returns: a dbus error message + * + * Convenience function to create and return an invalid network error + */ +DBusMessage * wpas_dbus_new_invalid_network_error(DBusMessage *message) +{ + return dbus_message_new_error(message, WPAS_ERROR_INVALID_NETWORK, + "The requested network does not exist."); +} + + +/** + * wpas_dbus_new_invalid_bssid_error - Return a new invalid bssid error message + * @message: Pointer to incoming dbus message this error refers to + * Returns: a dbus error message + * + * Convenience function to create and return an invalid bssid error + */ +static DBusMessage * wpas_dbus_new_invalid_bssid_error(DBusMessage *message) +{ + return dbus_message_new_error(message, WPAS_ERROR_INVALID_BSSID, + "The BSSID requested was invalid."); +} + + +/** + * wpas_dispatch_network_method - dispatch messages for configured networks + * @message: the incoming dbus message + * @wpa_s: a network interface's data + * @network_id: id of the configured network we're interested in + * Returns: a reply dbus message, or a dbus error message + * + * This function dispatches all incoming dbus messages for configured networks. + */ +static DBusMessage * wpas_dispatch_network_method(DBusMessage *message, + struct wpa_supplicant *wpa_s, + int network_id) +{ + DBusMessage *reply = NULL; + const char *method = dbus_message_get_member(message); + struct wpa_ssid *ssid; + + ssid = wpa_config_get_network(wpa_s->conf, network_id); + if (ssid == NULL) + return wpas_dbus_new_invalid_network_error(message); + + if (!strcmp(method, "set")) + reply = wpas_dbus_iface_set_network(message, wpa_s, ssid); + else if (!strcmp(method, "enable")) + reply = wpas_dbus_iface_enable_network(message, wpa_s, ssid); + else if (!strcmp(method, "disable")) + reply = wpas_dbus_iface_disable_network(message, wpa_s, ssid); + + return reply; +} + + +/** + * wpas_dispatch_bssid_method - dispatch messages for scanned networks + * @message: the incoming dbus message + * @wpa_s: a network interface's data + * @bssid: bssid of the scanned network we're interested in + * Returns: a reply dbus message, or a dbus error message + * + * This function dispatches all incoming dbus messages for scanned networks. + */ +static DBusMessage * wpas_dispatch_bssid_method(DBusMessage *message, + struct wpa_supplicant *wpa_s, + const char *bssid) +{ + DBusMessage *reply = NULL; + const char *method = dbus_message_get_member(message); + struct wpa_scan_result * res = NULL; + int i; + + /* Ensure we actually have scan data */ + if (wpa_s->scan_results == NULL && + wpa_supplicant_get_scan_results(wpa_s) < 0) { + reply = wpas_dbus_new_invalid_bssid_error(message); + goto out; + } + + /* Find the bssid's scan data */ + for (i = 0; i < wpa_s->num_scan_results; i++) { + struct wpa_scan_result * search_res = &wpa_s->scan_results[i]; + char mac_str[18]; + + memset(mac_str, 0, sizeof(mac_str)); + snprintf(mac_str, sizeof(mac_str) - 1, WPAS_DBUS_BSSID_FORMAT, + MAC2STR(search_res->bssid)); + if (!strcmp(bssid, mac_str)) { + res = search_res; + } + } + + if (!res) { + reply = wpas_dbus_new_invalid_bssid_error(message); + goto out; + } + + /* Dispatch the method call against the scanned bssid */ + if (!strcmp(method, "properties")) + reply = wpas_dbus_bssid_properties(message, wpa_s, res); + +out: + return reply; +} + + +/** + * wpas_iface_message_handler - Dispatch messages for interfaces or networks + * @connection: Connection to the system message bus + * @message: An incoming dbus message + * @user_data: A pointer to a dbus control interface data structure + * Returns: Whether or not the message was handled + * + * This function dispatches all incoming dbus messages for network interfaces, + * or objects owned by them, such as scanned BSSIDs and configured networks. + */ +static DBusHandlerResult wpas_iface_message_handler(DBusConnection *connection, + DBusMessage *message, + void *user_data) +{ + struct wpa_supplicant *wpa_s = user_data; + const char *method = dbus_message_get_member(message); + const char *path = dbus_message_get_path(message); + const char *msg_interface = dbus_message_get_interface(message); + char *iface_obj_path = NULL; + char *network = NULL; + char *bssid = NULL; + DBusMessage *reply = NULL; + + /* Caller must specify a message interface */ + if (!msg_interface) + goto out; + + iface_obj_path = wpas_dbus_decompose_object_path(path, &network, + &bssid); + if (iface_obj_path == NULL) { + reply = wpas_dbus_new_invalid_iface_error(message); + goto out; + } + + /* Make sure the message's object path actually refers to the + * wpa_supplicant structure it's supposed to (which is wpa_s) + */ + if (wpa_supplicant_get_iface_by_dbus_path(wpa_s->global, + iface_obj_path) != wpa_s) { + reply = wpas_dbus_new_invalid_iface_error(message); + goto out; + } + + if (network && !strcmp(msg_interface, WPAS_DBUS_IFACE_NETWORK)) { + /* A method for one of this interface's configured networks */ + int nid = strtoul(network, NULL, 10); + if (errno != EINVAL) + reply = wpas_dispatch_network_method(message, wpa_s, + nid); + else + reply = wpas_dbus_new_invalid_network_error(message); + } else if (bssid && !strcmp(msg_interface, WPAS_DBUS_IFACE_BSSID)) { + /* A method for one of this interface's scanned BSSIDs */ + reply = wpas_dispatch_bssid_method(message, wpa_s, bssid); + } else if (!strcmp(msg_interface, WPAS_DBUS_IFACE_INTERFACE)) { + /* A method for an interface only. */ + if (!strcmp(method, "scan")) + reply = wpas_dbus_iface_scan(message, wpa_s); + else if (!strcmp(method, "scanResults")) + reply = wpas_dbus_iface_scan_results(message, wpa_s); + else if (!strcmp(method, "addNetwork")) + reply = wpas_dbus_iface_add_network(message, wpa_s); + else if (!strcmp(method, "removeNetwork")) + reply = wpas_dbus_iface_remove_network(message, wpa_s); + else if (!strcmp(method, "selectNetwork")) + reply = wpas_dbus_iface_select_network(message, wpa_s); + else if (!strcmp(method, "capabilities")) + reply = wpas_dbus_iface_capabilities(message, wpa_s); + else if (!strcmp(method, "disconnect")) + reply = wpas_dbus_iface_disconnect(message, wpa_s); + else if (!strcmp(method, "setAPScan")) + reply = wpas_dbus_iface_set_ap_scan(message, wpa_s); + else if (!strcmp(method, "state")) + reply = wpas_dbus_iface_get_state(message, wpa_s); + } + + /* If the message was handled, send back the reply */ + if (reply) { + dbus_connection_send(connection, reply, NULL); + dbus_message_unref(reply); + } + +out: + free(iface_obj_path); + free(network); + free(bssid); + return reply ? DBUS_HANDLER_RESULT_HANDLED : + DBUS_HANDLER_RESULT_NOT_YET_HANDLED; +} + + +/** + * wpas_message_handler - dispatch incoming dbus messages + * @connection: connection to the system message bus + * @message: an incoming dbus message + * @user_data: a pointer to a dbus control interface data structure + * Returns: whether or not the message was handled + * + * This function dispatches all incoming dbus messages to the correct + * handlers, depending on what the message's target object path is, + * and what the method call is. + */ +static DBusHandlerResult wpas_message_handler(DBusConnection *connection, + DBusMessage *message, void *user_data) +{ + struct ctrl_iface_dbus_priv *ctrl_iface = user_data; + const char *method; + const char *path; + const char *msg_interface; + DBusMessage *reply = NULL; + + method = dbus_message_get_member(message); + path = dbus_message_get_path(message); + msg_interface = dbus_message_get_interface(message); + if (!method || !path || !ctrl_iface || !msg_interface) + return DBUS_HANDLER_RESULT_NOT_YET_HANDLED; + + /* Validate the method interface */ + if (strcmp(msg_interface, WPAS_DBUS_INTERFACE) != 0) + return DBUS_HANDLER_RESULT_NOT_YET_HANDLED; + + if (!strcmp(path, WPAS_DBUS_PATH)) { + /* dispatch methods against our global dbus interface here */ + if (!strcmp(method, "addInterface")) { + reply = wpas_dbus_global_add_interface( + message, ctrl_iface->global); + } else if (!strcmp(method, "removeInterface")) { + reply = wpas_dbus_global_remove_interface( + message, ctrl_iface->global); + } else if (!strcmp(method, "getInterface")) { + reply = wpas_dbus_global_get_interface( + message, ctrl_iface->global); + } + } + + /* If the message was handled, send back the reply */ + if (reply) { + dbus_connection_send(connection, reply, NULL); + dbus_message_unref(reply); + } + + return reply ? DBUS_HANDLER_RESULT_HANDLED : + DBUS_HANDLER_RESULT_NOT_YET_HANDLED; +} + + +/** + * wpa_supplicant_dbus_notify_scan_results - Send a scan results signal + * @wpa_s: %wpa_supplicant network interface data + * Returns: 0 on success, -1 on failure + * + * Notify listeners that this interface has updated scan results. + */ +void wpa_supplicant_dbus_notify_scan_results(struct wpa_supplicant *wpa_s) +{ + struct ctrl_iface_dbus_priv *iface = wpa_s->global->dbus_ctrl_iface; + DBusMessage *signal; + const char *path; + + /* Do nothing if the control interface is not turned on */ + if (iface == NULL) + return; + + path = wpa_supplicant_get_dbus_path(wpa_s); + if (path == NULL) { + perror("wpa_supplicant_dbus_notify_scan_results[dbus]: " + "interface didn't have a dbus path"); + wpa_printf(MSG_ERROR, + "wpa_supplicant_dbus_notify_scan_results[dbus]: " + "interface didn't have a dbus path; can't send " + "scan result signal."); + return; + } + signal = dbus_message_new_signal(path, WPAS_DBUS_IFACE_INTERFACE, + "ScanResultsAvailable"); + if (signal == NULL) { + perror("wpa_supplicant_dbus_notify_scan_results[dbus]: " + "couldn't create dbus signal; likely out of memory"); + wpa_printf(MSG_ERROR, "dbus control interface: not enough " + "memory to send scan results signal."); + return; + } + dbus_connection_send(iface->con, signal, NULL); +} + + +/** + * wpa_supplicant_dbus_notify_state_change - Send a state change signal + * @wpa_s: %wpa_supplicant network interface data + * @new_state: new state wpa_supplicant is entering + * @old_state: old state wpa_supplicant is leaving + * Returns: 0 on success, -1 on failure + * + * Notify listeners that wpa_supplicant has changed state + */ +void wpa_supplicant_dbus_notify_state_change(struct wpa_supplicant *wpa_s, + wpa_states new_state, + wpa_states old_state) +{ + struct ctrl_iface_dbus_priv *iface; + DBusMessage *signal; + const char *path; + const char *new_state_str, *old_state_str; + + /* Do nothing if the control interface is not turned on */ + if (wpa_s->global == NULL) + return; + iface = wpa_s->global->dbus_ctrl_iface; + if (iface == NULL) + return; + + /* Only send signal if state really changed */ + if (new_state == old_state) + return; + + path = wpa_supplicant_get_dbus_path(wpa_s); + if (path == NULL) { + perror("wpa_supplicant_dbus_notify_state_change[dbus]: " + "interface didn't have a dbus path"); + wpa_printf(MSG_ERROR, + "wpa_supplicant_dbus_notify_state_change[dbus]: " + "interface didn't have a dbus path; can't send " + "signal."); + return; + } + signal = dbus_message_new_signal(path, WPAS_DBUS_IFACE_INTERFACE, + "StateChange"); + if (signal == NULL) { + perror("wpa_supplicant_dbus_notify_state_change[dbus]: " + "couldn't create dbus signal; likely out of memory"); + wpa_printf(MSG_ERROR, + "wpa_supplicant_dbus_notify_state_change[dbus]: " + "couldn't create dbus signal; likely out of " + "memory."); + return; + } + + new_state_str = wpa_supplicant_state_txt(new_state); + old_state_str = wpa_supplicant_state_txt(old_state); + if (new_state_str == NULL || old_state_str == NULL) { + perror("wpa_supplicant_dbus_notify_state_change[dbus]: " + "couldn't convert state strings"); + wpa_printf(MSG_ERROR, + "wpa_supplicant_dbus_notify_state_change[dbus]: " + "couldn't convert state strings."); + return; + } + + if (!dbus_message_append_args(signal, + DBUS_TYPE_STRING, &new_state_str, + DBUS_TYPE_STRING, &old_state_str, + DBUS_TYPE_INVALID)) { + perror("wpa_supplicant_dbus_notify_state_change[dbus]: " + "not enough memory to construct state change signal."); + wpa_printf(MSG_ERROR, + "wpa_supplicant_dbus_notify_state_change[dbus]: " + "not enough memory to construct state change " + "signal."); + } + dbus_connection_send(iface->con, signal, NULL); +} + + +/** + * integrate_with_eloop - Register our mainloop integration with dbus + * @connection: connection to the system message bus + * @iface: a dbus control interface data structure + * Returns: 0 on success, -1 on failure + * + * We register our mainloop integration functions with dbus here. + */ +static int integrate_with_eloop(DBusConnection *connection, + struct ctrl_iface_dbus_priv *iface) +{ + if (!dbus_connection_set_watch_functions(connection, add_watch, + remove_watch, watch_toggled, + iface, NULL)) { + perror("dbus_connection_set_watch_functions[dbus]"); + wpa_printf(MSG_ERROR, "Not enough memory to set up dbus."); + return -1; + } + + if (!dbus_connection_set_timeout_functions(connection, add_timeout, + remove_timeout, + timeout_toggled, iface, + NULL)) { + perror("dbus_connection_set_timeout_functions[dbus]"); + wpa_printf(MSG_ERROR, "Not enough memory to set up dbus."); + return -1; + } + + if (connection_setup_wakeup_main(iface) < 0) { + perror("connection_setup_wakeup_main[dbus]"); + wpa_printf(MSG_ERROR, "Could not setup main wakeup function."); + return -1; + } + + return 0; +} + + +/** + * dispatch_initial_dbus_messages - Dispatch initial dbus messages after + * claiming bus name + * @eloop_ctx: the DBusConnection to dispatch on + * @timeout_ctx: unused + * + * If clients are quick to notice that wpa_supplicant claimed its bus name, + * there may have been messages that came in before initialization was + * all finished. Dispatch those here. + */ +static void dispatch_initial_dbus_messages(void *eloop_ctx, void *timeout_ctx) +{ + DBusConnection *con = eloop_ctx; + + while (dbus_connection_get_dispatch_status(con) == + DBUS_DISPATCH_DATA_REMAINS) + dbus_connection_dispatch(con); +} + + +/** + * wpa_supplicant_dbus_ctrl_iface_init - Initialize dbus control interface + * @global: Pointer to global data from wpa_supplicant_init() + * Returns: Pointer to dbus_ctrl_iface date or %NULL on failure + * + * Initialize the dbus control interface and start receiving commands from + * external programs over the bus. + */ +struct ctrl_iface_dbus_priv * +wpa_supplicant_dbus_ctrl_iface_init(struct wpa_global *global) +{ + struct ctrl_iface_dbus_priv *iface; + DBusError error; + int ret = -1; + DBusObjectPathVTable wpas_vtable = { + NULL, &wpas_message_handler, NULL, NULL, NULL, NULL + }; + + iface = wpa_zalloc(sizeof(struct ctrl_iface_dbus_priv)); + if (iface == NULL) + return NULL; + + iface->global = global; + + /* Get a reference to the system bus */ + dbus_error_init(&error); + iface->con = dbus_bus_get(DBUS_BUS_SYSTEM, &error); + dbus_error_free(&error); + if (!iface->con) { + perror("dbus_bus_get[ctrl_iface_dbus]"); + wpa_printf(MSG_ERROR, "Could not acquire the system bus."); + goto fail; + } + + /* Tell dbus about our mainloop integration functions */ + if (integrate_with_eloop(iface->con, iface)) + goto fail; + + /* Register the message handler for the global dbus interface */ + if (!dbus_connection_register_object_path(iface->con, + WPAS_DBUS_PATH, &wpas_vtable, + iface)) { + perror("dbus_connection_register_object_path[dbus]"); + wpa_printf(MSG_ERROR, "Could not set up DBus message " + "handler."); + goto fail; + } + + /* Register our service with the message bus */ + dbus_error_init(&error); + switch (dbus_bus_request_name(iface->con, WPAS_DBUS_SERVICE, + 0, &error)) { + case DBUS_REQUEST_NAME_REPLY_PRIMARY_OWNER: + ret = 0; + break; + case DBUS_REQUEST_NAME_REPLY_EXISTS: + case DBUS_REQUEST_NAME_REPLY_IN_QUEUE: + case DBUS_REQUEST_NAME_REPLY_ALREADY_OWNER: + perror("dbus_bus_request_name[dbus]"); + wpa_printf(MSG_ERROR, "Could not request DBus service name: " + "already registered."); + break; + default: + perror("dbus_bus_request_name[dbus]"); + wpa_printf(MSG_ERROR, "Could not request DBus service name: " + "%s %s.", error.name, error.message); + break; + } + dbus_error_free(&error); + + if (ret != 0) + goto fail; + + wpa_printf(MSG_DEBUG, "Providing DBus service '" WPAS_DBUS_SERVICE + "'."); + + /* + * Dispatch initial DBus messages that may have come in since the bus + * name was claimed above. Happens when clients are quick to notice the + * wpa_supplicant service. + * + * FIXME: is there a better solution to this problem? + */ + eloop_register_timeout(0, 50, dispatch_initial_dbus_messages, + iface->con, NULL); + + return iface; + +fail: + wpa_supplicant_dbus_ctrl_iface_deinit(iface); + return NULL; +} + + +/** + * wpa_supplicant_dbus_ctrl_iface_deinit - Deinitialize dbus ctrl interface + * @iface: Pointer to dbus private data from + * wpa_supplicant_dbus_ctrl_iface_init() + * + * Deinitialize the dbus control interface that was initialized with + * wpa_supplicant_dbus_ctrl_iface_init(). + */ +void wpa_supplicant_dbus_ctrl_iface_deinit(struct ctrl_iface_dbus_priv *iface) +{ + if (iface == NULL) + return; + + if (iface->con) { + eloop_cancel_timeout(dispatch_initial_dbus_messages, + iface->con, NULL); + dbus_connection_set_watch_functions(iface->con, NULL, NULL, + NULL, NULL, NULL); + dbus_connection_set_timeout_functions(iface->con, NULL, NULL, + NULL, NULL, NULL); + dbus_connection_unref(iface->con); + } + + memset(iface, 0, sizeof(struct ctrl_iface_dbus_priv)); + free(iface); +} + + +/** + * wpas_dbus_register_new_iface - Register a new interface with dbus + * @global: Global %wpa_supplicant data + * @wpa_s: %wpa_supplicant interface description structure to register + * Returns: 0 on success, -1 on error + * + * Registers a new interface with dbus and assigns it a dbus object path. + */ +int wpas_dbus_register_iface(struct wpa_supplicant *wpa_s) +{ + struct ctrl_iface_dbus_priv *ctrl_iface = + wpa_s->global->dbus_ctrl_iface; + DBusConnection * con; + u32 next; + DBusObjectPathVTable vtable = { + NULL, &wpas_iface_message_handler, NULL, NULL, NULL, NULL + }; + char *path; + int ret = -1; + + /* Do nothing if the control interface is not turned on */ + if (ctrl_iface == NULL) + return 0; + + con = ctrl_iface->con; + next = wpa_supplicant_dbus_next_objid(ctrl_iface); + + /* Create and set the interface's object path */ + path = wpa_zalloc(WPAS_DBUS_OBJECT_PATH_MAX); + if (path == NULL) + return -1; + snprintf(path, WPAS_DBUS_OBJECT_PATH_MAX, + WPAS_DBUS_PATH_INTERFACES "/%u", + next); + if (wpa_supplicant_set_dbus_path(wpa_s, path)) { + wpa_printf(MSG_DEBUG, + "Failed to set dbus path for interface %s", + wpa_s->ifname); + goto out; + } + + /* Register the message handler for the interface functions */ + if (!dbus_connection_register_fallback(con, path, &vtable, wpa_s)) { + perror("wpas_dbus_register_iface [dbus]"); + wpa_printf(MSG_ERROR, "Could not set up DBus message " + "handler for interface %s.", wpa_s->ifname); + goto out; + } + ret = 0; + +out: + free(path); + return ret; +} + + +/** + * wpas_dbus_unregister_iface - Unregister an interface from dbus + * @wpa_s: wpa_supplicant interface structure + * Returns: 0 on success, -1 on failure + * + * Unregisters the interface with dbus + */ +int wpas_dbus_unregister_iface(struct wpa_supplicant *wpa_s) +{ + struct ctrl_iface_dbus_priv *ctrl_iface; + DBusConnection *con; + const char *path; + + /* Do nothing if the control interface is not turned on */ + if (wpa_s == NULL || wpa_s->global == NULL) + return 0; + ctrl_iface = wpa_s->global->dbus_ctrl_iface; + if (ctrl_iface == NULL) + return 0; + + con = ctrl_iface->con; + path = wpa_supplicant_get_dbus_path(wpa_s); + + if (!dbus_connection_unregister_object_path(con, path)) + return -1; + + free(wpa_s->dbus_path); + wpa_s->dbus_path = NULL; + + return 0; +} + + +/** + * wpa_supplicant_get_iface_by_dbus_path - Get a new network interface + * @global: Pointer to global data from wpa_supplicant_init() + * @path: Pointer to a dbus object path representing an interface + * Returns: Pointer to the interface or %NULL if not found + */ +struct wpa_supplicant * wpa_supplicant_get_iface_by_dbus_path( + struct wpa_global *global, const char *path) +{ + struct wpa_supplicant *wpa_s; + + for (wpa_s = global->ifaces; wpa_s; wpa_s = wpa_s->next) { + if (strcmp(wpa_s->dbus_path, path) == 0) + return wpa_s; + } + return NULL; +} + + +/** + * wpa_supplicant_set_dbus_path - Assign a dbus path to an interface + * @wpa_s: wpa_supplicant interface structure + * @path: dbus path to set on the interface + * Returns: 0 on succes, -1 on error + */ +int wpa_supplicant_set_dbus_path(struct wpa_supplicant *wpa_s, + const char *path) +{ + u32 len = strlen (path); + if (len >= WPAS_DBUS_OBJECT_PATH_MAX) + return -1; + if (wpa_s->dbus_path) + return -1; + wpa_s->dbus_path = strdup(path); + return 0; +} + + +/** + * wpa_supplicant_get_dbus_path - Get an interface's dbus path + * @wpa_s: %wpa_supplicant interface structure + * Returns: Interface's dbus object path, or %NULL on error + */ +const char * wpa_supplicant_get_dbus_path(struct wpa_supplicant *wpa_s) +{ + return wpa_s->dbus_path; +} diff --git a/contrib/wpa_supplicant/ctrl_iface_dbus.h b/contrib/wpa_supplicant/ctrl_iface_dbus.h new file mode 100644 index 000000000000..b66c179c596e --- /dev/null +++ b/contrib/wpa_supplicant/ctrl_iface_dbus.h @@ -0,0 +1,146 @@ +/* + * WPA Supplicant / dbus-based control interface + * Copyright (c) 2006, Dan Williams <dcbw@redhat.com> and Red Hat, Inc. + * + * 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. + */ + +#ifndef CTRL_IFACE_DBUS_H +#define CTRL_IFACE_DBUS_H + +#ifdef CONFIG_CTRL_IFACE_DBUS + +#ifndef SIGPOLL +#ifdef SIGIO +/* + * If we do not have SIGPOLL, try to use SIGIO instead. This is needed for + * FreeBSD. + */ +#define SIGPOLL SIGIO +#endif +#endif + +#include <dbus/dbus.h> + +#define WPAS_DBUS_OBJECT_PATH_MAX 150 + +#define WPAS_DBUS_SERVICE "fi.epitest.hostap.WPASupplicant" +#define WPAS_DBUS_PATH "/fi/epitest/hostap/WPASupplicant" +#define WPAS_DBUS_INTERFACE "fi.epitest.hostap.WPASupplicant" + +#define WPAS_DBUS_PATH_INTERFACES WPAS_DBUS_PATH "/Interfaces" +#define WPAS_DBUS_IFACE_INTERFACE WPAS_DBUS_INTERFACE ".Interface" + +#define WPAS_DBUS_NETWORKS_PART "Networks" +#define WPAS_DBUS_IFACE_NETWORK WPAS_DBUS_INTERFACE ".Network" + +#define WPAS_DBUS_BSSIDS_PART "BSSIDs" +#define WPAS_DBUS_IFACE_BSSID WPAS_DBUS_INTERFACE ".BSSID" + + +/* Errors */ +#define WPAS_ERROR_INVALID_NETWORK \ + WPAS_DBUS_IFACE_INTERFACE ".InvalidNetwork" +#define WPAS_ERROR_INVALID_BSSID \ + WPAS_DBUS_IFACE_INTERFACE ".InvalidBSSID" + +#define WPAS_ERROR_INVALID_OPTS \ + WPAS_DBUS_INTERFACE ".InvalidOptions" +#define WPAS_ERROR_INVALID_IFACE \ + WPAS_DBUS_INTERFACE ".InvalidInterface" + +#define WPAS_ERROR_ADD_ERROR \ + WPAS_DBUS_INTERFACE ".AddError" +#define WPAS_ERROR_EXISTS_ERROR \ + WPAS_DBUS_INTERFACE ".ExistsError" +#define WPAS_ERROR_REMOVE_ERROR \ + WPAS_DBUS_INTERFACE ".RemoveError" + +#define WPAS_ERROR_SCAN_ERROR \ + WPAS_DBUS_IFACE_INTERFACE ".ScanError" +#define WPAS_ERROR_ADD_NETWORK_ERROR \ + WPAS_DBUS_IFACE_INTERFACE ".AddNetworkError" +#define WPAS_ERROR_INTERNAL_ERROR \ + WPAS_DBUS_IFACE_INTERFACE ".InternalError" +#define WPAS_ERROR_REMOVE_NETWORK_ERROR \ + WPAS_DBUS_IFACE_INTERFACE ".RemoveNetworkError" + +#define WPAS_DBUS_BSSID_FORMAT "%02x%02x%02x%02x%02x%02x" + +struct wpa_global; +struct wpa_supplicant; + +struct ctrl_iface_dbus_priv * +wpa_supplicant_dbus_ctrl_iface_init(struct wpa_global *global); +void wpa_supplicant_dbus_ctrl_iface_deinit(struct ctrl_iface_dbus_priv *iface); +void wpa_supplicant_dbus_notify_scan_results(struct wpa_supplicant *wpa_s); +void wpa_supplicant_dbus_notify_state_change(struct wpa_supplicant *wpa_s, + wpa_states new_state, + wpa_states old_state); + +char * wpas_dbus_decompose_object_path(const char *path, char **network, + char **bssid); + +int wpas_dbus_register_iface(struct wpa_supplicant *wpa_s); +int wpas_dbus_unregister_iface(struct wpa_supplicant *wpa_s); + + +/* Methods internal to the dbus control interface */ +u32 wpa_supplicant_dbus_next_objid(struct ctrl_iface_dbus_priv *iface); + +int wpa_supplicant_set_dbus_path(struct wpa_supplicant *wpa_s, + const char *path); +const char *wpa_supplicant_get_dbus_path(struct wpa_supplicant *wpa_s); +struct wpa_supplicant * wpa_supplicant_get_iface_by_dbus_path( + struct wpa_global *global, const char *path); + +DBusMessage * wpas_dbus_new_invalid_iface_error(DBusMessage *message); +DBusMessage * wpas_dbus_new_invalid_network_error(DBusMessage *message); + +#else /* CONFIG_CTRL_IFACE_DBUS */ + +static inline struct ctrl_iface_dbus_priv * +wpa_supplicant_dbus_ctrl_iface_init(struct wpa_global *global) +{ + return (struct ctrl_iface_dbus_priv *) 1; +} + +static inline void +wpa_supplicant_dbus_ctrl_iface_deinit(struct ctrl_iface_dbus_priv *iface) +{ +} + +static inline void +wpa_supplicant_dbus_notify_scan_results(struct wpa_supplicant *wpa_s) +{ +} + +static inline void +wpa_supplicant_dbus_notify_state_change(struct wpa_supplicant *wpa_s, + wpa_states new_state, + wpa_states old_state) +{ +} + +static inline int +wpas_dbus_register_iface(struct wpa_supplicant *wpa_s) +{ + return 0; +} + +static inline int +wpas_dbus_unregister_iface(struct wpa_supplicant *wpa_s) +{ + return 0; +} + +#endif /* CONFIG_CTRL_IFACE_DBUS */ + +#endif /* CTRL_IFACE_DBUS_H */ diff --git a/contrib/wpa_supplicant/ctrl_iface_dbus_handlers.c b/contrib/wpa_supplicant/ctrl_iface_dbus_handlers.c new file mode 100644 index 000000000000..5e952ec5ffa9 --- /dev/null +++ b/contrib/wpa_supplicant/ctrl_iface_dbus_handlers.c @@ -0,0 +1,1205 @@ +/* + * WPA Supplicant / dbus-based control interface + * Copyright (c) 2006, Dan Williams <dcbw@redhat.com> and Red Hat, Inc. + * + * 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 "includes.h" + +#include <dbus/dbus.h> + +#include "common.h" +#include "config.h" +#include "wpa_supplicant_i.h" +#include "ctrl_iface_dbus.h" +#include "ctrl_iface_dbus_handlers.h" +#include "l2_packet.h" +#include "eap_methods.h" +#include "dbus_dict_helpers.h" +#include "wpa.h" + + +/** + * wpas_dbus_new_invalid_opts_error - Return a new invalid options error message + * @message: Pointer to incoming dbus message this error refers to + * Returns: a dbus error message + * + * Convenience function to create and return an invalid options error + */ +static DBusMessage * wpas_dbus_new_invalid_opts_error(DBusMessage *message, + const char *arg) +{ + DBusMessage *reply; + + reply = dbus_message_new_error(message, WPAS_ERROR_INVALID_OPTS, + "Did not receive correct message " + "arguments."); + if (arg != NULL) + dbus_message_append_args(reply, DBUS_TYPE_STRING, &arg, + DBUS_TYPE_INVALID); + + return reply; +} + + +/** + * wpas_dbus_new_success_reply - Return a new success reply message + * @message: Pointer to incoming dbus message this reply refers to + * Returns: a dbus message containing a single UINT32 that indicates + * success (ie, a value of 1) + * + * Convenience function to create and return a success reply message + */ +static DBusMessage * wpas_dbus_new_success_reply(DBusMessage *message) +{ + DBusMessage *reply; + unsigned int success = 1; + + reply = dbus_message_new_method_return(message); + dbus_message_append_args(reply, DBUS_TYPE_UINT32, &success, + DBUS_TYPE_INVALID); + return reply; +} + + +static void wpas_dbus_free_wpa_interface(struct wpa_interface *iface) +{ + free((char *) iface->driver); + free((char *) iface->driver_param); + free((char *) iface->confname); + free((char *) iface->bridge_ifname); +} + + +/** + * wpas_dbus_global_add_interface - Request registration of a network interface + * @message: Pointer to incoming dbus message + * @global: %wpa_supplicant global data structure + * Returns: The object path of the new interface object, + * or a dbus error message with more information + * + * Handler function for "addInterface" method call. Handles requests + * by dbus clients to register a network interface that wpa_supplicant + * will manage. + */ +DBusMessage * wpas_dbus_global_add_interface(DBusMessage *message, + struct wpa_global *global) +{ + struct wpa_interface iface; + char *ifname = NULL; + DBusMessage *reply = NULL; + DBusMessageIter iter; + + memset(&iface, 0, sizeof(iface)); + + dbus_message_iter_init(message, &iter); + + /* First argument: interface name (DBUS_TYPE_STRING) + * Required; must be non-zero length + */ + if (dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_STRING) + goto error; + dbus_message_iter_get_basic(&iter, &ifname); + if (!strlen(ifname)) + goto error; + iface.ifname = ifname; + + /* Second argument: dict of options */ + if (dbus_message_iter_next(&iter)) { + DBusMessageIter iter_dict; + struct wpa_dbus_dict_entry entry; + + if (!wpa_dbus_dict_open_read(&iter, &iter_dict)) + goto error; + while (wpa_dbus_dict_has_dict_entry(&iter_dict)) { + if (!wpa_dbus_dict_get_entry(&iter_dict, &entry)) + goto error; + if (!strcmp(entry.key, "driver") && + (entry.type == DBUS_TYPE_STRING)) { + iface.driver = strdup(entry.str_value); + if (iface.driver == NULL) + goto error; + } else if (!strcmp(entry.key, "driver-params") && + (entry.type == DBUS_TYPE_STRING)) { + iface.driver_param = strdup(entry.str_value); + if (iface.driver_param == NULL) + goto error; + } else if (!strcmp(entry.key, "config-file") && + (entry.type == DBUS_TYPE_STRING)) { + iface.confname = strdup(entry.str_value); + if (iface.confname == NULL) + goto error; + } else if (!strcmp(entry.key, "bridge-ifname") && + (entry.type == DBUS_TYPE_STRING)) { + iface.bridge_ifname = strdup(entry.str_value); + if (iface.bridge_ifname == NULL) + goto error; + } else { + wpa_dbus_dict_entry_clear(&entry); + goto error; + } + wpa_dbus_dict_entry_clear(&entry); + } + } + + /* + * Try to get the wpa_supplicant record for this iface, return + * an error if we already control it. + */ + if (wpa_supplicant_get_iface(global, iface.ifname) != 0) { + reply = dbus_message_new_error(message, + WPAS_ERROR_EXISTS_ERROR, + "wpa_supplicant already " + "controls this interface."); + } else { + struct wpa_supplicant *wpa_s; + /* Otherwise, have wpa_supplicant attach to it. */ + if ((wpa_s = wpa_supplicant_add_iface(global, &iface))) { + const char *path = wpa_supplicant_get_dbus_path(wpa_s); + reply = dbus_message_new_method_return(message); + dbus_message_append_args(reply, DBUS_TYPE_OBJECT_PATH, + &path, DBUS_TYPE_INVALID); + } else { + reply = dbus_message_new_error(message, + WPAS_ERROR_ADD_ERROR, + "wpa_supplicant " + "couldn't grab this " + "interface."); + } + } + wpas_dbus_free_wpa_interface(&iface); + return reply; + +error: + wpas_dbus_free_wpa_interface(&iface); + return wpas_dbus_new_invalid_opts_error(message, NULL); +} + + +/** + * wpas_dbus_global_remove_interface - Request deregistration of an interface + * @message: Pointer to incoming dbus message + * @global: wpa_supplicant global data structure + * Returns: a dbus message containing a UINT32 indicating success (1) or + * failure (0), or returns a dbus error message with more information + * + * Handler function for "removeInterface" method call. Handles requests + * by dbus clients to deregister a network interface that wpa_supplicant + * currently manages. + */ +DBusMessage * wpas_dbus_global_remove_interface(DBusMessage *message, + struct wpa_global *global) +{ + struct wpa_supplicant *wpa_s; + char *path; + DBusMessage *reply = NULL; + + if (!dbus_message_get_args(message, NULL, + DBUS_TYPE_OBJECT_PATH, &path, + DBUS_TYPE_INVALID)) { + reply = wpas_dbus_new_invalid_opts_error(message, NULL); + goto out; + } + + wpa_s = wpa_supplicant_get_iface_by_dbus_path(global, path); + if (wpa_s == NULL) { + reply = wpas_dbus_new_invalid_iface_error(message); + goto out; + } + + if (!wpa_supplicant_remove_iface(global, wpa_s)) { + reply = wpas_dbus_new_success_reply(message); + } else { + reply = dbus_message_new_error(message, + WPAS_ERROR_REMOVE_ERROR, + "wpa_supplicant couldn't " + "remove this interface."); + } + +out: + return reply; +} + + +/** + * wpas_dbus_global_get_interface - Get the object path for an interface name + * @message: Pointer to incoming dbus message + * @global: %wpa_supplicant global data structure + * Returns: The object path of the interface object, + * or a dbus error message with more information + * + * Handler function for "getInterface" method call. Handles requests + * by dbus clients for the object path of an specific network interface. + */ +DBusMessage * wpas_dbus_global_get_interface(DBusMessage *message, + struct wpa_global *global) +{ + DBusMessage *reply = NULL; + const char *ifname; + const char *path; + struct wpa_supplicant *wpa_s; + + if (!dbus_message_get_args(message, NULL, + DBUS_TYPE_STRING, &ifname, + DBUS_TYPE_INVALID)) { + reply = wpas_dbus_new_invalid_opts_error(message, NULL); + goto out; + } + + wpa_s = wpa_supplicant_get_iface(global, ifname); + if (wpa_s == NULL) { + reply = wpas_dbus_new_invalid_iface_error(message); + goto out; + } + + path = wpa_supplicant_get_dbus_path(wpa_s); + if (path == NULL) { + reply = dbus_message_new_error(message, + WPAS_ERROR_INTERNAL_ERROR, + "an internal error occurred " + "getting the interface."); + goto out; + } + + reply = dbus_message_new_method_return(message); + dbus_message_append_args(reply, + DBUS_TYPE_OBJECT_PATH, &path, + DBUS_TYPE_INVALID); + +out: + return reply; +} + + +/** + * wpas_dbus_iface_scan - Request a wireless scan on an interface + * @message: Pointer to incoming dbus message + * @wpa_s: wpa_supplicant structure for a network interface + * Returns: a dbus message containing a UINT32 indicating success (1) or + * failure (0) + * + * Handler function for "scan" method call of a network device. Requests + * that wpa_supplicant perform a wireless scan as soon as possible + * on a particular wireless interface. + */ +DBusMessage * wpas_dbus_iface_scan(DBusMessage *message, + struct wpa_supplicant *wpa_s) +{ + wpa_s->scan_req = 2; + wpa_supplicant_req_scan(wpa_s, 0, 0); + return wpas_dbus_new_success_reply(message); +} + + +/** + * wpas_dbus_iface_scan_results - Get the results of a recent scan request + * @message: Pointer to incoming dbus message + * @wpa_s: wpa_supplicant structure for a network interface + * Returns: a dbus message containing a dbus array of objects paths, or returns + * a dbus error message if not scan results could be found + * + * Handler function for "scanResults" method call of a network device. Returns + * a dbus message containing the object paths of wireless networks found. + */ +DBusMessage * wpas_dbus_iface_scan_results(DBusMessage *message, + struct wpa_supplicant *wpa_s) +{ + DBusMessage *reply = NULL; + DBusMessageIter iter; + DBusMessageIter sub_iter; + int i; + + /* Ensure we've actually got scan results to return */ + if (wpa_s->scan_results == NULL && + wpa_supplicant_get_scan_results(wpa_s) < 0) { + reply = dbus_message_new_error(message, WPAS_ERROR_SCAN_ERROR, + "An error ocurred getting scan " + "results."); + goto out; + } + + /* Create and initialize the return message */ + reply = dbus_message_new_method_return(message); + dbus_message_iter_init_append(reply, &iter); + dbus_message_iter_open_container(&iter, DBUS_TYPE_ARRAY, + DBUS_TYPE_OBJECT_PATH_AS_STRING, + &sub_iter); + + /* Loop through scan results and append each result's object path */ + for (i = 0; i < wpa_s->num_scan_results; i++) { + struct wpa_scan_result *res = &wpa_s->scan_results[i]; + char *path; + + path = wpa_zalloc(WPAS_DBUS_OBJECT_PATH_MAX); + if (path == NULL) { + perror("wpas_dbus_iface_scan_results[dbus]: out of " + "memory."); + wpa_printf(MSG_ERROR, "dbus control interface: not " + "enough memory to send scan results " + "signal."); + break; + } + /* Construct the object path for this network. Note that ':' + * is not a valid character in dbus object paths. + */ + snprintf(path, WPAS_DBUS_OBJECT_PATH_MAX, + "%s/" WPAS_DBUS_BSSIDS_PART "/" + WPAS_DBUS_BSSID_FORMAT, + wpa_supplicant_get_dbus_path(wpa_s), + MAC2STR(res->bssid)); + dbus_message_iter_append_basic(&sub_iter, + DBUS_TYPE_OBJECT_PATH, &path); + free(path); + } + + dbus_message_iter_close_container(&iter, &sub_iter); + +out: + return reply; +} + + +/** + * wpas_dbus_bssid_properties - Return the properties of a scanned network + * @message: Pointer to incoming dbus message + * @wpa_s: wpa_supplicant structure for a network interface + * @res: wpa_supplicant scan result for which to get properties + * Returns: a dbus message containing the properties for the requested network + * + * Handler function for "properties" method call of a scanned network. + * Returns a dbus message containing the the properties. + */ +DBusMessage * wpas_dbus_bssid_properties(DBusMessage *message, + struct wpa_supplicant *wpa_s, + struct wpa_scan_result *res) +{ + DBusMessage *reply = NULL; + char *bssid_data, *ssid_data, *wpa_ie_data, *rsn_ie_data; + DBusMessageIter iter, iter_dict; + + /* dbus needs the address of a pointer to the actual value + * for array types, not the address of the value itself. + */ + bssid_data = (char *) &res->bssid; + ssid_data = (char *) &res->ssid; + wpa_ie_data = (char *) &res->wpa_ie; + rsn_ie_data = (char *) &res->rsn_ie; + + /* Dump the properties into a dbus message */ + reply = dbus_message_new_method_return(message); + + dbus_message_iter_init_append(reply, &iter); + if (!wpa_dbus_dict_open_write(&iter, &iter_dict)) + goto error; + + if (!wpa_dbus_dict_append_byte_array(&iter_dict, "bssid", + bssid_data, ETH_ALEN)) + goto error; + if (!wpa_dbus_dict_append_byte_array(&iter_dict, "ssid", + ssid_data, res->ssid_len)) + goto error; + if (res->wpa_ie_len) { + if (!wpa_dbus_dict_append_byte_array(&iter_dict, "wpaie", + wpa_ie_data, + res->wpa_ie_len)) { + goto error; + } + } + if (res->rsn_ie_len) { + if (!wpa_dbus_dict_append_byte_array(&iter_dict, "rsnie", + rsn_ie_data, + res->rsn_ie_len)) { + goto error; + } + } + if (res->freq) { + if (!wpa_dbus_dict_append_int32(&iter_dict, "frequency", + res->freq)) + goto error; + } + if (!wpa_dbus_dict_append_uint16(&iter_dict, "capabilities", + res->caps)) + goto error; + if (!wpa_dbus_dict_append_int32(&iter_dict, "quality", res->qual)) + goto error; + if (!wpa_dbus_dict_append_int32(&iter_dict, "noise", res->noise)) + goto error; + if (!wpa_dbus_dict_append_int32(&iter_dict, "level", res->level)) + goto error; + if (!wpa_dbus_dict_append_int32(&iter_dict, "maxrate", res->maxrate)) + goto error; + + if (!wpa_dbus_dict_close_write(&iter, &iter_dict)) + goto error; + + return reply; + +error: + if (reply) + dbus_message_unref(reply); + return dbus_message_new_error(message, WPAS_ERROR_INTERNAL_ERROR, + "an internal error occurred returning " + "BSSID properties."); +} + + +/** + * wpas_dbus_iface_capabilities - Return interface capabilities + * @message: Pointer to incoming dbus message + * @wpa_s: wpa_supplicant structure for a network interface + * Returns: A dbus message containing a dict of strings + * + * Handler function for "capabilities" method call of an interface. + */ +DBusMessage * wpas_dbus_iface_capabilities(DBusMessage *message, + struct wpa_supplicant *wpa_s) +{ + DBusMessage *reply = NULL; + struct wpa_driver_capa capa; + int res; + DBusMessageIter iter, iter_dict; + char **eap_methods; + size_t num_items; + dbus_bool_t strict = FALSE; + DBusMessageIter iter_dict_entry, iter_dict_val, iter_array; + + if (!dbus_message_get_args(message, NULL, + DBUS_TYPE_BOOLEAN, &strict, + DBUS_TYPE_INVALID)) + strict = FALSE; + + reply = dbus_message_new_method_return(message); + + dbus_message_iter_init_append(reply, &iter); + if (!wpa_dbus_dict_open_write(&iter, &iter_dict)) + goto error; + + /* EAP methods */ + eap_methods = eap_get_names_as_string_array(&num_items); + if (eap_methods) { + dbus_bool_t success = FALSE; + size_t i = 0; + + success = wpa_dbus_dict_append_string_array( + &iter_dict, "eap", (const char **) eap_methods, + num_items); + + /* free returned method array */ + while (eap_methods[i]) + free(eap_methods[i++]); + free(eap_methods); + + if (!success) + goto error; + } + + res = wpa_drv_get_capa(wpa_s, &capa); + + /***** pairwise cipher */ + if (res < 0) { + if (!strict) { + const char *args[] = {"CCMP", "TKIP", "NONE"}; + if (!wpa_dbus_dict_append_string_array( + &iter_dict, "pairwise", args, + sizeof(args) / sizeof(char*))) + goto error; + } + } else { + if (!wpa_dbus_dict_begin_string_array(&iter_dict, "pairwise", + &iter_dict_entry, + &iter_dict_val, + &iter_array)) + goto error; + + if (capa.enc & WPA_DRIVER_CAPA_ENC_CCMP) { + if (!wpa_dbus_dict_string_array_add_element( + &iter_array, "CCMP")) + goto error; + } + + if (capa.enc & WPA_DRIVER_CAPA_ENC_TKIP) { + if (!wpa_dbus_dict_string_array_add_element( + &iter_array, "TKIP")) + goto error; + } + + if (capa.key_mgmt & WPA_DRIVER_CAPA_KEY_MGMT_WPA_NONE) { + if (!wpa_dbus_dict_string_array_add_element( + &iter_array, "NONE")) + goto error; + } + + if (!wpa_dbus_dict_end_string_array(&iter_dict, + &iter_dict_entry, + &iter_dict_val, + &iter_array)) + goto error; + } + + /***** group cipher */ + if (res < 0) { + if (!strict) { + const char *args[] = { + "CCMP", "TKIP", "WEP104", "WEP40" + }; + if (!wpa_dbus_dict_append_string_array( + &iter_dict, "group", args, + sizeof(args) / sizeof(char*))) + goto error; + } + } else { + if (!wpa_dbus_dict_begin_string_array(&iter_dict, "group", + &iter_dict_entry, + &iter_dict_val, + &iter_array)) + goto error; + + if (capa.enc & WPA_DRIVER_CAPA_ENC_CCMP) { + if (!wpa_dbus_dict_string_array_add_element( + &iter_array, "CCMP")) + goto error; + } + + if (capa.enc & WPA_DRIVER_CAPA_ENC_TKIP) { + if (!wpa_dbus_dict_string_array_add_element( + &iter_array, "TKIP")) + goto error; + } + + if (capa.enc & WPA_DRIVER_CAPA_ENC_WEP104) { + if (!wpa_dbus_dict_string_array_add_element( + &iter_array, "WEP104")) + goto error; + } + + if (capa.enc & WPA_DRIVER_CAPA_ENC_WEP40) { + if (!wpa_dbus_dict_string_array_add_element( + &iter_array, "WEP40")) + goto error; + } + + if (!wpa_dbus_dict_end_string_array(&iter_dict, + &iter_dict_entry, + &iter_dict_val, + &iter_array)) + goto error; + } + + /***** key management */ + if (res < 0) { + if (!strict) { + const char *args[] = { + "WPA-PSK", "WPA-EAP", "IEEE8021X", "WPA-NONE", + "NONE" + }; + if (!wpa_dbus_dict_append_string_array( + &iter_dict, "key_mgmt", args, + sizeof(args) / sizeof(char*))) + goto error; + } + } else { + if (!wpa_dbus_dict_begin_string_array(&iter_dict, "key_mgmt", + &iter_dict_entry, + &iter_dict_val, + &iter_array)) + goto error; + + if (!wpa_dbus_dict_string_array_add_element(&iter_array, + "NONE")) + goto error; + + if (!wpa_dbus_dict_string_array_add_element(&iter_array, + "IEEE8021X")) + goto error; + + if (capa.key_mgmt & (WPA_DRIVER_CAPA_KEY_MGMT_WPA | + WPA_DRIVER_CAPA_KEY_MGMT_WPA2)) { + if (!wpa_dbus_dict_string_array_add_element( + &iter_array, "WPA-EAP")) + goto error; + } + + if (capa.key_mgmt & (WPA_DRIVER_CAPA_KEY_MGMT_WPA_PSK | + WPA_DRIVER_CAPA_KEY_MGMT_WPA2_PSK)) { + if (!wpa_dbus_dict_string_array_add_element( + &iter_array, "WPA-PSK")) + goto error; + } + + if (capa.key_mgmt & WPA_DRIVER_CAPA_KEY_MGMT_WPA_NONE) { + if (!wpa_dbus_dict_string_array_add_element( + &iter_array, "WPA-NONE")) + goto error; + } + + if (!wpa_dbus_dict_end_string_array(&iter_dict, + &iter_dict_entry, + &iter_dict_val, + &iter_array)) + goto error; + } + + /***** WPA protocol */ + if (res < 0) { + if (!strict) { + const char *args[] = { "RSN", "WPA" }; + if (!wpa_dbus_dict_append_string_array( + &iter_dict, "proto", args, + sizeof(args) / sizeof(char*))) + goto error; + } + } else { + if (!wpa_dbus_dict_begin_string_array(&iter_dict, "proto", + &iter_dict_entry, + &iter_dict_val, + &iter_array)) + goto error; + + if (capa.key_mgmt & (WPA_DRIVER_CAPA_KEY_MGMT_WPA2 | + WPA_DRIVER_CAPA_KEY_MGMT_WPA2_PSK)) { + if (!wpa_dbus_dict_string_array_add_element( + &iter_array, "RSN")) + goto error; + } + + if (capa.key_mgmt & (WPA_DRIVER_CAPA_KEY_MGMT_WPA | + WPA_DRIVER_CAPA_KEY_MGMT_WPA_PSK)) { + if (!wpa_dbus_dict_string_array_add_element( + &iter_array, "WPA")) + goto error; + } + + if (!wpa_dbus_dict_end_string_array(&iter_dict, + &iter_dict_entry, + &iter_dict_val, + &iter_array)) + goto error; + } + + /***** auth alg */ + if (res < 0) { + if (!strict) { + const char *args[] = { "OPEN", "SHARED", "LEAP" }; + if (!wpa_dbus_dict_append_string_array( + &iter_dict, "auth_alg", args, + sizeof(args) / sizeof(char*))) + goto error; + } + } else { + if (!wpa_dbus_dict_begin_string_array(&iter_dict, "auth_alg", + &iter_dict_entry, + &iter_dict_val, + &iter_array)) + goto error; + + if (capa.auth & (WPA_DRIVER_AUTH_OPEN)) { + if (!wpa_dbus_dict_string_array_add_element( + &iter_array, "OPEN")) + goto error; + } + + if (capa.auth & (WPA_DRIVER_AUTH_SHARED)) { + if (!wpa_dbus_dict_string_array_add_element( + &iter_array, "SHARED")) + goto error; + } + + if (capa.auth & (WPA_DRIVER_AUTH_LEAP)) { + if (!wpa_dbus_dict_string_array_add_element( + &iter_array, "LEAP")) + goto error; + } + + if (!wpa_dbus_dict_end_string_array(&iter_dict, + &iter_dict_entry, + &iter_dict_val, + &iter_array)) + goto error; + } + + if (!wpa_dbus_dict_close_write(&iter, &iter_dict)) + goto error; + + return reply; + +error: + if (reply) + dbus_message_unref(reply); + return dbus_message_new_error(message, WPAS_ERROR_INTERNAL_ERROR, + "an internal error occurred returning " + "interface capabilities."); +} + + +/** + * wpas_dbus_iface_add_network - Add a new configured network + * @message: Pointer to incoming dbus message + * @wpa_s: wpa_supplicant structure for a network interface + * Returns: A dbus message containing the object path of the new network + * + * Handler function for "addNetwork" method call of a network interface. + */ +DBusMessage * wpas_dbus_iface_add_network(DBusMessage *message, + struct wpa_supplicant *wpa_s) +{ + DBusMessage *reply = NULL; + struct wpa_ssid *ssid; + char *path = NULL; + + path = wpa_zalloc(WPAS_DBUS_OBJECT_PATH_MAX); + if (path == NULL) { + perror("wpas_dbus_iface_scan_results[dbus]: out of " + "memory."); + wpa_printf(MSG_ERROR, "dbus control interface: not " + "enough memory to send scan results " + "signal."); + goto out; + } + + ssid = wpa_config_add_network(wpa_s->conf); + if (ssid == NULL) { + reply = dbus_message_new_error(message, + WPAS_ERROR_ADD_NETWORK_ERROR, + "wpa_supplicant could not add " + "a network on this interface."); + goto out; + } + ssid->disabled = 1; + wpa_config_set_network_defaults(ssid); + + /* Construct the object path for this network. */ + snprintf(path, WPAS_DBUS_OBJECT_PATH_MAX, + "%s/" WPAS_DBUS_NETWORKS_PART "/%d", + wpa_supplicant_get_dbus_path(wpa_s), + ssid->id); + + reply = dbus_message_new_method_return(message); + dbus_message_append_args(reply, DBUS_TYPE_OBJECT_PATH, + &path, DBUS_TYPE_INVALID); + +out: + free(path); + return reply; +} + + +/** + * wpas_dbus_iface_remove_network - Remove a configured network + * @message: Pointer to incoming dbus message + * @wpa_s: wpa_supplicant structure for a network interface + * Returns: A dbus message containing a UINT32 indicating success (1) or + * failure (0) + * + * Handler function for "removeNetwork" method call of a network interface. + */ +DBusMessage * wpas_dbus_iface_remove_network(DBusMessage *message, + struct wpa_supplicant *wpa_s) +{ + DBusMessage *reply = NULL; + const char *op; + char *iface = NULL, *net_id = NULL; + int id; + struct wpa_ssid *ssid; + + if (!dbus_message_get_args(message, NULL, + DBUS_TYPE_OBJECT_PATH, &op, + DBUS_TYPE_INVALID)) { + reply = wpas_dbus_new_invalid_opts_error(message, NULL); + goto out; + } + + /* Extract the network ID */ + iface = wpas_dbus_decompose_object_path(op, &net_id, NULL); + if (iface == NULL) { + reply = wpas_dbus_new_invalid_network_error(message); + goto out; + } + /* Ensure the network is actually a child of this interface */ + if (strcmp(iface, wpa_supplicant_get_dbus_path(wpa_s)) != 0) { + reply = wpas_dbus_new_invalid_network_error(message); + goto out; + } + + id = strtoul(net_id, NULL, 10); + ssid = wpa_config_get_network(wpa_s->conf, id); + if (ssid == NULL) { + reply = wpas_dbus_new_invalid_network_error(message); + goto out; + } + + if (wpa_config_remove_network(wpa_s->conf, id) < 0) { + reply = dbus_message_new_error(message, + WPAS_ERROR_REMOVE_NETWORK_ERROR, + "error removing the specified " + "on this interface."); + goto out; + } + + if (ssid == wpa_s->current_ssid) + wpa_supplicant_disassociate(wpa_s, REASON_DEAUTH_LEAVING); + reply = wpas_dbus_new_success_reply(message); + +out: + free(iface); + free(net_id); + return reply; +} + + +static const char *dont_quote[] = { + "key_mgmt", "proto", "pairwise", "auth_alg", "group", "eap", + "opensc_engine_path", "pkcs11_engine_path", "pkcs11_module_path", + "bssid", NULL +}; + +static dbus_bool_t should_quote_opt(const char *key) +{ + int i = 0; + while (dont_quote[i] != NULL) { + if (strcmp(key, dont_quote[i]) == 0) + return FALSE; + i++; + } + return TRUE; +} + +/** + * wpas_dbus_iface_set_network - Set options for a configured network + * @message: Pointer to incoming dbus message + * @wpa_s: wpa_supplicant structure for a network interface + * @ssid: wpa_ssid structure for a configured network + * Returns: a dbus message containing a UINT32 indicating success (1) or + * failure (0) + * + * Handler function for "set" method call of a configured network. + */ +DBusMessage * wpas_dbus_iface_set_network(DBusMessage *message, + struct wpa_supplicant *wpa_s, + struct wpa_ssid *ssid) +{ + DBusMessage *reply = NULL; + struct wpa_dbus_dict_entry entry = { .type = DBUS_TYPE_STRING }; + DBusMessageIter iter, iter_dict; + + dbus_message_iter_init(message, &iter); + + if (!wpa_dbus_dict_open_read(&iter, &iter_dict)) { + reply = wpas_dbus_new_invalid_opts_error(message, NULL); + goto out; + } + + while (wpa_dbus_dict_has_dict_entry(&iter_dict)) { + char *value = NULL; + size_t size = 50; + int ret; + + if (!wpa_dbus_dict_get_entry(&iter_dict, &entry)) { + reply = wpas_dbus_new_invalid_opts_error(message, + NULL); + goto out; + } + + /* Type conversions, since wpa_supplicant wants strings */ + if (entry.type == DBUS_TYPE_ARRAY && + entry.array_type == DBUS_TYPE_BYTE) { + if (entry.array_len <= 0) + goto error; + + size = entry.array_len * 2 + 1; + value = wpa_zalloc(size); + if (value == NULL) + goto error; + ret = wpa_snprintf_hex(value, size, + (u8 *) entry.bytearray_value, + entry.array_len); + if (ret <= 0) + goto error; + } else if (entry.type == DBUS_TYPE_STRING) { + if (should_quote_opt(entry.key)) { + size = strlen(entry.str_value); + /* Zero-length option check */ + if (size <= 0) + goto error; + size += 3; /* For quotes and terminator */ + value = wpa_zalloc(size); + if (value == NULL) + goto error; + ret = snprintf(value, size, "\"%s\"", + entry.str_value); + if (ret < 0 || (size_t) ret != (size - 1)) + goto error; + } else { + value = strdup(entry.str_value); + if (value == NULL) + goto error; + } + } else if (entry.type == DBUS_TYPE_UINT32) { + value = wpa_zalloc(size); + if (value == NULL) + goto error; + ret = snprintf(value, size, "%u", entry.uint32_value); + if (ret <= 0) + goto error; + } else if (entry.type == DBUS_TYPE_INT32) { + value = wpa_zalloc(size); + if (value == NULL) + goto error; + ret = snprintf(value, size, "%d", entry.int32_value); + if (ret <= 0) + goto error; + } else + goto error; + + if (wpa_config_set(ssid, entry.key, value, 0) < 0) + goto error; + + if ((strcmp(entry.key, "psk") == 0 && + value[0] == '"' && ssid->ssid_len) || + (strcmp(entry.key, "ssid") == 0 && ssid->passphrase)) + wpa_config_update_psk(ssid); + + free(value); + wpa_dbus_dict_entry_clear(&entry); + continue; + + error: + free(value); + reply = wpas_dbus_new_invalid_opts_error(message, entry.key); + wpa_dbus_dict_entry_clear(&entry); + break; + } + + if (!reply) + reply = wpas_dbus_new_success_reply(message); + +out: + return reply; +} + + +/** + * wpas_dbus_iface_enable_network - Mark a configured network as enabled + * @message: Pointer to incoming dbus message + * @wpa_s: wpa_supplicant structure for a network interface + * @ssid: wpa_ssid structure for a configured network + * Returns: A dbus message containing a UINT32 indicating success (1) or + * failure (0) + * + * Handler function for "enable" method call of a configured network. + */ +DBusMessage * wpas_dbus_iface_enable_network(DBusMessage *message, + struct wpa_supplicant *wpa_s, + struct wpa_ssid *ssid) +{ + if (wpa_s->current_ssid == NULL && ssid->disabled) { + /* + * Try to reassociate since there is no current configuration + * and a new network was made available. + */ + wpa_s->reassociate = 1; + wpa_supplicant_req_scan(wpa_s, 0, 0); + } + ssid->disabled = 0; + + return wpas_dbus_new_success_reply(message); +} + + +/** + * wpas_dbus_iface_disable_network - Mark a configured network as disabled + * @message: Pointer to incoming dbus message + * @wpa_s: wpa_supplicant structure for a network interface + * @ssid: wpa_ssid structure for a configured network + * Returns: A dbus message containing a UINT32 indicating success (1) or + * failure (0) + * + * Handler function for "disable" method call of a configured network. + */ +DBusMessage * wpas_dbus_iface_disable_network(DBusMessage *message, + struct wpa_supplicant *wpa_s, + struct wpa_ssid *ssid) +{ + if (ssid == wpa_s->current_ssid) + wpa_supplicant_disassociate(wpa_s, REASON_DEAUTH_LEAVING); + ssid->disabled = 1; + + return wpas_dbus_new_success_reply(message); +} + + +/** + * wpas_dbus_iface_select_network - Attempt association with a configured network + * @message: Pointer to incoming dbus message + * @wpa_s: wpa_supplicant structure for a network interface + * Returns: A dbus message containing a UINT32 indicating success (1) or + * failure (0) + * + * Handler function for "selectNetwork" method call of network interface. + */ +DBusMessage * wpas_dbus_iface_select_network(DBusMessage *message, + struct wpa_supplicant *wpa_s) +{ + DBusMessage *reply = NULL; + const char *op; + struct wpa_ssid *ssid; + char *iface_obj_path = NULL; + char *network = NULL; + + if (strlen(dbus_message_get_signature(message)) == 0) { + /* Any network */ + ssid = wpa_s->conf->ssid; + while (ssid) { + ssid->disabled = 0; + ssid = ssid->next; + } + wpa_s->reassociate = 1; + wpa_supplicant_req_scan(wpa_s, 0, 0); + } else { + const char *obj_path; + int nid; + + if (!dbus_message_get_args(message, NULL, + DBUS_TYPE_OBJECT_PATH, &op, + DBUS_TYPE_INVALID)) { + reply = wpas_dbus_new_invalid_opts_error(message, + NULL); + goto out; + } + + /* Extract the network number */ + iface_obj_path = wpas_dbus_decompose_object_path(op, + &network, + NULL); + if (iface_obj_path == NULL) { + reply = wpas_dbus_new_invalid_iface_error(message); + goto out; + } + /* Ensure the object path really points to this interface */ + obj_path = wpa_supplicant_get_dbus_path(wpa_s); + if (strcmp(iface_obj_path, obj_path) != 0) { + reply = wpas_dbus_new_invalid_network_error(message); + goto out; + } + + nid = strtoul(network, NULL, 10); + if (errno == EINVAL) { + reply = wpas_dbus_new_invalid_network_error(message); + goto out; + } + + ssid = wpa_config_get_network(wpa_s->conf, nid); + if (ssid == NULL) { + reply = wpas_dbus_new_invalid_network_error(message); + goto out; + } + + /* Finally, associate with the network */ + if (ssid != wpa_s->current_ssid && wpa_s->current_ssid) + wpa_supplicant_disassociate(wpa_s, + REASON_DEAUTH_LEAVING); + + /* Mark all other networks disabled and trigger reassociation + */ + ssid = wpa_s->conf->ssid; + while (ssid) { + ssid->disabled = (nid != ssid->id); + ssid = ssid->next; + } + wpa_s->disconnected = 0; + wpa_s->reassociate = 1; + wpa_supplicant_req_scan(wpa_s, 0, 0); + } + + reply = wpas_dbus_new_success_reply(message); + +out: + free(iface_obj_path); + free(network); + return reply; +} + + +/** + * wpas_dbus_iface_disconnect - Terminate the current connection + * @message: Pointer to incoming dbus message + * @wpa_s: wpa_supplicant structure for a network interface + * Returns: A dbus message containing a UINT32 indicating success (1) or + * failure (0) + * + * Handler function for "disconnect" method call of network interface. + */ +DBusMessage * wpas_dbus_iface_disconnect(DBusMessage *message, + struct wpa_supplicant *wpa_s) +{ + wpa_s->disconnected = 1; + wpa_supplicant_disassociate(wpa_s, REASON_DEAUTH_LEAVING); + + return wpas_dbus_new_success_reply(message); +} + + +/** + * wpas_dbus_iface_set_ap_scan - Control roaming mode + * @message: Pointer to incoming dbus message + * @wpa_s: wpa_supplicant structure for a network interface + * Returns: A dbus message containing a UINT32 indicating success (1) or + * failure (0) + * + * Handler function for "setAPScan" method call. + */ +DBusMessage * wpas_dbus_iface_set_ap_scan(DBusMessage *message, + struct wpa_supplicant *wpa_s) +{ + DBusMessage *reply = NULL; + dbus_uint32_t ap_scan = 1; + + if (!dbus_message_get_args(message, NULL, DBUS_TYPE_UINT32, &ap_scan, + DBUS_TYPE_INVALID)) { + reply = wpas_dbus_new_invalid_opts_error(message, NULL); + goto out; + } + + if (ap_scan > 2) { + reply = wpas_dbus_new_invalid_opts_error(message, NULL); + goto out; + } + wpa_s->conf->ap_scan = ap_scan; + reply = wpas_dbus_new_success_reply(message); + +out: + return reply; +} + + +/** + * wpas_dbus_iface_get_state - Get interface state + * @message: Pointer to incoming dbus message + * @wpa_s: wpa_supplicant structure for a network interface + * Returns: A dbus message containing a STRING representing the current + * interface state + * + * Handler function for "state" method call. + */ +DBusMessage * wpas_dbus_iface_get_state(DBusMessage *message, + struct wpa_supplicant *wpa_s) +{ + DBusMessage *reply = NULL; + const char *str_state; + + reply = dbus_message_new_method_return(message); + if (reply != NULL) { + str_state = wpa_supplicant_state_txt(wpa_s->wpa_state); + dbus_message_append_args(reply, DBUS_TYPE_STRING, &str_state, + DBUS_TYPE_INVALID); + } + + return reply; +} diff --git a/contrib/wpa_supplicant/ctrl_iface_dbus_handlers.h b/contrib/wpa_supplicant/ctrl_iface_dbus_handlers.h new file mode 100644 index 000000000000..0fd1d3164267 --- /dev/null +++ b/contrib/wpa_supplicant/ctrl_iface_dbus_handlers.h @@ -0,0 +1,77 @@ +/* + * WPA Supplicant / dbus-based control interface + * Copyright (c) 2006, Dan Williams <dcbw@redhat.com> and Red Hat, Inc. + * + * 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. + */ + +#ifndef CTRL_IFACE_DBUS_HANDLERS_H +#define CTRL_IFACE_DBUS_HANDLERS_H + +#ifdef CONFIG_CTRL_IFACE_DBUS + +DBusMessage * wpas_dbus_new_invalid_iface_error(DBusMessage *message); + +DBusMessage * wpas_dbus_global_add_interface(DBusMessage *message, + struct wpa_global *global); + +DBusMessage * wpas_dbus_global_remove_interface(DBusMessage *message, + struct wpa_global *global); + +DBusMessage * wpas_dbus_global_get_interface(DBusMessage *message, + struct wpa_global *global); + +DBusMessage * wpas_dbus_iface_scan(DBusMessage *message, + struct wpa_supplicant *wpa_s); + +DBusMessage * wpas_dbus_iface_scan_results(DBusMessage *message, + struct wpa_supplicant *wpa_s); + +DBusMessage * wpas_dbus_bssid_properties(DBusMessage *message, + struct wpa_supplicant *wpa_s, + struct wpa_scan_result *res); + +DBusMessage * wpas_dbus_iface_capabilities(DBusMessage *message, + struct wpa_supplicant *wpa_s); + +DBusMessage * wpas_dbus_iface_add_network(DBusMessage *message, + struct wpa_supplicant *wpa_s); + +DBusMessage * wpas_dbus_iface_remove_network(DBusMessage *message, + struct wpa_supplicant *wpa_s); + +DBusMessage * wpas_dbus_iface_set_network(DBusMessage *message, + struct wpa_supplicant *wpa_s, + struct wpa_ssid *ssid); + +DBusMessage * wpas_dbus_iface_enable_network(DBusMessage *message, + struct wpa_supplicant *wpa_s, + struct wpa_ssid *ssid); + +DBusMessage * wpas_dbus_iface_disable_network(DBusMessage *message, + struct wpa_supplicant *wpa_s, + struct wpa_ssid *ssid); + +DBusMessage * wpas_dbus_iface_select_network(DBusMessage *message, + struct wpa_supplicant *wpa_s); + +DBusMessage * wpas_dbus_iface_disconnect(DBusMessage *message, + struct wpa_supplicant *wpa_s); + +DBusMessage * wpas_dbus_iface_set_ap_scan(DBusMessage *message, + struct wpa_supplicant *wpa_s); + +DBusMessage * wpas_dbus_iface_get_state(DBusMessage *message, + struct wpa_supplicant *wpa_s); + +#endif /* CONFIG_CTRL_IFACE_DBUS */ + +#endif /* CTRL_IFACE_DBUS_HANDLERS_H */ + diff --git a/contrib/wpa_supplicant/ctrl_iface_named_pipe.c b/contrib/wpa_supplicant/ctrl_iface_named_pipe.c new file mode 100644 index 000000000000..5813e089a86c --- /dev/null +++ b/contrib/wpa_supplicant/ctrl_iface_named_pipe.c @@ -0,0 +1,834 @@ +/* + * WPA Supplicant / Windows Named Pipe -based control interface + * Copyright (c) 2004-2006, Jouni Malinen <j@w1.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 "includes.h" + +#include "common.h" +#include "eloop.h" +#include "config.h" +#include "eapol_sm.h" +#include "wpa_supplicant_i.h" +#include "ctrl_iface.h" +#include "wpa_ctrl.h" + +#ifdef __MINGW32_VERSION +/* mingw-w32api v3.1 does not yet include sddl.h, so define needed parts here + */ +#define SDDL_REVISION_1 1 +BOOL WINAPI ConvertStringSecurityDescriptorToSecurityDescriptorA( + LPCSTR, DWORD, PSECURITY_DESCRIPTOR *, PULONG); +BOOL WINAPI ConvertStringSecurityDescriptorToSecurityDescriptorW( + LPCWSTR, DWORD, PSECURITY_DESCRIPTOR *, PULONG); +#ifdef UNICODE +#define ConvertStringSecurityDescriptorToSecurityDescriptor \ +ConvertStringSecurityDescriptorToSecurityDescriptorW +#else +#define ConvertStringSecurityDescriptorToSecurityDescriptor \ +ConvertStringSecurityDescriptorToSecurityDescriptorA +#endif +#else /* __MINGW32_VERSION */ +#ifndef _WIN32_WINNT +#define _WIN32_WINNT 0x0500 +#endif +#include <sddl.h> +#endif /* __MINGW32_VERSION */ + +#ifndef WPA_SUPPLICANT_NAMED_PIPE +#define WPA_SUPPLICANT_NAMED_PIPE "WpaSupplicant" +#endif +#define NAMED_PIPE_PREFIX TEXT("\\\\.\\pipe\\") TEXT(WPA_SUPPLICANT_NAMED_PIPE) + +/* Per-interface ctrl_iface */ + +#define REQUEST_BUFSIZE 256 +#define REPLY_BUFSIZE 4096 + +struct ctrl_iface_priv; + +/** + * struct wpa_ctrl_dst - Internal data structure of control interface clients + * + * This structure is used to store information about registered control + * interface monitors into struct wpa_supplicant. This data is private to + * ctrl_iface_named_pipe.c and should not be touched directly from other files. + */ +struct wpa_ctrl_dst { + /* Note: OVERLAPPED must be the first member of struct wpa_ctrl_dst */ + OVERLAPPED overlap; + struct wpa_ctrl_dst *next, *prev; + struct ctrl_iface_priv *priv; + HANDLE pipe; + int attached; + int debug_level; + int errors; + char req_buf[REQUEST_BUFSIZE]; + char *rsp_buf; + int used; +}; + + +struct ctrl_iface_priv { + struct wpa_supplicant *wpa_s; + struct wpa_ctrl_dst *ctrl_dst; + SECURITY_ATTRIBUTES attr; + int sec_attr_set; +}; + + +static void wpa_supplicant_ctrl_iface_send(struct ctrl_iface_priv *priv, + int level, const char *buf, + size_t len); + +static void ctrl_close_pipe(struct wpa_ctrl_dst *dst); +static void wpa_supplicant_ctrl_iface_receive(void *, void *); +static VOID WINAPI ctrl_iface_read_completed(DWORD err, DWORD bytes, + LPOVERLAPPED overlap); + +struct wpa_global_dst; +static void global_close_pipe(struct wpa_global_dst *dst); +static void wpa_supplicant_global_iface_receive(void *eloop_data, + void *user_ctx); +static VOID WINAPI global_iface_read_completed(DWORD err, DWORD bytes, + LPOVERLAPPED overlap); + + +static int ctrl_broken_pipe(HANDLE pipe, int used) +{ + DWORD err; + + if (PeekNamedPipe(pipe, NULL, 0, NULL, NULL, NULL)) + return 0; + + err = GetLastError(); + if (err == ERROR_BROKEN_PIPE || (err == ERROR_BAD_PIPE && used)) + return 1; + return 0; +} + + +static void ctrl_flush_broken_pipes(struct ctrl_iface_priv *priv) +{ + struct wpa_ctrl_dst *dst, *next; + + dst = priv->ctrl_dst; + + while (dst) { + next = dst->next; + if (ctrl_broken_pipe(dst->pipe, dst->used)) { + wpa_printf(MSG_DEBUG, "CTRL: closing broken pipe %p", + dst); + ctrl_close_pipe(dst); + } + dst = next; + } +} + + +static int ctrl_open_pipe(struct ctrl_iface_priv *priv) +{ + struct wpa_ctrl_dst *dst; + DWORD err; + TCHAR name[256]; + + dst = os_zalloc(sizeof(*dst)); + if (dst == NULL) + return -1; + wpa_printf(MSG_DEBUG, "CTRL: Open pipe %p", dst); + + dst->priv = priv; + dst->debug_level = MSG_INFO; + dst->pipe = INVALID_HANDLE_VALUE; + + dst->overlap.hEvent = CreateEvent(NULL, TRUE, TRUE, NULL); + if (dst->overlap.hEvent == NULL) { + wpa_printf(MSG_ERROR, "CTRL: CreateEvent failed: %d", + (int) GetLastError()); + goto fail; + } + + eloop_register_event(dst->overlap.hEvent, + sizeof(dst->overlap.hEvent), + wpa_supplicant_ctrl_iface_receive, dst, NULL); + +#ifdef UNICODE + _snwprintf(name, 256, NAMED_PIPE_PREFIX TEXT("-%S"), + priv->wpa_s->ifname); +#else /* UNICODE */ + os_snprintf(name, 256, NAMED_PIPE_PREFIX "-%s", + priv->wpa_s->ifname); +#endif /* UNICODE */ + + /* TODO: add support for configuring access list for the pipe */ + dst->pipe = CreateNamedPipe(name, + PIPE_ACCESS_DUPLEX | FILE_FLAG_OVERLAPPED, + PIPE_TYPE_MESSAGE | + PIPE_READMODE_MESSAGE | + PIPE_WAIT, + 15, REPLY_BUFSIZE, REQUEST_BUFSIZE, + 1000, + priv->sec_attr_set ? &priv->attr : NULL); + if (dst->pipe == INVALID_HANDLE_VALUE) { + wpa_printf(MSG_ERROR, "CTRL: CreateNamedPipe failed: %d", + (int) GetLastError()); + goto fail; + } + + if (ConnectNamedPipe(dst->pipe, &dst->overlap)) { + wpa_printf(MSG_ERROR, "CTRL: ConnectNamedPipe failed: %d", + (int) GetLastError()); + CloseHandle(dst->pipe); + os_free(dst); + return -1; + } + + err = GetLastError(); + switch (err) { + case ERROR_IO_PENDING: + wpa_printf(MSG_DEBUG, "CTRL: ConnectNamedPipe: connection in " + "progress"); + break; + case ERROR_PIPE_CONNECTED: + wpa_printf(MSG_DEBUG, "CTRL: ConnectNamedPipe: already " + "connected"); + if (SetEvent(dst->overlap.hEvent)) + break; + /* fall through */ + default: + wpa_printf(MSG_DEBUG, "CTRL: ConnectNamedPipe error: %d", + (int) err); + CloseHandle(dst->pipe); + os_free(dst); + return -1; + } + + dst->next = priv->ctrl_dst; + if (dst->next) + dst->next->prev = dst; + priv->ctrl_dst = dst; + + return 0; + +fail: + ctrl_close_pipe(dst); + return -1; +} + + +static void ctrl_close_pipe(struct wpa_ctrl_dst *dst) +{ + wpa_printf(MSG_DEBUG, "CTRL: close pipe %p", dst); + + if (dst->overlap.hEvent) { + eloop_unregister_event(dst->overlap.hEvent, + sizeof(dst->overlap.hEvent)); + CloseHandle(dst->overlap.hEvent); + } + + if (dst->pipe != INVALID_HANDLE_VALUE) { + /* + * Could use FlushFileBuffers() here to guarantee that all data + * gets delivered to the client, but that can block, so let's + * not do this for now. + * FlushFileBuffers(dst->pipe); + */ + CloseHandle(dst->pipe); + } + + if (dst->prev) + dst->prev->next = dst->next; + else + dst->priv->ctrl_dst = dst->next; + if (dst->next) + dst->next->prev = dst->prev; + + os_free(dst->rsp_buf); + os_free(dst); +} + + +static VOID WINAPI ctrl_iface_write_completed(DWORD err, DWORD bytes, + LPOVERLAPPED overlap) +{ + struct wpa_ctrl_dst *dst = (struct wpa_ctrl_dst *) overlap; + wpa_printf(MSG_DEBUG, "CTRL: Overlapped write completed: dst=%p " + "err=%d bytes=%d", dst, (int) err, (int) bytes); + if (err) { + ctrl_close_pipe(dst); + return; + } + + os_free(dst->rsp_buf); + dst->rsp_buf = NULL; + + if (!ReadFileEx(dst->pipe, dst->req_buf, sizeof(dst->req_buf), + &dst->overlap, ctrl_iface_read_completed)) { + wpa_printf(MSG_DEBUG, "CTRL: ReadFileEx failed: %d", + (int) GetLastError()); + ctrl_close_pipe(dst); + return; + } + wpa_printf(MSG_DEBUG, "CTRL: Overlapped read started for %p", dst); +} + + +static void wpa_supplicant_ctrl_iface_rx(struct wpa_ctrl_dst *dst, size_t len) +{ + struct wpa_supplicant *wpa_s = dst->priv->wpa_s; + char *reply = NULL, *send_buf; + size_t reply_len = 0, send_len; + int new_attached = 0; + char *buf = dst->req_buf; + + dst->used = 1; + if (len >= REQUEST_BUFSIZE) + len = REQUEST_BUFSIZE - 1; + buf[len] = '\0'; + + if (os_strcmp(buf, "ATTACH") == 0) { + dst->attached = 1; + wpa_printf(MSG_DEBUG, "CTRL_IFACE monitor attached"); + new_attached = 1; + reply_len = 2; + } else if (os_strcmp(buf, "DETACH") == 0) { + dst->attached = 0; + wpa_printf(MSG_DEBUG, "CTRL_IFACE monitor detached"); + reply_len = 2; + } else if (os_strncmp(buf, "LEVEL ", 6) == 0) { + wpa_printf(MSG_DEBUG, "CTRL_IFACE LEVEL %s", buf + 6); + dst->debug_level = atoi(buf + 6); + reply_len = 2; + } else { + reply = wpa_supplicant_ctrl_iface_process(wpa_s, buf, + &reply_len); + } + + if (reply) { + send_buf = reply; + send_len = reply_len; + } else if (reply_len == 2) { + send_buf = "OK\n"; + send_len = 3; + } else { + send_buf = "FAIL\n"; + send_len = 5; + } + + os_free(dst->rsp_buf); + dst->rsp_buf = os_malloc(send_len); + if (dst->rsp_buf == NULL) { + ctrl_close_pipe(dst); + os_free(reply); + return; + } + os_memcpy(dst->rsp_buf, send_buf, send_len); + os_free(reply); + + if (!WriteFileEx(dst->pipe, dst->rsp_buf, send_len, &dst->overlap, + ctrl_iface_write_completed)) { + wpa_printf(MSG_DEBUG, "CTRL: WriteFileEx failed: %d", + (int) GetLastError()); + ctrl_close_pipe(dst); + } else { + wpa_printf(MSG_DEBUG, "CTRL: Overlapped write started for %p", + dst); + } + + if (new_attached) + eapol_sm_notify_ctrl_attached(wpa_s->eapol); +} + + +static VOID WINAPI ctrl_iface_read_completed(DWORD err, DWORD bytes, + LPOVERLAPPED overlap) +{ + struct wpa_ctrl_dst *dst = (struct wpa_ctrl_dst *) overlap; + wpa_printf(MSG_DEBUG, "CTRL: Overlapped read completed: dst=%p err=%d " + "bytes=%d", dst, (int) err, (int) bytes); + if (err == 0 && bytes > 0) + wpa_supplicant_ctrl_iface_rx(dst, bytes); +} + + +static void wpa_supplicant_ctrl_iface_receive(void *eloop_data, void *user_ctx) +{ + struct wpa_ctrl_dst *dst = eloop_data; + struct ctrl_iface_priv *priv = dst->priv; + DWORD bytes; + + wpa_printf(MSG_DEBUG, "CTRL: wpa_supplicant_ctrl_iface_receive"); + ResetEvent(dst->overlap.hEvent); + + if (!GetOverlappedResult(dst->pipe, &dst->overlap, &bytes, FALSE)) { + wpa_printf(MSG_DEBUG, "CTRL: GetOverlappedResult failed: %d", + (int) GetLastError()); + return; + } + wpa_printf(MSG_DEBUG, "CTRL: GetOverlappedResult: New client " + "connected"); + + /* Open a new named pipe for the next client. */ + ctrl_open_pipe(priv); + + /* Use write completion function to start reading a command */ + ctrl_iface_write_completed(0, 0, &dst->overlap); + + ctrl_flush_broken_pipes(priv); +} + + +static int ctrl_iface_parse(struct ctrl_iface_priv *priv, const char *params) +{ + const char *sddl = NULL; + TCHAR *t_sddl; + + if (os_strncmp(params, "SDDL=", 5) == 0) + sddl = params + 5; + if (!sddl) { + sddl = os_strstr(params, " SDDL="); + if (sddl) + sddl += 6; + } + + if (!sddl) + return 0; + + wpa_printf(MSG_DEBUG, "CTRL: SDDL='%s'", sddl); + os_memset(&priv->attr, 0, sizeof(priv->attr)); + priv->attr.nLength = sizeof(priv->attr); + priv->attr.bInheritHandle = FALSE; + t_sddl = wpa_strdup_tchar(sddl); + if (t_sddl == NULL) + return -1; + if (!ConvertStringSecurityDescriptorToSecurityDescriptor( + t_sddl, SDDL_REVISION_1, + (PSECURITY_DESCRIPTOR *) &priv->attr.lpSecurityDescriptor, + NULL)) { + os_free(t_sddl); + wpa_printf(MSG_ERROR, "CTRL: SDDL='%s' - could not convert to " + "security descriptor: %d", + sddl, (int) GetLastError()); + return -1; + } + os_free(t_sddl); + + priv->sec_attr_set = 1; + + return 0; +} + + +static void wpa_supplicant_ctrl_iface_msg_cb(void *ctx, int level, + const char *txt, size_t len) +{ + struct wpa_supplicant *wpa_s = ctx; + if (wpa_s == NULL || wpa_s->ctrl_iface == NULL) + return; + wpa_supplicant_ctrl_iface_send(wpa_s->ctrl_iface, level, txt, len); +} + + +struct ctrl_iface_priv * +wpa_supplicant_ctrl_iface_init(struct wpa_supplicant *wpa_s) +{ + struct ctrl_iface_priv *priv; + + priv = os_zalloc(sizeof(*priv)); + if (priv == NULL) + return NULL; + priv->wpa_s = wpa_s; + + if (wpa_s->conf->ctrl_interface == NULL) + return priv; + + if (ctrl_iface_parse(priv, wpa_s->conf->ctrl_interface) < 0) { + os_free(priv); + return NULL; + } + + if (ctrl_open_pipe(priv) < 0) { + os_free(priv); + return NULL; + } + + wpa_msg_register_cb(wpa_supplicant_ctrl_iface_msg_cb); + + return priv; +} + + +void wpa_supplicant_ctrl_iface_deinit(struct ctrl_iface_priv *priv) +{ + while (priv->ctrl_dst) + ctrl_close_pipe(priv->ctrl_dst); + if (priv->sec_attr_set) + LocalFree(priv->attr.lpSecurityDescriptor); + os_free(priv); +} + + +static void wpa_supplicant_ctrl_iface_send(struct ctrl_iface_priv *priv, + int level, const char *buf, + size_t len) +{ + struct wpa_ctrl_dst *dst, *next; + char levelstr[10]; + int idx; + char *sbuf; + int llen; + DWORD written; + + dst = priv->ctrl_dst; + if (dst == NULL) + return; + + os_snprintf(levelstr, sizeof(levelstr), "<%d>", level); + + llen = os_strlen(levelstr); + sbuf = os_malloc(llen + len); + if (sbuf == NULL) + return; + + os_memcpy(sbuf, levelstr, llen); + os_memcpy(sbuf + llen, buf, len); + + idx = 0; + while (dst) { + next = dst->next; + if (dst->attached && level >= dst->debug_level) { + wpa_printf(MSG_DEBUG, "CTRL_IFACE monitor send %p", + dst); + if (!WriteFile(dst->pipe, sbuf, llen + len, &written, + NULL)) { + wpa_printf(MSG_DEBUG, "CTRL: WriteFile to dst " + "%p failed: %d", + dst, (int) GetLastError()); + dst->errors++; + if (dst->errors > 10) + ctrl_close_pipe(dst); + } else + dst->errors = 0; + } + idx++; + dst = next; + } + os_free(sbuf); +} + + +void wpa_supplicant_ctrl_iface_wait(struct ctrl_iface_priv *priv) +{ + wpa_printf(MSG_DEBUG, "CTRL_IFACE - %s - wait for monitor", + priv->wpa_s->ifname); + if (priv->ctrl_dst == NULL) + return; + WaitForSingleObject(priv->ctrl_dst->pipe, INFINITE); +} + + +/* Global ctrl_iface */ + +struct ctrl_iface_global_priv; + +struct wpa_global_dst { + /* Note: OVERLAPPED must be the first member of struct wpa_global_dst + */ + OVERLAPPED overlap; + struct wpa_global_dst *next, *prev; + struct ctrl_iface_global_priv *priv; + HANDLE pipe; + char req_buf[REQUEST_BUFSIZE]; + char *rsp_buf; + int used; +}; + +struct ctrl_iface_global_priv { + struct wpa_global *global; + struct wpa_global_dst *ctrl_dst; +}; + + +static void global_flush_broken_pipes(struct ctrl_iface_global_priv *priv) +{ + struct wpa_global_dst *dst, *next; + + dst = priv->ctrl_dst; + + while (dst) { + next = dst->next; + if (ctrl_broken_pipe(dst->pipe, dst->used)) { + wpa_printf(MSG_DEBUG, "CTRL: closing broken pipe %p", + dst); + global_close_pipe(dst); + } + dst = next; + } +} + + +static int global_open_pipe(struct ctrl_iface_global_priv *priv) +{ + struct wpa_global_dst *dst; + DWORD err; + + dst = os_zalloc(sizeof(*dst)); + if (dst == NULL) + return -1; + wpa_printf(MSG_DEBUG, "CTRL: Open pipe %p", dst); + + dst->priv = priv; + dst->pipe = INVALID_HANDLE_VALUE; + + dst->overlap.hEvent = CreateEvent(NULL, TRUE, TRUE, NULL); + if (dst->overlap.hEvent == NULL) { + wpa_printf(MSG_ERROR, "CTRL: CreateEvent failed: %d", + (int) GetLastError()); + goto fail; + } + + eloop_register_event(dst->overlap.hEvent, + sizeof(dst->overlap.hEvent), + wpa_supplicant_global_iface_receive, dst, NULL); + + /* TODO: add support for configuring access list for the pipe */ + dst->pipe = CreateNamedPipe(NAMED_PIPE_PREFIX, + PIPE_ACCESS_DUPLEX | FILE_FLAG_OVERLAPPED, + PIPE_TYPE_MESSAGE | + PIPE_READMODE_MESSAGE | + PIPE_WAIT, + 10, REPLY_BUFSIZE, REQUEST_BUFSIZE, + 1000, NULL); + if (dst->pipe == INVALID_HANDLE_VALUE) { + wpa_printf(MSG_ERROR, "CTRL: CreateNamedPipe failed: %d", + (int) GetLastError()); + goto fail; + } + + if (ConnectNamedPipe(dst->pipe, &dst->overlap)) { + wpa_printf(MSG_ERROR, "CTRL: ConnectNamedPipe failed: %d", + (int) GetLastError()); + CloseHandle(dst->pipe); + os_free(dst); + return -1; + } + + err = GetLastError(); + switch (err) { + case ERROR_IO_PENDING: + wpa_printf(MSG_DEBUG, "CTRL: ConnectNamedPipe: connection in " + "progress"); + break; + case ERROR_PIPE_CONNECTED: + wpa_printf(MSG_DEBUG, "CTRL: ConnectNamedPipe: already " + "connected"); + if (SetEvent(dst->overlap.hEvent)) + break; + /* fall through */ + default: + wpa_printf(MSG_DEBUG, "CTRL: ConnectNamedPipe error: %d", + (int) err); + CloseHandle(dst->pipe); + os_free(dst); + return -1; + } + + dst->next = priv->ctrl_dst; + if (dst->next) + dst->next->prev = dst; + priv->ctrl_dst = dst; + + return 0; + +fail: + global_close_pipe(dst); + return -1; +} + + +static void global_close_pipe(struct wpa_global_dst *dst) +{ + wpa_printf(MSG_DEBUG, "CTRL: close pipe %p", dst); + + if (dst->overlap.hEvent) { + eloop_unregister_event(dst->overlap.hEvent, + sizeof(dst->overlap.hEvent)); + CloseHandle(dst->overlap.hEvent); + } + + if (dst->pipe != INVALID_HANDLE_VALUE) { + /* + * Could use FlushFileBuffers() here to guarantee that all data + * gets delivered to the client, but that can block, so let's + * not do this for now. + * FlushFileBuffers(dst->pipe); + */ + CloseHandle(dst->pipe); + } + + if (dst->prev) + dst->prev->next = dst->next; + else + dst->priv->ctrl_dst = dst->next; + if (dst->next) + dst->next->prev = dst->prev; + + os_free(dst->rsp_buf); + os_free(dst); +} + + +static VOID WINAPI global_iface_write_completed(DWORD err, DWORD bytes, + LPOVERLAPPED overlap) +{ + struct wpa_global_dst *dst = (struct wpa_global_dst *) overlap; + wpa_printf(MSG_DEBUG, "CTRL: Overlapped write completed: dst=%p " + "err=%d bytes=%d", dst, (int) err, (int) bytes); + if (err) { + global_close_pipe(dst); + return; + } + + os_free(dst->rsp_buf); + dst->rsp_buf = NULL; + + if (!ReadFileEx(dst->pipe, dst->req_buf, sizeof(dst->req_buf), + &dst->overlap, global_iface_read_completed)) { + wpa_printf(MSG_DEBUG, "CTRL: ReadFileEx failed: %d", + (int) GetLastError()); + global_close_pipe(dst); + /* FIX: if this was the pipe waiting for new global + * connections, at this point there are no open global pipes.. + * Should try to open a new pipe.. */ + return; + } + wpa_printf(MSG_DEBUG, "CTRL: Overlapped read started for %p", dst); +} + + +static void wpa_supplicant_global_iface_rx(struct wpa_global_dst *dst, + size_t len) +{ + struct wpa_global *global = dst->priv->global; + char *reply = NULL, *send_buf; + size_t reply_len = 0, send_len; + char *buf = dst->req_buf; + + dst->used = 1; + if (len >= REQUEST_BUFSIZE) + len = REQUEST_BUFSIZE - 1; + buf[len] = '\0'; + + reply = wpa_supplicant_global_ctrl_iface_process(global, buf, + &reply_len); + if (reply) { + send_buf = reply; + send_len = reply_len; + } else if (reply_len) { + send_buf = "FAIL\n"; + send_len = 5; + } else { + os_free(dst->rsp_buf); + dst->rsp_buf = NULL; + return; + } + + os_free(dst->rsp_buf); + dst->rsp_buf = os_malloc(send_len); + if (dst->rsp_buf == NULL) { + global_close_pipe(dst); + os_free(reply); + return; + } + os_memcpy(dst->rsp_buf, send_buf, send_len); + os_free(reply); + + if (!WriteFileEx(dst->pipe, dst->rsp_buf, send_len, &dst->overlap, + global_iface_write_completed)) { + wpa_printf(MSG_DEBUG, "CTRL: WriteFileEx failed: %d", + (int) GetLastError()); + global_close_pipe(dst); + } else { + wpa_printf(MSG_DEBUG, "CTRL: Overlapped write started for %p", + dst); + } +} + + +static VOID WINAPI global_iface_read_completed(DWORD err, DWORD bytes, + LPOVERLAPPED overlap) +{ + struct wpa_global_dst *dst = (struct wpa_global_dst *) overlap; + wpa_printf(MSG_DEBUG, "CTRL: Overlapped read completed: dst=%p err=%d " + "bytes=%d", dst, (int) err, (int) bytes); + if (err == 0 && bytes > 0) + wpa_supplicant_global_iface_rx(dst, bytes); +} + + +static void wpa_supplicant_global_iface_receive(void *eloop_data, + void *user_ctx) +{ + struct wpa_global_dst *dst = eloop_data; + struct ctrl_iface_global_priv *priv = dst->priv; + DWORD bytes; + + wpa_printf(MSG_DEBUG, "CTRL: wpa_supplicant_global_iface_receive"); + ResetEvent(dst->overlap.hEvent); + + if (!GetOverlappedResult(dst->pipe, &dst->overlap, &bytes, FALSE)) { + wpa_printf(MSG_DEBUG, "CTRL: GetOverlappedResult failed: %d", + (int) GetLastError()); + return; + } + wpa_printf(MSG_DEBUG, "CTRL: GetOverlappedResult: New client " + "connected"); + + /* Open a new named pipe for the next client. */ + if (global_open_pipe(priv) < 0) { + wpa_printf(MSG_DEBUG, "CTRL: global_open_pipe failed"); + return; + } + + /* Use write completion function to start reading a command */ + global_iface_write_completed(0, 0, &dst->overlap); + + global_flush_broken_pipes(priv); +} + + +struct ctrl_iface_global_priv * +wpa_supplicant_global_ctrl_iface_init(struct wpa_global *global) +{ + struct ctrl_iface_global_priv *priv; + + priv = os_zalloc(sizeof(*priv)); + if (priv == NULL) + return NULL; + priv->global = global; + + if (global_open_pipe(priv) < 0) { + os_free(priv); + return NULL; + } + + return priv; +} + + +void +wpa_supplicant_global_ctrl_iface_deinit(struct ctrl_iface_global_priv *priv) +{ + while (priv->ctrl_dst) + global_close_pipe(priv->ctrl_dst); + os_free(priv); +} diff --git a/contrib/wpa_supplicant/ctrl_iface_udp.c b/contrib/wpa_supplicant/ctrl_iface_udp.c new file mode 100644 index 000000000000..bb6f11d50c9c --- /dev/null +++ b/contrib/wpa_supplicant/ctrl_iface_udp.c @@ -0,0 +1,561 @@ +/* + * WPA Supplicant / UDP socket -based control interface + * Copyright (c) 2004-2005, Jouni Malinen <j@w1.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 "includes.h" + +#include "common.h" +#include "eloop.h" +#include "config.h" +#include "eapol_sm.h" +#include "wpa_supplicant_i.h" +#include "ctrl_iface.h" +#include "wpa_ctrl.h" + + +#define COOKIE_LEN 8 + +/* Per-interface ctrl_iface */ + +/** + * struct wpa_ctrl_dst - Internal data structure of control interface monitors + * + * This structure is used to store information about registered control + * interface monitors into struct wpa_supplicant. This data is private to + * ctrl_iface_udp.c and should not be touched directly from other files. + */ +struct wpa_ctrl_dst { + struct wpa_ctrl_dst *next; + struct sockaddr_in addr; + socklen_t addrlen; + int debug_level; + int errors; +}; + + +struct ctrl_iface_priv { + struct wpa_supplicant *wpa_s; + int sock; + struct wpa_ctrl_dst *ctrl_dst; + u8 cookie[COOKIE_LEN]; +}; + + +static void wpa_supplicant_ctrl_iface_send(struct ctrl_iface_priv *priv, + int level, const char *buf, + size_t len); + + +static int wpa_supplicant_ctrl_iface_attach(struct ctrl_iface_priv *priv, + struct sockaddr_in *from, + socklen_t fromlen) +{ + struct wpa_ctrl_dst *dst; + + dst = os_zalloc(sizeof(*dst)); + if (dst == NULL) + return -1; + os_memcpy(&dst->addr, from, sizeof(struct sockaddr_in)); + dst->addrlen = fromlen; + dst->debug_level = MSG_INFO; + dst->next = priv->ctrl_dst; + priv->ctrl_dst = dst; + wpa_printf(MSG_DEBUG, "CTRL_IFACE monitor attached %s:%d", + inet_ntoa(from->sin_addr), ntohs(from->sin_port)); + return 0; +} + + +static int wpa_supplicant_ctrl_iface_detach(struct ctrl_iface_priv *priv, + struct sockaddr_in *from, + socklen_t fromlen) +{ + struct wpa_ctrl_dst *dst, *prev = NULL; + + dst = priv->ctrl_dst; + while (dst) { + if (from->sin_addr.s_addr == dst->addr.sin_addr.s_addr && + from->sin_port == dst->addr.sin_port) { + if (prev == NULL) + priv->ctrl_dst = dst->next; + else + prev->next = dst->next; + os_free(dst); + wpa_printf(MSG_DEBUG, "CTRL_IFACE monitor detached " + "%s:%d", inet_ntoa(from->sin_addr), + ntohs(from->sin_port)); + return 0; + } + prev = dst; + dst = dst->next; + } + return -1; +} + + +static int wpa_supplicant_ctrl_iface_level(struct ctrl_iface_priv *priv, + struct sockaddr_in *from, + socklen_t fromlen, + char *level) +{ + struct wpa_ctrl_dst *dst; + + wpa_printf(MSG_DEBUG, "CTRL_IFACE LEVEL %s", level); + + dst = priv->ctrl_dst; + while (dst) { + if (from->sin_addr.s_addr == dst->addr.sin_addr.s_addr && + from->sin_port == dst->addr.sin_port) { + wpa_printf(MSG_DEBUG, "CTRL_IFACE changed monitor " + "level %s:%d", inet_ntoa(from->sin_addr), + ntohs(from->sin_port)); + dst->debug_level = atoi(level); + return 0; + } + dst = dst->next; + } + + return -1; +} + + +static char * +wpa_supplicant_ctrl_iface_get_cookie(struct ctrl_iface_priv *priv, + size_t *reply_len) +{ + char *reply; + reply = os_malloc(7 + 2 * COOKIE_LEN + 1); + if (reply == NULL) { + *reply_len = 1; + return NULL; + } + + os_memcpy(reply, "COOKIE=", 7); + wpa_snprintf_hex(reply + 7, 2 * COOKIE_LEN + 1, + priv->cookie, COOKIE_LEN); + + *reply_len = 7 + 2 * COOKIE_LEN; + return reply; +} + + +static void wpa_supplicant_ctrl_iface_receive(int sock, void *eloop_ctx, + void *sock_ctx) +{ + struct wpa_supplicant *wpa_s = eloop_ctx; + struct ctrl_iface_priv *priv = sock_ctx; + char buf[256], *pos; + int res; + struct sockaddr_in from; + socklen_t fromlen = sizeof(from); + char *reply = NULL; + size_t reply_len = 0; + int new_attached = 0; + u8 cookie[COOKIE_LEN]; + + res = recvfrom(sock, buf, sizeof(buf) - 1, 0, + (struct sockaddr *) &from, &fromlen); + if (res < 0) { + perror("recvfrom(ctrl_iface)"); + return; + } + if (from.sin_addr.s_addr != htonl((127 << 24) | 1)) { + /* + * The OS networking stack is expected to drop this kind of + * frames since the socket is bound to only localhost address. + * Just in case, drop the frame if it is coming from any other + * address. + */ + wpa_printf(MSG_DEBUG, "CTRL: Drop packet from unexpected " + "source %s", inet_ntoa(from.sin_addr)); + return; + } + buf[res] = '\0'; + + if (os_strcmp(buf, "GET_COOKIE") == 0) { + reply = wpa_supplicant_ctrl_iface_get_cookie(priv, &reply_len); + goto done; + } + + /* + * Require that the client includes a prefix with the 'cookie' value + * fetched with GET_COOKIE command. This is used to verify that the + * client has access to a bidirectional link over UDP in order to + * avoid attacks using forged localhost IP address even if the OS does + * not block such frames from remote destinations. + */ + if (os_strncmp(buf, "COOKIE=", 7) != 0) { + wpa_printf(MSG_DEBUG, "CTLR: No cookie in the request - " + "drop request"); + return; + } + + if (hexstr2bin(buf + 7, cookie, COOKIE_LEN) < 0) { + wpa_printf(MSG_DEBUG, "CTLR: Invalid cookie format in the " + "request - drop request"); + return; + } + + if (os_memcmp(cookie, priv->cookie, COOKIE_LEN) != 0) { + wpa_printf(MSG_DEBUG, "CTLR: Invalid cookie in the request - " + "drop request"); + return; + } + + pos = buf + 7 + 2 * COOKIE_LEN; + while (*pos == ' ') + pos++; + + if (os_strcmp(pos, "ATTACH") == 0) { + if (wpa_supplicant_ctrl_iface_attach(priv, &from, fromlen)) + reply_len = 1; + else { + new_attached = 1; + reply_len = 2; + } + } else if (os_strcmp(pos, "DETACH") == 0) { + if (wpa_supplicant_ctrl_iface_detach(priv, &from, fromlen)) + reply_len = 1; + else + reply_len = 2; + } else if (os_strncmp(pos, "LEVEL ", 6) == 0) { + if (wpa_supplicant_ctrl_iface_level(priv, &from, fromlen, + pos + 6)) + reply_len = 1; + else + reply_len = 2; + } else { + reply = wpa_supplicant_ctrl_iface_process(wpa_s, pos, + &reply_len); + } + + done: + if (reply) { + sendto(sock, reply, reply_len, 0, (struct sockaddr *) &from, + fromlen); + os_free(reply); + } else if (reply_len == 1) { + sendto(sock, "FAIL\n", 5, 0, (struct sockaddr *) &from, + fromlen); + } else if (reply_len == 2) { + sendto(sock, "OK\n", 3, 0, (struct sockaddr *) &from, + fromlen); + } + + if (new_attached) + eapol_sm_notify_ctrl_attached(wpa_s->eapol); +} + + +static void wpa_supplicant_ctrl_iface_msg_cb(void *ctx, int level, + const char *txt, size_t len) +{ + struct wpa_supplicant *wpa_s = ctx; + if (wpa_s == NULL || wpa_s->ctrl_iface == NULL) + return; + wpa_supplicant_ctrl_iface_send(wpa_s->ctrl_iface, level, txt, len); +} + + +struct ctrl_iface_priv * +wpa_supplicant_ctrl_iface_init(struct wpa_supplicant *wpa_s) +{ + struct ctrl_iface_priv *priv; + struct sockaddr_in addr; + + priv = os_zalloc(sizeof(*priv)); + if (priv == NULL) + return NULL; + priv->wpa_s = wpa_s; + priv->sock = -1; + os_get_random(priv->cookie, COOKIE_LEN); + + if (wpa_s->conf->ctrl_interface == NULL) + return priv; + + priv->sock = socket(PF_INET, SOCK_DGRAM, 0); + if (priv->sock < 0) { + perror("socket(PF_INET)"); + goto fail; + } + + os_memset(&addr, 0, sizeof(addr)); + addr.sin_family = AF_INET; + addr.sin_addr.s_addr = htonl((127 << 24) | 1); + addr.sin_port = htons(WPA_CTRL_IFACE_PORT); + if (bind(priv->sock, (struct sockaddr *) &addr, sizeof(addr)) < 0) { + perror("bind(AF_INET)"); + goto fail; + } + + eloop_register_read_sock(priv->sock, wpa_supplicant_ctrl_iface_receive, + wpa_s, priv); + wpa_msg_register_cb(wpa_supplicant_ctrl_iface_msg_cb); + + return priv; + +fail: + if (priv->sock >= 0) + close(priv->sock); + os_free(priv); + return NULL; +} + + +void wpa_supplicant_ctrl_iface_deinit(struct ctrl_iface_priv *priv) +{ + struct wpa_ctrl_dst *dst, *prev; + + if (priv->sock > -1) { + eloop_unregister_read_sock(priv->sock); + if (priv->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"); + os_sleep(1, 0); + } + close(priv->sock); + priv->sock = -1; + } + + dst = priv->ctrl_dst; + while (dst) { + prev = dst; + dst = dst->next; + os_free(prev); + } + os_free(priv); +} + + +static void wpa_supplicant_ctrl_iface_send(struct ctrl_iface_priv *priv, + int level, const char *buf, + size_t len) +{ + struct wpa_ctrl_dst *dst, *next; + char levelstr[10]; + int idx; + char *sbuf; + int llen; + + dst = priv->ctrl_dst; + if (priv->sock < 0 || dst == NULL) + return; + + os_snprintf(levelstr, sizeof(levelstr), "<%d>", level); + + llen = os_strlen(levelstr); + sbuf = os_malloc(llen + len); + if (sbuf == NULL) + return; + + os_memcpy(sbuf, levelstr, llen); + os_memcpy(sbuf + llen, buf, len); + + idx = 0; + while (dst) { + next = dst->next; + if (level >= dst->debug_level) { + wpa_printf(MSG_DEBUG, "CTRL_IFACE monitor send %s:%d", + inet_ntoa(dst->addr.sin_addr), + ntohs(dst->addr.sin_port)); + if (sendto(priv->sock, sbuf, llen + len, 0, + (struct sockaddr *) &dst->addr, + sizeof(dst->addr)) < 0) { + perror("sendto(CTRL_IFACE monitor)"); + dst->errors++; + if (dst->errors > 10) { + wpa_supplicant_ctrl_iface_detach( + priv, &dst->addr, + dst->addrlen); + } + } else + dst->errors = 0; + } + idx++; + dst = next; + } + os_free(sbuf); +} + + +void wpa_supplicant_ctrl_iface_wait(struct ctrl_iface_priv *priv) +{ + wpa_printf(MSG_DEBUG, "CTRL_IFACE - %s - wait for monitor", + priv->wpa_s->ifname); + eloop_wait_for_read_sock(priv->sock); +} + + +/* Global ctrl_iface */ + +struct ctrl_iface_global_priv { + int sock; + u8 cookie[COOKIE_LEN]; +}; + + +static char * +wpa_supplicant_global_get_cookie(struct ctrl_iface_global_priv *priv, + size_t *reply_len) +{ + char *reply; + reply = os_malloc(7 + 2 * COOKIE_LEN + 1); + if (reply == NULL) { + *reply_len = 1; + return NULL; + } + + os_memcpy(reply, "COOKIE=", 7); + wpa_snprintf_hex(reply + 7, 2 * COOKIE_LEN + 1, + priv->cookie, COOKIE_LEN); + + *reply_len = 7 + 2 * COOKIE_LEN; + return reply; +} + + +static void wpa_supplicant_global_ctrl_iface_receive(int sock, void *eloop_ctx, + void *sock_ctx) +{ + struct wpa_global *global = eloop_ctx; + struct ctrl_iface_global_priv *priv = sock_ctx; + char buf[256], *pos; + int res; + struct sockaddr_in from; + socklen_t fromlen = sizeof(from); + char *reply; + size_t reply_len; + u8 cookie[COOKIE_LEN]; + + res = recvfrom(sock, buf, sizeof(buf) - 1, 0, + (struct sockaddr *) &from, &fromlen); + if (res < 0) { + perror("recvfrom(ctrl_iface)"); + return; + } + if (from.sin_addr.s_addr != htonl((127 << 24) | 1)) { + /* + * The OS networking stack is expected to drop this kind of + * frames since the socket is bound to only localhost address. + * Just in case, drop the frame if it is coming from any other + * address. + */ + wpa_printf(MSG_DEBUG, "CTRL: Drop packet from unexpected " + "source %s", inet_ntoa(from.sin_addr)); + return; + } + buf[res] = '\0'; + + if (os_strcmp(buf, "GET_COOKIE") == 0) { + reply = wpa_supplicant_global_get_cookie(priv, &reply_len); + goto done; + } + + if (os_strncmp(buf, "COOKIE=", 7) != 0) { + wpa_printf(MSG_DEBUG, "CTLR: No cookie in the request - " + "drop request"); + return; + } + + if (hexstr2bin(buf + 7, cookie, COOKIE_LEN) < 0) { + wpa_printf(MSG_DEBUG, "CTLR: Invalid cookie format in the " + "request - drop request"); + return; + } + + if (os_memcmp(cookie, priv->cookie, COOKIE_LEN) != 0) { + wpa_printf(MSG_DEBUG, "CTLR: Invalid cookie in the request - " + "drop request"); + return; + } + + pos = buf + 7 + 2 * COOKIE_LEN; + while (*pos == ' ') + pos++; + + reply = wpa_supplicant_global_ctrl_iface_process(global, pos, + &reply_len); + + done: + if (reply) { + sendto(sock, reply, reply_len, 0, (struct sockaddr *) &from, + fromlen); + os_free(reply); + } else if (reply_len) { + sendto(sock, "FAIL\n", 5, 0, (struct sockaddr *) &from, + fromlen); + } +} + + +struct ctrl_iface_global_priv * +wpa_supplicant_global_ctrl_iface_init(struct wpa_global *global) +{ + struct ctrl_iface_global_priv *priv; + struct sockaddr_in addr; + + priv = os_zalloc(sizeof(*priv)); + if (priv == NULL) + return NULL; + priv->sock = -1; + os_get_random(priv->cookie, COOKIE_LEN); + + if (global->params.ctrl_interface == NULL) + return priv; + + wpa_printf(MSG_DEBUG, "Global control interface '%s'", + global->params.ctrl_interface); + + priv->sock = socket(PF_INET, SOCK_DGRAM, 0); + if (priv->sock < 0) { + perror("socket(PF_INET)"); + goto fail; + } + + os_memset(&addr, 0, sizeof(addr)); + addr.sin_family = AF_INET; + addr.sin_addr.s_addr = htonl((127 << 24) | 1); + addr.sin_port = htons(WPA_GLOBAL_CTRL_IFACE_PORT); + if (bind(priv->sock, (struct sockaddr *) &addr, sizeof(addr)) < 0) { + perror("bind(AF_INET)"); + goto fail; + } + + eloop_register_read_sock(priv->sock, + wpa_supplicant_global_ctrl_iface_receive, + global, priv); + + return priv; + +fail: + if (priv->sock >= 0) + close(priv->sock); + os_free(priv); + return NULL; +} + + +void +wpa_supplicant_global_ctrl_iface_deinit(struct ctrl_iface_global_priv *priv) +{ + if (priv->sock >= 0) { + eloop_unregister_read_sock(priv->sock); + close(priv->sock); + } + os_free(priv); +} diff --git a/contrib/wpa_supplicant/ctrl_iface_unix.c b/contrib/wpa_supplicant/ctrl_iface_unix.c new file mode 100644 index 000000000000..e9bc47239c63 --- /dev/null +++ b/contrib/wpa_supplicant/ctrl_iface_unix.c @@ -0,0 +1,656 @@ +/* + * WPA Supplicant / UNIX domain socket -based control interface + * Copyright (c) 2004-2005, Jouni Malinen <j@w1.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 "includes.h" +#include <sys/un.h> +#include <sys/stat.h> +#include <grp.h> + +#include "common.h" +#include "eloop.h" +#include "config.h" +#include "eapol_sm.h" +#include "wpa_supplicant_i.h" +#include "ctrl_iface.h" + +/* Per-interface ctrl_iface */ + +/** + * struct wpa_ctrl_dst - Internal data structure of control interface monitors + * + * This structure is used to store information about registered control + * interface monitors into struct wpa_supplicant. This data is private to + * ctrl_iface_unix.c and should not be touched directly from other files. + */ +struct wpa_ctrl_dst { + struct wpa_ctrl_dst *next; + struct sockaddr_un addr; + socklen_t addrlen; + int debug_level; + int errors; +}; + + +struct ctrl_iface_priv { + struct wpa_supplicant *wpa_s; + int sock; + struct wpa_ctrl_dst *ctrl_dst; +}; + + +static void wpa_supplicant_ctrl_iface_send(struct ctrl_iface_priv *priv, + int level, const char *buf, + size_t len); + + +static int wpa_supplicant_ctrl_iface_attach(struct ctrl_iface_priv *priv, + struct sockaddr_un *from, + socklen_t fromlen) +{ + struct wpa_ctrl_dst *dst; + + dst = os_zalloc(sizeof(*dst)); + if (dst == NULL) + return -1; + os_memcpy(&dst->addr, from, sizeof(struct sockaddr_un)); + dst->addrlen = fromlen; + dst->debug_level = MSG_INFO; + dst->next = priv->ctrl_dst; + priv->ctrl_dst = dst; + wpa_hexdump(MSG_DEBUG, "CTRL_IFACE monitor attached", + (u8 *) from->sun_path, fromlen - sizeof(from->sun_family)); + return 0; +} + + +static int wpa_supplicant_ctrl_iface_detach(struct ctrl_iface_priv *priv, + struct sockaddr_un *from, + socklen_t fromlen) +{ + struct wpa_ctrl_dst *dst, *prev = NULL; + + dst = priv->ctrl_dst; + while (dst) { + if (fromlen == dst->addrlen && + os_memcmp(from->sun_path, dst->addr.sun_path, + fromlen - sizeof(from->sun_family)) == 0) { + if (prev == NULL) + priv->ctrl_dst = dst->next; + else + prev->next = dst->next; + os_free(dst); + wpa_hexdump(MSG_DEBUG, "CTRL_IFACE monitor detached", + (u8 *) from->sun_path, + fromlen - sizeof(from->sun_family)); + return 0; + } + prev = dst; + dst = dst->next; + } + return -1; +} + + +static int wpa_supplicant_ctrl_iface_level(struct ctrl_iface_priv *priv, + struct sockaddr_un *from, + socklen_t fromlen, + char *level) +{ + struct wpa_ctrl_dst *dst; + + wpa_printf(MSG_DEBUG, "CTRL_IFACE LEVEL %s", level); + + dst = priv->ctrl_dst; + while (dst) { + if (fromlen == dst->addrlen && + os_memcmp(from->sun_path, dst->addr.sun_path, + fromlen - sizeof(from->sun_family)) == 0) { + wpa_hexdump(MSG_DEBUG, "CTRL_IFACE changed monitor " + "level", (u8 *) from->sun_path, + fromlen - sizeof(from->sun_family)); + dst->debug_level = atoi(level); + return 0; + } + dst = dst->next; + } + + return -1; +} + + +static void wpa_supplicant_ctrl_iface_receive(int sock, void *eloop_ctx, + void *sock_ctx) +{ + struct wpa_supplicant *wpa_s = eloop_ctx; + struct ctrl_iface_priv *priv = sock_ctx; + char buf[256]; + int res; + struct sockaddr_un from; + socklen_t fromlen = sizeof(from); + char *reply = NULL; + size_t reply_len = 0; + int new_attached = 0; + + res = recvfrom(sock, buf, sizeof(buf) - 1, 0, + (struct sockaddr *) &from, &fromlen); + if (res < 0) { + perror("recvfrom(ctrl_iface)"); + return; + } + buf[res] = '\0'; + + if (os_strcmp(buf, "ATTACH") == 0) { + if (wpa_supplicant_ctrl_iface_attach(priv, &from, fromlen)) + reply_len = 1; + else { + new_attached = 1; + reply_len = 2; + } + } else if (os_strcmp(buf, "DETACH") == 0) { + if (wpa_supplicant_ctrl_iface_detach(priv, &from, fromlen)) + reply_len = 1; + else + reply_len = 2; + } else if (os_strncmp(buf, "LEVEL ", 6) == 0) { + if (wpa_supplicant_ctrl_iface_level(priv, &from, fromlen, + buf + 6)) + reply_len = 1; + else + reply_len = 2; + } else { + reply = wpa_supplicant_ctrl_iface_process(wpa_s, buf, + &reply_len); + } + + if (reply) { + sendto(sock, reply, reply_len, 0, (struct sockaddr *) &from, + fromlen); + os_free(reply); + } else if (reply_len == 1) { + sendto(sock, "FAIL\n", 5, 0, (struct sockaddr *) &from, + fromlen); + } else if (reply_len == 2) { + sendto(sock, "OK\n", 3, 0, (struct sockaddr *) &from, + fromlen); + } + + if (new_attached) + eapol_sm_notify_ctrl_attached(wpa_s->eapol); +} + + +static char * wpa_supplicant_ctrl_iface_path(struct wpa_supplicant *wpa_s) +{ + char *buf; + size_t len; + char *pbuf, *dir = NULL, *gid_str = NULL; + + if (wpa_s->conf->ctrl_interface == NULL) + return NULL; + + pbuf = os_strdup(wpa_s->conf->ctrl_interface); + if (pbuf == NULL) + return NULL; + if (os_strncmp(pbuf, "DIR=", 4) == 0) { + dir = pbuf + 4; + gid_str = os_strstr(dir, " GROUP="); + if (gid_str) { + *gid_str = '\0'; + gid_str += 7; + } + } else + dir = pbuf; + + len = os_strlen(dir) + os_strlen(wpa_s->ifname) + 2; + buf = os_malloc(len); + if (buf == NULL) { + os_free(pbuf); + return NULL; + } + + os_snprintf(buf, len, "%s/%s", dir, wpa_s->ifname); +#ifdef __CYGWIN__ + { + /* Windows/WinPcap uses interface names that are not suitable + * as a file name - convert invalid chars to underscores */ + char *pos = buf; + while (*pos) { + if (*pos == '\\') + *pos = '_'; + pos++; + } + } +#endif /* __CYGWIN__ */ + os_free(pbuf); + return buf; +} + + +static void wpa_supplicant_ctrl_iface_msg_cb(void *ctx, int level, + const char *txt, size_t len) +{ + struct wpa_supplicant *wpa_s = ctx; + if (wpa_s == NULL || wpa_s->ctrl_iface == NULL) + return; + wpa_supplicant_ctrl_iface_send(wpa_s->ctrl_iface, level, txt, len); +} + + +struct ctrl_iface_priv * +wpa_supplicant_ctrl_iface_init(struct wpa_supplicant *wpa_s) +{ + struct ctrl_iface_priv *priv; + struct sockaddr_un addr; + char *fname = NULL; + gid_t gid = 0; + int gid_set = 0; + char *buf, *dir = NULL, *gid_str = NULL; + struct group *grp; + char *endp; + + priv = os_zalloc(sizeof(*priv)); + if (priv == NULL) + return NULL; + priv->wpa_s = wpa_s; + priv->sock = -1; + + if (wpa_s->conf->ctrl_interface == NULL) + return priv; + + buf = os_strdup(wpa_s->conf->ctrl_interface); + if (buf == NULL) + goto fail; + if (os_strncmp(buf, "DIR=", 4) == 0) { + dir = buf + 4; + gid_str = os_strstr(dir, " GROUP="); + if (gid_str) { + *gid_str = '\0'; + gid_str += 7; + } + } else { + dir = buf; + gid_str = wpa_s->conf->ctrl_interface_group; + } + + if (mkdir(dir, S_IRWXU | S_IRWXG) < 0) { + if (errno == EEXIST) { + wpa_printf(MSG_DEBUG, "Using existing control " + "interface directory."); + } else { + perror("mkdir[ctrl_interface]"); + goto fail; + } + } + + if (gid_str) { + grp = getgrnam(gid_str); + if (grp) { + gid = grp->gr_gid; + gid_set = 1; + wpa_printf(MSG_DEBUG, "ctrl_interface_group=%d" + " (from group name '%s')", + (int) gid, gid_str); + } else { + /* Group name not found - try to parse this as gid */ + gid = strtol(gid_str, &endp, 10); + if (*gid_str == '\0' || *endp != '\0') { + wpa_printf(MSG_DEBUG, "CTRL: Invalid group " + "'%s'", gid_str); + goto fail; + } + gid_set = 1; + wpa_printf(MSG_DEBUG, "ctrl_interface_group=%d", + (int) gid); + } + } + + if (gid_set && chown(dir, -1, gid) < 0) { + perror("chown[ctrl_interface]"); + goto fail; + } + + if (os_strlen(dir) + 1 + os_strlen(wpa_s->ifname) >= + sizeof(addr.sun_path)) + goto fail; + + priv->sock = socket(PF_UNIX, SOCK_DGRAM, 0); + if (priv->sock < 0) { + perror("socket(PF_UNIX)"); + goto fail; + } + + os_memset(&addr, 0, sizeof(addr)); + addr.sun_family = AF_UNIX; + fname = wpa_supplicant_ctrl_iface_path(wpa_s); + if (fname == NULL) + goto fail; + os_strncpy(addr.sun_path, fname, sizeof(addr.sun_path)); + if (bind(priv->sock, (struct sockaddr *) &addr, sizeof(addr)) < 0) { + wpa_printf(MSG_DEBUG, "ctrl_iface bind(PF_UNIX) failed: %s", + strerror(errno)); + if (connect(priv->sock, (struct sockaddr *) &addr, + sizeof(addr)) < 0) { + wpa_printf(MSG_DEBUG, "ctrl_iface exists, but does not" + " allow connections - assuming it was left" + "over from forced program termination"); + if (unlink(fname) < 0) { + perror("unlink[ctrl_iface]"); + wpa_printf(MSG_ERROR, "Could not unlink " + "existing ctrl_iface socket '%s'", + fname); + goto fail; + } + if (bind(priv->sock, (struct sockaddr *) &addr, + sizeof(addr)) < 0) { + perror("bind(PF_UNIX)"); + goto fail; + } + wpa_printf(MSG_DEBUG, "Successfully replaced leftover " + "ctrl_iface socket '%s'", fname); + } else { + wpa_printf(MSG_INFO, "ctrl_iface exists and seems to " + "be in use - cannot override it"); + wpa_printf(MSG_INFO, "Delete '%s' manually if it is " + "not used anymore", fname); + os_free(fname); + fname = NULL; + goto fail; + } + } + + if (gid_set && chown(fname, -1, gid) < 0) { + perror("chown[ctrl_interface/ifname]"); + goto fail; + } + + if (chmod(fname, S_IRWXU | S_IRWXG) < 0) { + perror("chmod[ctrl_interface/ifname]"); + goto fail; + } + os_free(fname); + + eloop_register_read_sock(priv->sock, wpa_supplicant_ctrl_iface_receive, + wpa_s, priv); + wpa_msg_register_cb(wpa_supplicant_ctrl_iface_msg_cb); + + os_free(buf); + return priv; + +fail: + if (priv->sock >= 0) + close(priv->sock); + os_free(priv); + if (fname) { + unlink(fname); + os_free(fname); + } + os_free(buf); + return NULL; +} + + +void wpa_supplicant_ctrl_iface_deinit(struct ctrl_iface_priv *priv) +{ + struct wpa_ctrl_dst *dst, *prev; + + if (priv->sock > -1) { + char *fname; + char *buf, *dir = NULL, *gid_str = NULL; + eloop_unregister_read_sock(priv->sock); + if (priv->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"); + os_sleep(1, 0); + } + close(priv->sock); + priv->sock = -1; + fname = wpa_supplicant_ctrl_iface_path(priv->wpa_s); + if (fname) { + unlink(fname); + os_free(fname); + } + + buf = os_strdup(priv->wpa_s->conf->ctrl_interface); + if (buf == NULL) + goto free_dst; + if (os_strncmp(buf, "DIR=", 4) == 0) { + dir = buf + 4; + gid_str = os_strstr(dir, " GROUP="); + if (gid_str) { + *gid_str = '\0'; + gid_str += 7; + } + } else + dir = buf; + + if (rmdir(dir) < 0) { + if (errno == ENOTEMPTY) { + wpa_printf(MSG_DEBUG, "Control interface " + "directory not empty - leaving it " + "behind"); + } else { + perror("rmdir[ctrl_interface]"); + } + } + os_free(buf); + } + +free_dst: + dst = priv->ctrl_dst; + while (dst) { + prev = dst; + dst = dst->next; + os_free(prev); + } + os_free(priv); +} + + +/** + * wpa_supplicant_ctrl_iface_send - Send a control interface packet to monitors + * @priv: Pointer to private data from wpa_supplicant_ctrl_iface_init() + * @level: Priority level of the message + * @buf: Message data + * @len: Message length + * + * Send a packet to all monitor programs attached to the control interface. + */ +static void wpa_supplicant_ctrl_iface_send(struct ctrl_iface_priv *priv, + int level, const char *buf, + size_t len) +{ + struct wpa_ctrl_dst *dst, *next; + char levelstr[10]; + int idx; + struct msghdr msg; + struct iovec io[2]; + + dst = priv->ctrl_dst; + if (priv->sock < 0 || dst == NULL) + return; + + os_snprintf(levelstr, sizeof(levelstr), "<%d>", level); + io[0].iov_base = levelstr; + io[0].iov_len = os_strlen(levelstr); + io[1].iov_base = (char *) buf; + io[1].iov_len = len; + os_memset(&msg, 0, sizeof(msg)); + msg.msg_iov = io; + msg.msg_iovlen = 2; + + idx = 0; + while (dst) { + next = dst->next; + if (level >= dst->debug_level) { + wpa_hexdump(MSG_DEBUG, "CTRL_IFACE monitor send", + (u8 *) dst->addr.sun_path, dst->addrlen - + sizeof(dst->addr.sun_family)); + msg.msg_name = (void *) &dst->addr; + msg.msg_namelen = dst->addrlen; + if (sendmsg(priv->sock, &msg, 0) < 0) { + perror("sendmsg(CTRL_IFACE monitor)"); + dst->errors++; + if (dst->errors > 10) { + wpa_supplicant_ctrl_iface_detach( + priv, &dst->addr, + dst->addrlen); + } + } else + dst->errors = 0; + } + idx++; + dst = next; + } +} + + +void wpa_supplicant_ctrl_iface_wait(struct ctrl_iface_priv *priv) +{ + wpa_printf(MSG_DEBUG, "CTRL_IFACE - %s - wait for monitor", + priv->wpa_s->ifname); + eloop_wait_for_read_sock(priv->sock); +} + + +/* Global ctrl_iface */ + +struct ctrl_iface_global_priv { + struct wpa_global *global; + int sock; +}; + + +static void wpa_supplicant_global_ctrl_iface_receive(int sock, void *eloop_ctx, + void *sock_ctx) +{ + struct wpa_global *global = eloop_ctx; + char buf[256]; + int res; + struct sockaddr_un from; + socklen_t fromlen = sizeof(from); + char *reply; + size_t reply_len; + + res = recvfrom(sock, buf, sizeof(buf) - 1, 0, + (struct sockaddr *) &from, &fromlen); + if (res < 0) { + perror("recvfrom(ctrl_iface)"); + return; + } + buf[res] = '\0'; + + reply = wpa_supplicant_global_ctrl_iface_process(global, buf, + &reply_len); + + if (reply) { + sendto(sock, reply, reply_len, 0, (struct sockaddr *) &from, + fromlen); + os_free(reply); + } else if (reply_len) { + sendto(sock, "FAIL\n", 5, 0, (struct sockaddr *) &from, + fromlen); + } +} + + +struct ctrl_iface_global_priv * +wpa_supplicant_global_ctrl_iface_init(struct wpa_global *global) +{ + struct ctrl_iface_global_priv *priv; + struct sockaddr_un addr; + + priv = os_zalloc(sizeof(*priv)); + if (priv == NULL) + return NULL; + priv->global = global; + priv->sock = -1; + + if (global->params.ctrl_interface == NULL) + return priv; + + wpa_printf(MSG_DEBUG, "Global control interface '%s'", + global->params.ctrl_interface); + + priv->sock = socket(PF_UNIX, SOCK_DGRAM, 0); + if (priv->sock < 0) { + perror("socket(PF_UNIX)"); + goto fail; + } + + os_memset(&addr, 0, sizeof(addr)); + addr.sun_family = AF_UNIX; + os_strncpy(addr.sun_path, global->params.ctrl_interface, + sizeof(addr.sun_path)); + if (bind(priv->sock, (struct sockaddr *) &addr, sizeof(addr)) < 0) { + perror("bind(PF_UNIX)"); + if (connect(priv->sock, (struct sockaddr *) &addr, + sizeof(addr)) < 0) { + wpa_printf(MSG_DEBUG, "ctrl_iface exists, but does not" + " allow connections - assuming it was left" + "over from forced program termination"); + if (unlink(global->params.ctrl_interface) < 0) { + perror("unlink[ctrl_iface]"); + wpa_printf(MSG_ERROR, "Could not unlink " + "existing ctrl_iface socket '%s'", + global->params.ctrl_interface); + goto fail; + } + if (bind(priv->sock, (struct sockaddr *) &addr, + sizeof(addr)) < 0) { + perror("bind(PF_UNIX)"); + goto fail; + } + wpa_printf(MSG_DEBUG, "Successfully replaced leftover " + "ctrl_iface socket '%s'", + global->params.ctrl_interface); + } else { + wpa_printf(MSG_INFO, "ctrl_iface exists and seems to " + "be in use - cannot override it"); + wpa_printf(MSG_INFO, "Delete '%s' manually if it is " + "not used anymore", + global->params.ctrl_interface); + goto fail; + } + } + + eloop_register_read_sock(priv->sock, + wpa_supplicant_global_ctrl_iface_receive, + global, NULL); + + return priv; + +fail: + if (priv->sock >= 0) + close(priv->sock); + os_free(priv); + return NULL; +} + + +void +wpa_supplicant_global_ctrl_iface_deinit(struct ctrl_iface_global_priv *priv) +{ + if (priv->sock >= 0) { + eloop_unregister_read_sock(priv->sock); + close(priv->sock); + } + if (priv->global->params.ctrl_interface) + unlink(priv->global->params.ctrl_interface); + os_free(priv); +} diff --git a/contrib/wpa_supplicant/dbus-wpa_supplicant.conf b/contrib/wpa_supplicant/dbus-wpa_supplicant.conf new file mode 100644 index 000000000000..1622af579030 --- /dev/null +++ b/contrib/wpa_supplicant/dbus-wpa_supplicant.conf @@ -0,0 +1,20 @@ +<!DOCTYPE busconfig PUBLIC + "-//freedesktop//DTD D-BUS Bus Configuration 1.0//EN" + "http://www.freedesktop.org/standards/dbus/1.0/busconfig.dtd"> +<busconfig> + <policy user="root"> + <allow own="fi.epitest.hostap.WPASupplicant"/> + + <allow send_destination="fi.epitest.hostap.WPASupplicant"/> + <allow send_interface="fi.epitest.hostap.WPASupplicant"/> + </policy> + <policy at_console="true"> + <allow send_destination="fi.epitest.hostap.WPASupplicant"/> + <allow send_interface="fi.epitest.hostap.WPASupplicant"/> + </policy> + <policy context="default"> + <deny own="fi.epitest.hostap.WPASupplicant"/> + <deny send_destination="fi.epitest.hostap.WPASupplicant"/> + <deny send_interface="fi.epitest.hostap.WPASupplicant"/> + </policy> +</busconfig> diff --git a/contrib/wpa_supplicant/dbus_dict_helpers.c b/contrib/wpa_supplicant/dbus_dict_helpers.c new file mode 100644 index 000000000000..2852ed522cd4 --- /dev/null +++ b/contrib/wpa_supplicant/dbus_dict_helpers.c @@ -0,0 +1,957 @@ +/* + * WPA Supplicant / dbus-based control interface + * Copyright (c) 2006, Dan Williams <dcbw@redhat.com> and Red Hat, Inc. + * + * 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 <dbus/dbus.h> +#include <string.h> +#include <stdio.h> +#include <stdlib.h> + +#include "common.h" +#include "dbus_dict_helpers.h" + + +/** + * Start a dict in a dbus message. Should be paired with a call to + * {@link wpa_dbus_dict_close_write}. + * + * @param iter A valid dbus message iterator + * @param iter_dict (out) A dict iterator to pass to further dict functions + * @return TRUE on success, FALSE on failure + * + */ +dbus_bool_t wpa_dbus_dict_open_write(DBusMessageIter *iter, + DBusMessageIter *iter_dict) +{ + dbus_bool_t result; + + if (!iter || !iter_dict) + return FALSE; + + result = dbus_message_iter_open_container( + iter, + DBUS_TYPE_ARRAY, + DBUS_DICT_ENTRY_BEGIN_CHAR_AS_STRING + DBUS_TYPE_STRING_AS_STRING + DBUS_TYPE_VARIANT_AS_STRING + DBUS_DICT_ENTRY_END_CHAR_AS_STRING, + iter_dict); + return result; +} + + +/** + * End a dict element in a dbus message. Should be paired with + * a call to {@link wpa_dbus_dict_open_write}. + * + * @param iter valid dbus message iterator, same as passed to + * wpa_dbus_dict_open_write() + * @param iter_dict a dbus dict iterator returned from + * {@link wpa_dbus_dict_open_write} + * @return TRUE on success, FALSE on failure + * + */ +dbus_bool_t wpa_dbus_dict_close_write(DBusMessageIter *iter, + DBusMessageIter *iter_dict) +{ + if (!iter || !iter_dict) + return FALSE; + + return dbus_message_iter_close_container(iter, iter_dict); +} + + +static const char * _wpa_get_type_as_string_from_type(const int type) +{ + switch(type) { + case DBUS_TYPE_BYTE: + return DBUS_TYPE_BYTE_AS_STRING; + case DBUS_TYPE_BOOLEAN: + return DBUS_TYPE_BOOLEAN_AS_STRING; + case DBUS_TYPE_INT16: + return DBUS_TYPE_INT16_AS_STRING; + case DBUS_TYPE_UINT16: + return DBUS_TYPE_UINT16_AS_STRING; + case DBUS_TYPE_INT32: + return DBUS_TYPE_INT32_AS_STRING; + case DBUS_TYPE_UINT32: + return DBUS_TYPE_UINT32_AS_STRING; + case DBUS_TYPE_INT64: + return DBUS_TYPE_INT64_AS_STRING; + case DBUS_TYPE_UINT64: + return DBUS_TYPE_UINT64_AS_STRING; + case DBUS_TYPE_DOUBLE: + return DBUS_TYPE_DOUBLE_AS_STRING; + case DBUS_TYPE_STRING: + return DBUS_TYPE_STRING_AS_STRING; + case DBUS_TYPE_OBJECT_PATH: + return DBUS_TYPE_OBJECT_PATH_AS_STRING; + case DBUS_TYPE_ARRAY: + return DBUS_TYPE_ARRAY_AS_STRING; + default: + return NULL; + } +} + + +static dbus_bool_t _wpa_dbus_add_dict_entry_start( + DBusMessageIter *iter_dict, DBusMessageIter *iter_dict_entry, + const char *key, const int value_type) +{ + if (!dbus_message_iter_open_container(iter_dict, + DBUS_TYPE_DICT_ENTRY, NULL, + iter_dict_entry)) + return FALSE; + + if (!dbus_message_iter_append_basic(iter_dict_entry, DBUS_TYPE_STRING, + &key)) + return FALSE; + + return TRUE; +} + + +static dbus_bool_t _wpa_dbus_add_dict_entry_end( + DBusMessageIter *iter_dict, DBusMessageIter *iter_dict_entry, + DBusMessageIter *iter_dict_val) +{ + if (!dbus_message_iter_close_container(iter_dict_entry, iter_dict_val)) + return FALSE; + if (!dbus_message_iter_close_container(iter_dict, iter_dict_entry)) + return FALSE; + + return TRUE; +} + + +static dbus_bool_t _wpa_dbus_add_dict_entry_basic(DBusMessageIter *iter_dict, + const char *key, + const int value_type, + const void *value) +{ + DBusMessageIter iter_dict_entry, iter_dict_val; + const char *type_as_string = NULL; + + type_as_string = _wpa_get_type_as_string_from_type(value_type); + if (!type_as_string) + return FALSE; + + if (!_wpa_dbus_add_dict_entry_start(iter_dict, &iter_dict_entry, + key, value_type)) + return FALSE; + + if (!dbus_message_iter_open_container(&iter_dict_entry, + DBUS_TYPE_VARIANT, + type_as_string, &iter_dict_val)) + return FALSE; + + if (!dbus_message_iter_append_basic(&iter_dict_val, value_type, value)) + return FALSE; + + if (!_wpa_dbus_add_dict_entry_end(iter_dict, &iter_dict_entry, + &iter_dict_val)) + return FALSE; + + return TRUE; +} + + +static dbus_bool_t _wpa_dbus_add_dict_entry_byte_array( + DBusMessageIter *iter_dict, const char *key, + const char *value, const dbus_uint32_t value_len) +{ + DBusMessageIter iter_dict_entry, iter_dict_val, iter_array; + dbus_uint32_t i; + + if (!_wpa_dbus_add_dict_entry_start(iter_dict, &iter_dict_entry, + key, DBUS_TYPE_ARRAY)) + return FALSE; + + if (!dbus_message_iter_open_container(&iter_dict_entry, + DBUS_TYPE_VARIANT, + DBUS_TYPE_ARRAY_AS_STRING + DBUS_TYPE_BYTE_AS_STRING, + &iter_dict_val)) + return FALSE; + + if (!dbus_message_iter_open_container(&iter_dict_val, DBUS_TYPE_ARRAY, + DBUS_TYPE_BYTE_AS_STRING, + &iter_array)) + return FALSE; + + for (i = 0; i < value_len; i++) { + if (!dbus_message_iter_append_basic(&iter_array, + DBUS_TYPE_BYTE, + &(value[i]))) + return FALSE; + } + + if (!dbus_message_iter_close_container(&iter_dict_val, &iter_array)) + return FALSE; + + if (!_wpa_dbus_add_dict_entry_end(iter_dict, &iter_dict_entry, + &iter_dict_val)) + return FALSE; + + return TRUE; +} + + +/** + * Add a string entry to the dict. + * + * @param iter_dict A valid DBusMessageIter returned from + * {@link wpa_dbus_dict_open_write} + * @param key The key of the dict item + * @param value The string value + * @return TRUE on success, FALSE on failure + * + */ +dbus_bool_t wpa_dbus_dict_append_string(DBusMessageIter *iter_dict, + const char *key, const char *value) +{ + if (!key || !value) + return FALSE; + return _wpa_dbus_add_dict_entry_basic(iter_dict, key, DBUS_TYPE_STRING, + &value); +} + + +/** + * Add a byte entry to the dict. + * + * @param iter_dict A valid DBusMessageIter returned from + * {@link wpa_dbus_dict_open_write} + * @param key The key of the dict item + * @param value The byte value + * @return TRUE on success, FALSE on failure + * + */ +dbus_bool_t wpa_dbus_dict_append_byte(DBusMessageIter *iter_dict, + const char *key, const char value) +{ + if (!key) + return FALSE; + return _wpa_dbus_add_dict_entry_basic(iter_dict, key, DBUS_TYPE_BYTE, + &value); +} + + +/** + * Add a boolean entry to the dict. + * + * @param iter_dict A valid DBusMessageIter returned from + * {@link wpa_dbus_dict_open_write} + * @param key The key of the dict item + * @param value The boolean value + * @return TRUE on success, FALSE on failure + * + */ +dbus_bool_t wpa_dbus_dict_append_bool(DBusMessageIter *iter_dict, + const char *key, const dbus_bool_t value) +{ + if (!key) + return FALSE; + return _wpa_dbus_add_dict_entry_basic(iter_dict, key, + DBUS_TYPE_BOOLEAN, &value); +} + + +/** + * Add a 16-bit signed integer entry to the dict. + * + * @param iter_dict A valid DBusMessageIter returned from + * {@link wpa_dbus_dict_open_write} + * @param key The key of the dict item + * @param value The 16-bit signed integer value + * @return TRUE on success, FALSE on failure + * + */ +dbus_bool_t wpa_dbus_dict_append_int16(DBusMessageIter *iter_dict, + const char *key, + const dbus_int16_t value) +{ + if (!key) + return FALSE; + return _wpa_dbus_add_dict_entry_basic(iter_dict, key, DBUS_TYPE_INT16, + &value); +} + + +/** + * Add a 16-bit unsigned integer entry to the dict. + * + * @param iter_dict A valid DBusMessageIter returned from + * {@link wpa_dbus_dict_open_write} + * @param key The key of the dict item + * @param value The 16-bit unsigned integer value + * @return TRUE on success, FALSE on failure + * + */ +dbus_bool_t wpa_dbus_dict_append_uint16(DBusMessageIter *iter_dict, + const char *key, + const dbus_uint16_t value) +{ + if (!key) + return FALSE; + return _wpa_dbus_add_dict_entry_basic(iter_dict, key, DBUS_TYPE_UINT16, + &value); +} + + +/** + * Add a 32-bit signed integer to the dict. + * + * @param iter_dict A valid DBusMessageIter returned from + * {@link wpa_dbus_dict_open_write} + * @param key The key of the dict item + * @param value The 32-bit signed integer value + * @return TRUE on success, FALSE on failure + * + */ +dbus_bool_t wpa_dbus_dict_append_int32(DBusMessageIter *iter_dict, + const char *key, + const dbus_int32_t value) +{ + if (!key) + return FALSE; + return _wpa_dbus_add_dict_entry_basic(iter_dict, key, DBUS_TYPE_INT32, + &value); +} + + +/** + * Add a 32-bit unsigned integer entry to the dict. + * + * @param iter_dict A valid DBusMessageIter returned from + * {@link wpa_dbus_dict_open_write} + * @param key The key of the dict item + * @param value The 32-bit unsigned integer value + * @return TRUE on success, FALSE on failure + * + */ +dbus_bool_t wpa_dbus_dict_append_uint32(DBusMessageIter *iter_dict, + const char *key, + const dbus_uint32_t value) +{ + if (!key) + return FALSE; + return _wpa_dbus_add_dict_entry_basic(iter_dict, key, DBUS_TYPE_UINT32, + &value); +} + + +/** + * Add a 64-bit integer entry to the dict. + * + * @param iter_dict A valid DBusMessageIter returned from + * {@link wpa_dbus_dict_open_write} + * @param key The key of the dict item + * @param value The 64-bit integer value + * @return TRUE on success, FALSE on failure + * + */ +dbus_bool_t wpa_dbus_dict_append_int64(DBusMessageIter *iter_dict, + const char *key, + const dbus_int64_t value) +{ + if (!key) + return FALSE; + return _wpa_dbus_add_dict_entry_basic(iter_dict, key, DBUS_TYPE_INT64, + &value); +} + + +/** + * Add a 64-bit unsigned integer entry to the dict. + * + * @param iter_dict A valid DBusMessageIter returned from + * {@link wpa_dbus_dict_open_write} + * @param key The key of the dict item + * @param value The 64-bit unsigned integer value + * @return TRUE on success, FALSE on failure + * + */ +dbus_bool_t wpa_dbus_dict_append_uint64(DBusMessageIter *iter_dict, + const char *key, + const dbus_uint64_t value) +{ + if (!key) + return FALSE; + return _wpa_dbus_add_dict_entry_basic(iter_dict, key, DBUS_TYPE_UINT64, + &value); +} + + +/** + * Add a double-precision floating point entry to the dict. + * + * @param iter_dict A valid DBusMessageIter returned from + * {@link wpa_dbus_dict_open_write} + * @param key The key of the dict item + * @param value The double-precision floating point value + * @return TRUE on success, FALSE on failure + * + */ +dbus_bool_t wpa_dbus_dict_append_double(DBusMessageIter *iter_dict, + const char * key, + const double value) +{ + if (!key) + return FALSE; + return _wpa_dbus_add_dict_entry_basic(iter_dict, key, DBUS_TYPE_DOUBLE, + &value); +} + + +/** + * Add a DBus object path entry to the dict. + * + * @param iter_dict A valid DBusMessageIter returned from + * {@link wpa_dbus_dict_open_write} + * @param key The key of the dict item + * @param value The DBus object path value + * @return TRUE on success, FALSE on failure + * + */ +dbus_bool_t wpa_dbus_dict_append_object_path(DBusMessageIter *iter_dict, + const char *key, + const char *value) +{ + if (!key || !value) + return FALSE; + return _wpa_dbus_add_dict_entry_basic(iter_dict, key, + DBUS_TYPE_OBJECT_PATH, &value); +} + + +/** + * Add a byte array entry to the dict. + * + * @param iter_dict A valid DBusMessageIter returned from + * {@link wpa_dbus_dict_open_write} + * @param key The key of the dict item + * @param value The byte array + * @param value_len The length of the byte array, in bytes + * @return TRUE on success, FALSE on failure + * + */ +dbus_bool_t wpa_dbus_dict_append_byte_array(DBusMessageIter *iter_dict, + const char *key, + const char *value, + const dbus_uint32_t value_len) +{ + if (!key) + return FALSE; + if (!value && (value_len != 0)) + return FALSE; + return _wpa_dbus_add_dict_entry_byte_array(iter_dict, key, value, + value_len); +} + + +/** + * Begin a string array entry in the dict + * + * @param iter_dict A valid DBusMessageIter returned from + * {@link nmu_dbus_dict_open_write} + * @param key The key of the dict item + * @param iter_dict_entry A private DBusMessageIter provided by the caller to + * be passed to {@link wpa_dbus_dict_end_string_array} + * @param iter_dict_val A private DBusMessageIter provided by the caller to + * be passed to {@link wpa_dbus_dict_end_string_array} + * @param iter_array On return, the DBusMessageIter to be passed to + * {@link wpa_dbus_dict_string_array_add_element} + * @return TRUE on success, FALSE on failure + * + */ +dbus_bool_t wpa_dbus_dict_begin_string_array(DBusMessageIter *iter_dict, + const char *key, + DBusMessageIter *iter_dict_entry, + DBusMessageIter *iter_dict_val, + DBusMessageIter *iter_array) +{ + if (!iter_dict || !iter_dict_entry || !iter_dict_val || !iter_array) + return FALSE; + + if (!_wpa_dbus_add_dict_entry_start(iter_dict, iter_dict_entry, + key, DBUS_TYPE_ARRAY)) + return FALSE; + + if (!dbus_message_iter_open_container(iter_dict_entry, + DBUS_TYPE_VARIANT, + DBUS_TYPE_ARRAY_AS_STRING + DBUS_TYPE_STRING_AS_STRING, + iter_dict_val)) + return FALSE; + + if (!dbus_message_iter_open_container(iter_dict_val, DBUS_TYPE_ARRAY, + DBUS_TYPE_BYTE_AS_STRING, + iter_array)) + return FALSE; + + return TRUE; +} + + +/** + * Add a single string element to a string array dict entry + * + * @param iter_array A valid DBusMessageIter returned from + * {@link wpa_dbus_dict_begin_string_array}'s + * iter_array parameter + * @param elem The string element to be added to the dict entry's string array + * @return TRUE on success, FALSE on failure + * + */ +dbus_bool_t wpa_dbus_dict_string_array_add_element(DBusMessageIter *iter_array, + const char *elem) +{ + if (!iter_array || !elem) + return FALSE; + + return dbus_message_iter_append_basic(iter_array, DBUS_TYPE_STRING, + &elem); +} + + +/** + * End a string array dict entry + * + * @param iter_dict A valid DBusMessageIter returned from + * {@link nmu_dbus_dict_open_write} + * @param iter_dict_entry A private DBusMessageIter returned from + * {@link wpa_dbus_dict_end_string_array} + * @param iter_dict_val A private DBusMessageIter returned from + * {@link wpa_dbus_dict_end_string_array} + * @param iter_array A DBusMessageIter returned from + * {@link wpa_dbus_dict_end_string_array} + * @return TRUE on success, FALSE on failure + * + */ +dbus_bool_t wpa_dbus_dict_end_string_array(DBusMessageIter *iter_dict, + DBusMessageIter *iter_dict_entry, + DBusMessageIter *iter_dict_val, + DBusMessageIter *iter_array) +{ + if (!iter_dict || !iter_dict_entry || !iter_dict_val || !iter_array) + return FALSE; + + if (!dbus_message_iter_close_container(iter_dict_val, iter_array)) + return FALSE; + + if (!_wpa_dbus_add_dict_entry_end(iter_dict, iter_dict_entry, + iter_dict_val)) + return FALSE; + + return TRUE; +} + + +/** + * Convenience function to add an entire string array to the dict. + * + * @param iter_dict A valid DBusMessageIter returned from + * {@link nmu_dbus_dict_open_write} + * @param key The key of the dict item + * @param items The array of strings + * @param num_items The number of strings in the array + * @return TRUE on success, FALSE on failure + * + */ +dbus_bool_t wpa_dbus_dict_append_string_array(DBusMessageIter *iter_dict, + const char *key, + const char **items, + const dbus_uint32_t num_items) +{ + DBusMessageIter iter_dict_entry, iter_dict_val, iter_array; + dbus_uint32_t i; + + if (!key) + return FALSE; + if (!items && (num_items != 0)) + return FALSE; + + if (!wpa_dbus_dict_begin_string_array(iter_dict, key, + &iter_dict_entry, &iter_dict_val, + &iter_array)) + return FALSE; + + for (i = 0; i < num_items; i++) { + if (!wpa_dbus_dict_string_array_add_element(&iter_array, + items[i])) + return FALSE; + } + + if (!wpa_dbus_dict_end_string_array(iter_dict, &iter_dict_entry, + &iter_dict_val, &iter_array)) + return FALSE; + + return TRUE; +} + + +/*****************************************************/ +/* Stuff for reading dicts */ +/*****************************************************/ + +/** + * Start reading from a dbus dict. + * + * @param iter A valid DBusMessageIter pointing to the start of the dict + * @param iter_dict (out) A DBusMessageIter to be passed to + * {@link wpa_dbus_dict_read_next_entry} + * @return TRUE on success, FALSE on failure + * + */ +dbus_bool_t wpa_dbus_dict_open_read(DBusMessageIter *iter, + DBusMessageIter *iter_dict) +{ + if (!iter || !iter_dict) + return FALSE; + + if (dbus_message_iter_get_arg_type(iter) != DBUS_TYPE_ARRAY || + dbus_message_iter_get_element_type(iter) != DBUS_TYPE_DICT_ENTRY) + return FALSE; + + dbus_message_iter_recurse(iter, iter_dict); + return TRUE; +} + + +static dbus_bool_t _wpa_dbus_dict_entry_get_byte_array( + DBusMessageIter *iter, int array_len, int array_type, + struct wpa_dbus_dict_entry *entry) +{ + dbus_uint32_t i = 0; + dbus_bool_t success = FALSE; + char byte; + + /* Zero-length arrays are valid. */ + if (array_len == 0) { + entry->bytearray_value = NULL; + entry->array_type = DBUS_TYPE_BYTE; + success = TRUE; + goto done; + } + + entry->bytearray_value = wpa_zalloc(array_len * sizeof(char)); + if (!entry->bytearray_value) { + perror("_wpa_dbus_dict_entry_get_byte_array[dbus]: out of " + "memory"); + goto done; + } + + entry->array_type = DBUS_TYPE_BYTE; + entry->array_len = array_len; + while (dbus_message_iter_get_arg_type(iter) == DBUS_TYPE_BYTE) { + dbus_message_iter_get_basic(iter, &byte); + entry->bytearray_value[i++] = byte; + dbus_message_iter_next(iter); + } + success = TRUE; + +done: + return success; +} + + +static dbus_bool_t _wpa_dbus_dict_entry_get_string_array( + DBusMessageIter *iter, int array_len, int array_type, + struct wpa_dbus_dict_entry *entry) +{ + dbus_uint32_t count = 0; + dbus_bool_t success = FALSE; + char **buffer; + + entry->strarray_value = NULL; + entry->array_type = DBUS_TYPE_STRING; + + /* Zero-length arrays are valid. */ + if (array_len == 0) { + success = TRUE; + goto done; + } + + buffer = wpa_zalloc(sizeof (char *) * 8); + if (buffer == NULL) { + perror("_wpa_dbus_dict_entry_get_string_array[dbus] out of " + "memory trying to retrieve a string array"); + goto done; + } + + entry->strarray_value = buffer; + entry->array_len = 0; + while (dbus_message_iter_get_arg_type(iter) == DBUS_TYPE_STRING) { + const char *value; + char *str; + + if ((count % 8) == 0 && count != 0) { + char **tmp; + tmp = realloc(buffer, sizeof(char *) * (count + 8)); + if (tmp == NULL) { + perror("_wpa_dbus_dict_entry_get_string_array[" + "dbus] out of memory trying to " + "retrieve the string array"); + free(buffer); + buffer = NULL; + goto done; + } + buffer = tmp; + } + entry->strarray_value = buffer; + + dbus_message_iter_get_basic(iter, &value); + str = strdup(value); + if (str == NULL) { + perror("_wpa_dbus_dict_entry_get_string_array[dbus] " + "out of memory trying to duplicate the string " + "array"); + goto done; + } + entry->strarray_value[count] = str; + entry->array_len = ++count; + dbus_message_iter_next(iter); + } + success = TRUE; + +done: + return success; +} + + +static dbus_bool_t _wpa_dbus_dict_entry_get_array( + DBusMessageIter *iter_dict_val, struct wpa_dbus_dict_entry *entry) +{ + int array_type = dbus_message_iter_get_element_type(iter_dict_val); + int array_len; + dbus_bool_t success = FALSE; + DBusMessageIter iter_array; + + if (!entry) + return FALSE; + + dbus_message_iter_recurse(iter_dict_val, &iter_array); + + array_len = dbus_message_iter_get_array_len(&iter_array); + if (array_len < 0) + return FALSE; + + switch (array_type) { + case DBUS_TYPE_BYTE: + success = _wpa_dbus_dict_entry_get_byte_array(&iter_array, + array_len, + array_type, + entry); + break; + case DBUS_TYPE_STRING: + success = _wpa_dbus_dict_entry_get_string_array(&iter_array, + array_len, + array_type, + entry); + break; + default: + break; + } + + return success; +} + + +static dbus_bool_t _wpa_dbus_dict_fill_value_from_variant( + struct wpa_dbus_dict_entry *entry, DBusMessageIter *iter_dict_val) +{ + dbus_bool_t success = TRUE; + + switch (entry->type) { + case DBUS_TYPE_STRING: { + const char *v; + dbus_message_iter_get_basic(iter_dict_val, &v); + entry->str_value = strdup(v); + break; + } + case DBUS_TYPE_BOOLEAN: { + dbus_bool_t v; + dbus_message_iter_get_basic(iter_dict_val, &v); + entry->bool_value = v; + break; + } + case DBUS_TYPE_BYTE: { + char v; + dbus_message_iter_get_basic(iter_dict_val, &v); + entry->byte_value = v; + break; + } + case DBUS_TYPE_INT16: { + dbus_int16_t v; + dbus_message_iter_get_basic(iter_dict_val, &v); + entry->int16_value = v; + break; + } + case DBUS_TYPE_UINT16: { + dbus_uint16_t v; + dbus_message_iter_get_basic(iter_dict_val, &v); + entry->uint16_value = v; + break; + } + case DBUS_TYPE_INT32: { + dbus_int32_t v; + dbus_message_iter_get_basic(iter_dict_val, &v); + entry->int32_value = v; + break; + } + case DBUS_TYPE_UINT32: { + dbus_uint32_t v; + dbus_message_iter_get_basic(iter_dict_val, &v); + entry->uint32_value = v; + break; + } + case DBUS_TYPE_INT64: { + dbus_int64_t v; + dbus_message_iter_get_basic(iter_dict_val, &v); + entry->int64_value = v; + break; + } + case DBUS_TYPE_UINT64: { + dbus_uint64_t v; + dbus_message_iter_get_basic(iter_dict_val, &v); + entry->uint64_value = v; + break; + } + case DBUS_TYPE_DOUBLE: { + double v; + dbus_message_iter_get_basic(iter_dict_val, &v); + entry->double_value = v; + break; + } + case DBUS_TYPE_OBJECT_PATH: { + char *v; + dbus_message_iter_get_basic(iter_dict_val, &v); + entry->str_value = strdup(v); + break; + } + case DBUS_TYPE_ARRAY: { + success = _wpa_dbus_dict_entry_get_array(iter_dict_val, entry); + break; + } + default: + success = FALSE; + break; + } + + return success; +} + + +/** + * Read the current key/value entry from the dict. Entries are dynamically + * allocated when needed and must be freed after use with the + * {@link wpa_dbus_dict_entry_clear} function. + * + * The returned entry object will be filled with the type and value of the next + * entry in the dict, or the type will be DBUS_TYPE_INVALID if an error + * occurred. + * + * @param iter_dict A valid DBusMessageIter returned from + * {@link wpa_dbus_dict_open_read} + * @param entry A valid dict entry object into which the dict key and value + * will be placed + * @return TRUE on success, FALSE on failure + * + */ +dbus_bool_t wpa_dbus_dict_get_entry(DBusMessageIter *iter_dict, + struct wpa_dbus_dict_entry * entry) +{ + DBusMessageIter iter_dict_entry, iter_dict_val; + int type; + const char *key; + + if (!iter_dict || !entry) + goto error; + + if (dbus_message_iter_get_arg_type(iter_dict) != DBUS_TYPE_DICT_ENTRY) + goto error; + + dbus_message_iter_recurse(iter_dict, &iter_dict_entry); + dbus_message_iter_get_basic(&iter_dict_entry, &key); + entry->key = key; + + if (!dbus_message_iter_next(&iter_dict_entry)) + goto error; + type = dbus_message_iter_get_arg_type(&iter_dict_entry); + if (type != DBUS_TYPE_VARIANT) + goto error; + + dbus_message_iter_recurse(&iter_dict_entry, &iter_dict_val); + entry->type = dbus_message_iter_get_arg_type(&iter_dict_val); + if (!_wpa_dbus_dict_fill_value_from_variant(entry, &iter_dict_val)) + goto error; + + dbus_message_iter_next(iter_dict); + return TRUE; + +error: + if (entry) { + wpa_dbus_dict_entry_clear(entry); + entry->type = DBUS_TYPE_INVALID; + entry->array_type = DBUS_TYPE_INVALID; + } + + return FALSE; +} + + +/** + * Return whether or not there are additional dictionary entries. + * + * @param iter_dict A valid DBusMessageIter returned from + * {@link wpa_dbus_dict_open_read} + * @return TRUE if more dict entries exists, FALSE if no more dict entries + * exist + */ +dbus_bool_t wpa_dbus_dict_has_dict_entry(DBusMessageIter *iter_dict) +{ + if (!iter_dict) { + perror("wpa_dbus_dict_has_dict_entry[dbus]: out of memory"); + return FALSE; + } + return dbus_message_iter_get_arg_type(iter_dict) == + DBUS_TYPE_DICT_ENTRY; +} + + +/** + * Free any memory used by the entry object. + * + * @param entry The entry object + */ +void wpa_dbus_dict_entry_clear(struct wpa_dbus_dict_entry *entry) +{ + if (!entry) + return; + switch (entry->type) { + case DBUS_TYPE_OBJECT_PATH: + case DBUS_TYPE_STRING: + free(entry->str_value); + break; + case DBUS_TYPE_ARRAY: + switch (entry->array_type) { + case DBUS_TYPE_BYTE: + free(entry->bytearray_value); + break; + } + break; + } + + memset(entry, 0, sizeof(struct wpa_dbus_dict_entry)); +} diff --git a/contrib/wpa_supplicant/dbus_dict_helpers.h b/contrib/wpa_supplicant/dbus_dict_helpers.h new file mode 100644 index 000000000000..f873efcbcb13 --- /dev/null +++ b/contrib/wpa_supplicant/dbus_dict_helpers.h @@ -0,0 +1,135 @@ +/* + * WPA Supplicant / dbus-based control interface + * Copyright (c) 2006, Dan Williams <dcbw@redhat.com> and Red Hat, Inc. + * + * 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. + */ + +#ifndef DBUS_DICT_HELPERS_H +#define DBUS_DICT_HELPERS_H + +/* + * Adding a dict to a DBusMessage + */ + +dbus_bool_t wpa_dbus_dict_open_write(DBusMessageIter *iter, + DBusMessageIter *iter_dict); + +dbus_bool_t wpa_dbus_dict_close_write(DBusMessageIter *iter, + DBusMessageIter *iter_dict); + +dbus_bool_t wpa_dbus_dict_append_string(DBusMessageIter *iter_dict, + const char *key, const char *value); + +dbus_bool_t wpa_dbus_dict_append_byte(DBusMessageIter *iter_dict, + const char *key, const char value); + +dbus_bool_t wpa_dbus_dict_append_bool(DBusMessageIter *iter_dict, + const char *key, + const dbus_bool_t value); + +dbus_bool_t wpa_dbus_dict_append_int16(DBusMessageIter *iter_dict, + const char *key, + const dbus_int16_t value); + +dbus_bool_t wpa_dbus_dict_append_uint16(DBusMessageIter *iter_dict, + const char *key, + const dbus_uint16_t value); + +dbus_bool_t wpa_dbus_dict_append_int32(DBusMessageIter *iter_dict, + const char *key, + const dbus_int32_t value); + +dbus_bool_t wpa_dbus_dict_append_uint32(DBusMessageIter *iter_dict, + const char *key, + const dbus_uint32_t value); + +dbus_bool_t wpa_dbus_dict_append_int64(DBusMessageIter *iter_dict, + const char *key, + const dbus_int64_t value); + +dbus_bool_t wpa_dbus_dict_append_uint64(DBusMessageIter *iter_dict, + const char *key, + const dbus_uint64_t value); + +dbus_bool_t wpa_dbus_dict_append_double(DBusMessageIter *iter_dict, + const char *key, + const double value); + +dbus_bool_t wpa_dbus_dict_append_object_path(DBusMessageIter *iter_dict, + const char *key, + const char *value); + +dbus_bool_t wpa_dbus_dict_append_byte_array(DBusMessageIter *iter_dict, + const char *key, + const char *value, + const dbus_uint32_t value_len); + +/* Manual construction and addition of string array elements */ +dbus_bool_t wpa_dbus_dict_begin_string_array(DBusMessageIter *iter_dict, + const char *key, + DBusMessageIter *iter_dict_entry, + DBusMessageIter *iter_dict_val, + DBusMessageIter *iter_array); + +dbus_bool_t wpa_dbus_dict_string_array_add_element(DBusMessageIter *iter_array, + const char *elem); + +dbus_bool_t wpa_dbus_dict_end_string_array(DBusMessageIter *iter_dict, + DBusMessageIter *iter_dict_entry, + DBusMessageIter *iter_dict_val, + DBusMessageIter *iter_array); + +/* Convenience function to add a whole string list */ +dbus_bool_t wpa_dbus_dict_append_string_array(DBusMessageIter *iter_dict, + const char *key, + const char **items, + const dbus_uint32_t num_items); + +/* + * Reading a dict from a DBusMessage + */ + +struct wpa_dbus_dict_entry { + int type; /** the dbus type of the dict entry's value */ + int array_type; /** the dbus type of the array elements if the dict + entry value contains an array */ + const char *key; /** key of the dict entry */ + + /** Possible values of the property */ + union { + char *str_value; + char byte_value; + dbus_bool_t bool_value; + dbus_int16_t int16_value; + dbus_uint16_t uint16_value; + dbus_int32_t int32_value; + dbus_uint32_t uint32_value; + dbus_int64_t int64_value; + dbus_uint64_t uint64_value; + double double_value; + char *bytearray_value; + char **strarray_value; + }; + dbus_uint32_t array_len; /** length of the array if the dict entry's + value contains an array */ +}; + +dbus_bool_t wpa_dbus_dict_open_read(DBusMessageIter *iter, + DBusMessageIter *iter_dict); |