aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorSam Leffler <sam@FreeBSD.org>2007-07-11 15:48:36 +0000
committerSam Leffler <sam@FreeBSD.org>2007-07-11 15:48:36 +0000
commit7700b89cce864f82dbd9cf54979c59dd06ca9356 (patch)
treec3da7f33886a852f7dceb74373fbdeec49a48f77
parent4e0922e888407f6dd91546a040e26125317fcfd8 (diff)
downloadsrc-7700b89cce864f82dbd9cf54979c59dd06ca9356.tar.gz
src-7700b89cce864f82dbd9cf54979c59dd06ca9356.zip
Import of WPA supplicant 0.5.8
Notes
Notes: svn path=/vendor/wpa_supplicant/dist/; revision=171366
-rw-r--r--contrib/wpa_supplicant/COPYING4
-rw-r--r--contrib/wpa_supplicant/ChangeLog328
-rw-r--r--contrib/wpa_supplicant/FREEBSD-Xlist19
-rw-r--r--contrib/wpa_supplicant/FREEBSD-upgrade8
-rw-r--r--contrib/wpa_supplicant/Makefile530
-rw-r--r--contrib/wpa_supplicant/README102
-rw-r--r--contrib/wpa_supplicant/aes.c12
-rw-r--r--contrib/wpa_supplicant/aes.h25
-rw-r--r--contrib/wpa_supplicant/aes_wrap.c377
-rw-r--r--contrib/wpa_supplicant/aes_wrap.h2
-rw-r--r--contrib/wpa_supplicant/asn1.c205
-rw-r--r--contrib/wpa_supplicant/asn1.h71
-rw-r--r--contrib/wpa_supplicant/asn1_test.c210
-rw-r--r--contrib/wpa_supplicant/base64.c32
-rw-r--r--contrib/wpa_supplicant/base64.h2
-rw-r--r--contrib/wpa_supplicant/bignum.c230
-rw-r--r--contrib/wpa_supplicant/bignum.h38
-rw-r--r--contrib/wpa_supplicant/build_config.h50
-rw-r--r--contrib/wpa_supplicant/common.c479
-rw-r--r--contrib/wpa_supplicant/common.h312
-rw-r--r--contrib/wpa_supplicant/config.c713
-rw-r--r--contrib/wpa_supplicant/config.h82
-rw-r--r--contrib/wpa_supplicant/config_file.c365
-rw-r--r--contrib/wpa_supplicant/config_none.c57
-rw-r--r--contrib/wpa_supplicant/config_ssid.h121
-rw-r--r--contrib/wpa_supplicant/config_types.h14
-rw-r--r--contrib/wpa_supplicant/config_winreg.c882
-rw-r--r--contrib/wpa_supplicant/crypto.c87
-rw-r--r--contrib/wpa_supplicant/crypto.h308
-rw-r--r--contrib/wpa_supplicant/crypto_cryptoapi.c801
-rw-r--r--contrib/wpa_supplicant/crypto_gnutls.c14
-rw-r--r--contrib/wpa_supplicant/crypto_internal.c670
-rw-r--r--contrib/wpa_supplicant/crypto_libtomcrypt.c736
-rw-r--r--contrib/wpa_supplicant/crypto_none.c28
-rw-r--r--contrib/wpa_supplicant/ctrl_iface.c1401
-rw-r--r--contrib/wpa_supplicant/ctrl_iface.h127
-rw-r--r--contrib/wpa_supplicant/ctrl_iface_dbus.c1043
-rw-r--r--contrib/wpa_supplicant/ctrl_iface_dbus.h146
-rw-r--r--contrib/wpa_supplicant/ctrl_iface_dbus_handlers.c1205
-rw-r--r--contrib/wpa_supplicant/ctrl_iface_dbus_handlers.h77
-rw-r--r--contrib/wpa_supplicant/ctrl_iface_named_pipe.c834
-rw-r--r--contrib/wpa_supplicant/ctrl_iface_udp.c561
-rw-r--r--contrib/wpa_supplicant/ctrl_iface_unix.c656
-rw-r--r--contrib/wpa_supplicant/dbus-wpa_supplicant.conf20
-rw-r--r--contrib/wpa_supplicant/dbus_dict_helpers.c957
-rw-r--r--contrib/wpa_supplicant/dbus_dict_helpers.h135
-rw-r--r--contrib/wpa_supplicant/defconfig162
-rw-r--r--contrib/wpa_supplicant/defs.h13
-rw-r--r--contrib/wpa_supplicant/des.c476
-rw-r--r--contrib/wpa_supplicant/doc/code_structure.doxygen6
-rw-r--r--contrib/wpa_supplicant/doc/ctrl_iface.doxygen30
-rw-r--r--contrib/wpa_supplicant/doc/docbook/wpa_background.84
-rw-r--r--contrib/wpa_supplicant/doc/docbook/wpa_background.sgml2
-rw-r--r--contrib/wpa_supplicant/doc/docbook/wpa_cli.815
-rw-r--r--contrib/wpa_supplicant/doc/docbook/wpa_cli.sgml14
-rw-r--r--contrib/wpa_supplicant/doc/docbook/wpa_passphrase.89
-rw-r--r--contrib/wpa_supplicant/doc/docbook/wpa_passphrase.sgml7
-rw-r--r--contrib/wpa_supplicant/doc/docbook/wpa_supplicant.817
-rw-r--r--contrib/wpa_supplicant/doc/docbook/wpa_supplicant.conf.58
-rw-r--r--contrib/wpa_supplicant/doc/docbook/wpa_supplicant.conf.sgml6
-rw-r--r--contrib/wpa_supplicant/doc/docbook/wpa_supplicant.sgml26
-rw-r--r--contrib/wpa_supplicant/doc/doxygen.fast2
-rw-r--r--contrib/wpa_supplicant/doc/doxygen.full4
-rw-r--r--contrib/wpa_supplicant/doc/eap.doxygen28
-rwxr-xr-xcontrib/wpa_supplicant/doc/kerneldoc2doxygen.pl4
-rw-r--r--contrib/wpa_supplicant/doc/mainpage.doxygen2
-rw-r--r--contrib/wpa_supplicant/doc/porting.doxygen91
-rw-r--r--contrib/wpa_supplicant/doc/testing_tools.doxygen9
-rw-r--r--contrib/wpa_supplicant/driver.h208
-rw-r--r--contrib/wpa_supplicant/driver_hostap.h2
-rw-r--r--contrib/wpa_supplicant/driver_ndis.c1500
-rw-r--r--contrib/wpa_supplicant/driver_ndis.h29
-rw-r--r--contrib/wpa_supplicant/driver_wired.c73
-rw-r--r--contrib/wpa_supplicant/drivers.c16
-rw-r--r--contrib/wpa_supplicant/eap.c1170
-rw-r--r--contrib/wpa_supplicant/eap.h62
-rw-r--r--contrib/wpa_supplicant/eap_aka.c342
-rw-r--r--contrib/wpa_supplicant/eap_defs.h39
-rw-r--r--contrib/wpa_supplicant/eap_fast.c736
-rw-r--r--contrib/wpa_supplicant/eap_gpsk.c583
-rw-r--r--contrib/wpa_supplicant/eap_gpsk_common.c441
-rw-r--r--contrib/wpa_supplicant/eap_gpsk_common.h66
-rw-r--r--contrib/wpa_supplicant/eap_gtc.c120
-rw-r--r--contrib/wpa_supplicant/eap_i.h84
-rw-r--r--contrib/wpa_supplicant/eap_leap.c148
-rw-r--r--contrib/wpa_supplicant/eap_md5.c89
-rw-r--r--contrib/wpa_supplicant/eap_methods.c500
-rw-r--r--contrib/wpa_supplicant/eap_methods.h87
-rw-r--r--contrib/wpa_supplicant/eap_mschapv2.c796
-rw-r--r--contrib/wpa_supplicant/eap_otp.c81
-rw-r--r--contrib/wpa_supplicant/eap_pax.c117
-rw-r--r--contrib/wpa_supplicant/eap_pax_common.c20
-rw-r--r--contrib/wpa_supplicant/eap_pax_common.h31
-rw-r--r--contrib/wpa_supplicant/eap_peap.c291
-rw-r--r--contrib/wpa_supplicant/eap_psk.c169
-rw-r--r--contrib/wpa_supplicant/eap_psk_common.c25
-rw-r--r--contrib/wpa_supplicant/eap_psk_common.h29
-rw-r--r--contrib/wpa_supplicant/eap_sake.c515
-rw-r--r--contrib/wpa_supplicant/eap_sake_common.c380
-rw-r--r--contrib/wpa_supplicant/eap_sake_common.h104
-rw-r--r--contrib/wpa_supplicant/eap_sim.c371
-rw-r--r--contrib/wpa_supplicant/eap_sim_common.c316
-rw-r--r--contrib/wpa_supplicant/eap_sim_common.h76
-rw-r--r--contrib/wpa_supplicant/eap_testing.txt14
-rw-r--r--contrib/wpa_supplicant/eap_tls.c183
-rw-r--r--contrib/wpa_supplicant/eap_tls_common.c579
-rw-r--r--contrib/wpa_supplicant/eap_tls_common.h11
-rw-r--r--contrib/wpa_supplicant/eap_tlv.c68
-rw-r--r--contrib/wpa_supplicant/eap_tlv.h24
-rw-r--r--contrib/wpa_supplicant/eap_ttls.c817
-rw-r--r--contrib/wpa_supplicant/eap_ttls.h14
-rw-r--r--contrib/wpa_supplicant/eap_vendor_test.c198
-rw-r--r--contrib/wpa_supplicant/eapol_sm.c328
-rw-r--r--contrib/wpa_supplicant/eapol_sm.h12
-rw-r--r--contrib/wpa_supplicant/eapol_test.c293
-rw-r--r--contrib/wpa_supplicant/eloop.c332
-rw-r--r--contrib/wpa_supplicant/eloop.h207
-rw-r--r--contrib/wpa_supplicant/eloop_none.c390
-rw-r--r--contrib/wpa_supplicant/eloop_win.c604
-rw-r--r--contrib/wpa_supplicant/events.c253
-rw-r--r--contrib/wpa_supplicant/hostapd.h9
-rw-r--r--contrib/wpa_supplicant/includes.h57
-rw-r--r--contrib/wpa_supplicant/l2_packet.h12
-rw-r--r--contrib/wpa_supplicant/libtommath.c2370
-rw-r--r--contrib/wpa_supplicant/main.c110
-rw-r--r--contrib/wpa_supplicant/md4.c282
-rw-r--r--contrib/wpa_supplicant/md5.c53
-rw-r--r--contrib/wpa_supplicant/md5.h11
-rw-r--r--contrib/wpa_supplicant/mlme.c2897
-rw-r--r--contrib/wpa_supplicant/mlme.h104
-rw-r--r--contrib/wpa_supplicant/ms_funcs.c245
-rw-r--r--contrib/wpa_supplicant/ms_funcs.h13
-rw-r--r--contrib/wpa_supplicant/nmake.mak188
-rw-r--r--contrib/wpa_supplicant/openssl-0.9.8d-tls-extensions.patch429
-rw-r--r--contrib/wpa_supplicant/openssl-0.9.8e-tls-extensions.patch353
-rw-r--r--contrib/wpa_supplicant/os.h485
-rw-r--r--contrib/wpa_supplicant/os_internal.c441
-rw-r--r--contrib/wpa_supplicant/os_none.c220
-rw-r--r--contrib/wpa_supplicant/os_unix.c212
-rw-r--r--contrib/wpa_supplicant/pcsc_funcs.c599
-rw-r--r--contrib/wpa_supplicant/pcsc_funcs.h10
-rw-r--r--contrib/wpa_supplicant/pmksa_cache.c502
-rw-r--r--contrib/wpa_supplicant/pmksa_cache.h116
-rw-r--r--contrib/wpa_supplicant/preauth.c530
-rw-r--r--contrib/wpa_supplicant/preauth.h53
-rw-r--r--contrib/wpa_supplicant/preauth_test.c77
-rw-r--r--contrib/wpa_supplicant/radius.c295
-rw-r--r--contrib/wpa_supplicant/radius.h48
-rw-r--r--contrib/wpa_supplicant/radius_client.c427
-rw-r--r--contrib/wpa_supplicant/radius_client.h22
-rw-r--r--contrib/wpa_supplicant/rc4.c7
-rw-r--r--contrib/wpa_supplicant/rc4.h2
-rw-r--r--contrib/wpa_supplicant/rsa.c359
-rw-r--r--contrib/wpa_supplicant/rsa.h29
-rw-r--r--contrib/wpa_supplicant/sha1.c470
-rw-r--r--contrib/wpa_supplicant/sha1.h10
-rw-r--r--contrib/wpa_supplicant/sha256.c379
-rw-r--r--contrib/wpa_supplicant/sha256.h27
-rw-r--r--contrib/wpa_supplicant/state_machine.h144
-rw-r--r--contrib/wpa_supplicant/tls.h182
-rw-r--r--contrib/wpa_supplicant/tls_gnutls.c772
-rw-r--r--contrib/wpa_supplicant/tls_internal.c326
-rw-r--r--contrib/wpa_supplicant/tls_none.c219
-rw-r--r--contrib/wpa_supplicant/tls_openssl.c418
-rw-r--r--contrib/wpa_supplicant/tls_schannel.c172
-rw-r--r--contrib/wpa_supplicant/tlsv1_client.c2609
-rw-r--r--contrib/wpa_supplicant/tlsv1_client.h58
-rw-r--r--contrib/wpa_supplicant/tlsv1_common.c552
-rw-r--r--contrib/wpa_supplicant/tlsv1_common.h233
-rw-r--r--contrib/wpa_supplicant/todo.txt93
-rw-r--r--contrib/wpa_supplicant/version.h2
-rw-r--r--contrib/wpa_supplicant/wpa.c2289
-rw-r--r--contrib/wpa_supplicant/wpa.h51
-rw-r--r--contrib/wpa_supplicant/wpa_cli.c604
-rw-r--r--contrib/wpa_supplicant/wpa_common.h58
-rw-r--r--contrib/wpa_supplicant/wpa_ctrl.c296
-rw-r--r--contrib/wpa_supplicant/wpa_ctrl.h4
-rw-r--r--contrib/wpa_supplicant/wpa_gui-qt4/eventhistory.cpp122
-rw-r--r--contrib/wpa_supplicant/wpa_gui-qt4/eventhistory.h63
-rw-r--r--contrib/wpa_supplicant/wpa_gui-qt4/eventhistory.ui200
-rw-r--r--contrib/wpa_supplicant/wpa_gui-qt4/main.cpp44
-rw-r--r--contrib/wpa_supplicant/wpa_gui-qt4/networkconfig.cpp582
-rw-r--r--contrib/wpa_supplicant/wpa_gui-qt4/networkconfig.h58
-rw-r--r--contrib/wpa_supplicant/wpa_gui-qt4/networkconfig.ui747
-rw-r--r--contrib/wpa_supplicant/wpa_gui-qt4/scanresults.cpp124
-rw-r--r--contrib/wpa_supplicant/wpa_gui-qt4/scanresults.h47
-rw-r--r--contrib/wpa_supplicant/wpa_gui-qt4/scanresults.ui290
-rw-r--r--contrib/wpa_supplicant/wpa_gui-qt4/userdatarequest.cpp100
-rw-r--r--contrib/wpa_supplicant/wpa_gui-qt4/userdatarequest.h46
-rw-r--r--contrib/wpa_supplicant/wpa_gui-qt4/userdatarequest.ui264
-rw-r--r--contrib/wpa_supplicant/wpa_gui-qt4/wpa_gui.pro31
-rw-r--r--contrib/wpa_supplicant/wpa_gui-qt4/wpagui.cpp779
-rw-r--r--contrib/wpa_supplicant/wpa_gui-qt4/wpagui.h76
-rw-r--r--contrib/wpa_supplicant/wpa_gui-qt4/wpagui.ui712
-rw-r--r--contrib/wpa_supplicant/wpa_gui-qt4/wpamsg.h42
-rw-r--r--contrib/wpa_supplicant/wpa_gui/eventhistory.ui.h4
-rw-r--r--contrib/wpa_supplicant/wpa_gui/networkconfig.ui.h92
-rw-r--r--contrib/wpa_supplicant/wpa_gui/scanresults.ui.h6
-rwxr-xr-xcontrib/wpa_supplicant/wpa_gui/setup-mingw-cross-compiling11
-rw-r--r--contrib/wpa_supplicant/wpa_gui/wpa_gui.pro28
-rw-r--r--contrib/wpa_supplicant/wpa_gui/wpagui.ui7
-rw-r--r--contrib/wpa_supplicant/wpa_gui/wpagui.ui.h88
-rw-r--r--contrib/wpa_supplicant/wpa_gui/wpamsg.h11
-rw-r--r--contrib/wpa_supplicant/wpa_i.h77
-rw-r--r--contrib/wpa_supplicant/wpa_passphrase.c9
-rw-r--r--contrib/wpa_supplicant/wpa_supplicant.c939
-rw-r--r--contrib/wpa_supplicant/wpa_supplicant.conf118
-rw-r--r--contrib/wpa_supplicant/wpa_supplicant.h43
-rw-r--r--contrib/wpa_supplicant/wpa_supplicant_i.h226
-rw-r--r--contrib/wpa_supplicant/x509v3.c1596
-rw-r--r--contrib/wpa_supplicant/x509v3.h154
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);
+
+dbus_bool_t wpa_dbus_dict_get_entry(DBusMessageIter *iter_dict,
+ struct wpa_dbus_dict_entry *entry);
+
+dbus_bool_t wpa_dbus_dict_has_dict_entry(DBusMessageIter *iter_dict);
+
+void wpa_dbus_dict_entry_clear(struct wpa_dbus_dict_entry *entry);
+
+#endif /* DBUS_DICT_HELPERS_H */
diff --git a/contrib/wpa_supplicant/defconfig b/contrib/wpa_supplicant/defconfig
index be013b48df10..d9526efd73f4 100644
--- a/