From f8262d7d8ac3000d0865826129738cd58a8fe1ab Mon Sep 17 00:00:00 2001
From: Philip Paeps
Date: Fri, 19 Mar 2021 11:13:37 +0800
Subject: [PATCH] Import wpa_supplicant/hostapd commit 9d9b42306541
Start tracking upstream development of hostapd and wpa_supplicant more
closely. The last upstream release is from August 2019. Keeping up
with upstream development will make importing releases less exciting.
Discussed with: cy
Sponsored by: Rubicon Communications, LLC ("Netgate")
---
.gitignore | 8 +
Android.mk | 10 +
CONTRIBUTIONS | 5 +-
build_release | 47 +
doc/.gitignore | 14 +
doc/Makefile | 42 +
doc/code_structure.doxygen | 315 +
doc/ctrl_iface.doxygen | 1054 ++
doc/dbus.doxygen | 2394 ++++
doc/directories.doxygen | 90 +
doc/doxygen.conf | 1547 +++
doc/driver_wrapper.doxygen | 180 +
doc/eap.doxygen | 87 +
doc/eap_server.doxygen | 56 +
doc/hostapd.fig | 264 +
doc/hostapd_ctrl_iface.doxygen | 66 +
doc/mainpage.doxygen | 95 +
doc/p2p.doxygen | 471 +
doc/p2p_arch.dot | 85 +
doc/p2p_arch2.dot | 85 +
doc/p2p_sm.dot | 62 +
doc/porting.doxygen | 209 +
doc/testing_tools.doxygen | 201 +
doc/wpa_supplicant.fig | 247 +
eap_example/.gitignore | 4 +
eap_example/Makefile | 119 +
eap_example/README | 42 +
eap_example/ca.pem | 55 +
eap_example/dh.conf | 5 +
eap_example/eap_example.c | 47 +
eap_example/eap_example_peer.c | 377 +
eap_example/eap_example_server.c | 300 +
eap_example/server-key.pem | 15 +
eap_example/server.key | 16 +
eap_example/server.pem | 64 +
hostapd/.gitignore | 5 +
hostapd/Android.mk | 86 +-
hostapd/ChangeLog | 4 +-
hostapd/Makefile | 197 +-
hostapd/android.config | 25 +-
hostapd/config_file.c | 418 +-
hostapd/ctrl_iface.c | 807 +-
hostapd/defconfig | 35 +-
hostapd/hostapd.conf | 337 +-
hostapd/hostapd.wpa_psk | 6 +
hostapd/hostapd_cli.c | 128 +-
hostapd/main.c | 22 +-
hostapd/sae_pk_gen.c | 196 +
hs20/client/Makefile | 55 +-
hs20/client/est.c | 7 +-
hs20/client/oma_dm_client.c | 2 +-
hs20/client/osu_client.c | 27 +-
hs20/client/osu_client.h | 2 +
hs20/client/spp_client.c | 2 +-
hs20/server/.gitignore | 1 +
hs20/server/Makefile | 42 +
hs20/server/ca/clean.sh | 13 +
hs20/server/ca/est-csrattrs.cnf | 17 +
hs20/server/ca/est-csrattrs.sh | 4 +
hs20/server/ca/hs20.oid | 7 +
hs20/server/ca/ocsp-req.sh | 11 +
hs20/server/ca/ocsp-responder-ica.sh | 3 +
hs20/server/ca/ocsp-responder.sh | 3 +
hs20/server/ca/ocsp-update-cache.sh | 11 +
hs20/server/ca/openssl-root.cnf | 125 +
hs20/server/ca/openssl.cnf | 200 +
hs20/server/ca/setup.sh | 209 +
hs20/server/ca/w1fi_logo.png | Bin 0 -> 7549 bytes
hs20/server/hs20-osu-server.txt | 262 +
hs20/server/hs20_spp_server.c | 207 +
hs20/server/spp_server.c | 2933 +++++
hs20/server/spp_server.h | 36 +
hs20/server/sql-example.txt | 17 +
hs20/server/sql.txt | 108 +
hs20/server/www/add-free.php | 50 +
hs20/server/www/add-mo.php | 56 +
hs20/server/www/cert-enroll.php | 39 +
hs20/server/www/config.php | 7 +
hs20/server/www/est.php | 232 +
hs20/server/www/free-remediation.php | 19 +
hs20/server/www/free.php | 23 +
hs20/server/www/redirect.php | 32 +
hs20/server/www/remediation-pw.php | 41 +
hs20/server/www/remediation.php | 55 +
hs20/server/www/signup.php | 59 +
hs20/server/www/spp.php | 168 +
hs20/server/www/terms.php | 87 +
hs20/server/www/users.php | 377 +
radius_example/.gitignore | 2 +
radius_example/Makefile | 28 +
radius_example/README | 35 +
radius_example/radius_example.c | 153 +
src/Makefile | 4 +-
src/ap/Makefile | 18 +-
src/ap/acs.c | 307 +-
src/ap/airtime_policy.c | 8 +-
src/ap/ap_config.c | 292 +-
src/ap/ap_config.h | 123 +-
src/ap/ap_drv_ops.c | 154 +-
src/ap/ap_drv_ops.h | 38 +-
src/ap/ap_list.c | 4 -
src/ap/authsrv.c | 87 +-
src/ap/beacon.c | 604 +-
src/ap/beacon.h | 2 +
src/ap/ctrl_iface_ap.c | 85 +-
src/ap/dfs.c | 313 +-
src/ap/dfs.h | 3 +
src/ap/dhcp_snoop.c | 8 +-
src/ap/dpp_hostapd.c | 1003 +-
src/ap/dpp_hostapd.h | 11 +
src/ap/drv_callbacks.c | 362 +-
src/ap/fils_hlp.c | 36 +-
src/ap/gas_serv.c | 10 +-
src/ap/hostapd.c | 255 +-
src/ap/hostapd.h | 57 +-
src/ap/hs20.c | 6 +-
src/ap/hw_features.c | 367 +-
src/ap/hw_features.h | 22 +-
src/ap/iapp.c | 542 -
src/ap/iapp.h | 39 -
src/ap/ieee802_11.c | 2339 +++-
src/ap/ieee802_11.h | 24 +-
src/ap/ieee802_11_auth.c | 170 +-
src/ap/ieee802_11_auth.h | 17 +-
src/ap/ieee802_11_he.c | 171 +-
src/ap/ieee802_11_ht.c | 30 +-
src/ap/ieee802_11_shared.c | 172 +-
src/ap/ieee802_11_vht.c | 174 +-
src/ap/ieee802_1x.c | 482 +-
src/ap/ieee802_1x.h | 7 +-
src/ap/neighbor_db.c | 58 +-
src/ap/neighbor_db.h | 1 +
src/ap/pmksa_cache_auth.c | 5 +
src/ap/preauth_auth.c | 2 +-
src/ap/sta_info.c | 111 +-
src/ap/sta_info.h | 53 +-
src/ap/utils.c | 4 +
src/ap/vlan_init.c | 5 +-
src/ap/wmm.c | 14 +-
src/ap/wnm_ap.c | 83 +-
src/ap/wpa_auth.c | 1389 +-
src/ap/wpa_auth.h | 98 +-
src/ap/wpa_auth_ft.c | 386 +-
src/ap/wpa_auth_glue.c | 336 +-
src/ap/wpa_auth_i.h | 71 +-
src/ap/wpa_auth_ie.c | 444 +-
src/ap/wpa_auth_ie.h | 35 -
src/ap/wpa_auth_kay.c | 12 +-
src/ap/wps_hostapd.c | 230 +-
src/build.rules | 109 +
src/common/Makefile | 18 +-
src/common/brcm_vendor.h | 156 +
src/common/common_module_tests.c | 392 +-
src/common/defs.h | 86 +-
src/common/dhcp.h | 2 +-
src/common/dpp.c | 8825 +++----------
src/common/dpp.h | 245 +-
src/common/dpp_auth.c | 1977 +++
src/common/dpp_backup.c | 1265 ++
src/common/dpp_crypto.c | 3329 +++++
src/common/dpp_i.h | 160 +
src/common/dpp_pkex.c | 1324 ++
src/common/dpp_reconfig.c | 958 ++
src/common/dpp_tcp.c | 1794 +++
src/common/gas_server.c | 140 +-
src/common/gas_server.h | 9 +-
src/common/hw_features_common.c | 431 +-
src/common/hw_features_common.h | 26 +-
src/common/ieee802_11_common.c | 760 +-
src/common/ieee802_11_common.h | 67 +-
src/common/ieee802_11_defs.h | 246 +-
src/common/ocv.c | 39 +-
src/common/ocv.h | 13 +-
src/common/privsep_commands.h | 1 +
src/common/ptksa_cache.c | 321 +
src/common/ptksa_cache.h | 79 +
src/common/qca-vendor.h | 3748 +++++-
src/common/sae.c | 1328 +-
src/common/sae.h | 107 +-
src/common/sae_pk.c | 884 ++
src/common/version.h | 2 +-
src/common/wpa_common.c | 1240 +-
src/common/wpa_common.h | 207 +-
src/common/wpa_ctrl.c | 5 +-
src/common/wpa_ctrl.h | 41 +-
src/crypto/.gitignore | 1 -
src/crypto/Makefile | 19 +-
src/crypto/crypto.h | 49 +-
src/crypto/crypto_module_tests.c | 150 +
src/crypto/crypto_openssl.c | 248 +
src/crypto/crypto_wolfssl.c | 77 +-
src/crypto/sha256.c | 6 +-
src/crypto/sha384-tlsprf.c | 71 +
src/crypto/sha384.c | 6 +-
src/crypto/sha384.h | 3 +
src/crypto/sha512.c | 6 +-
src/crypto/tls.h | 14 +
src/crypto/tls_openssl.c | 306 +-
src/crypto/tls_wolfssl.c | 65 +-
src/drivers/.gitignore | 2 -
src/drivers/driver.h | 703 +-
src/drivers/driver_atheros.c | 41 +-
src/drivers/driver_bsd.c | 613 +-
src/drivers/driver_common.c | 21 +
src/drivers/driver_hostap.c | 24 +-
src/drivers/driver_macsec_linux.c | 87 +-
src/drivers/driver_macsec_qca.c | 34 +-
src/drivers/driver_ndis.c | 20 +-
src/drivers/driver_nl80211.c | 2103 +++-
src/drivers/driver_nl80211.h | 65 +-
src/drivers/driver_nl80211_android.c | 4 +-
src/drivers/driver_nl80211_capa.c | 573 +-
src/drivers/driver_nl80211_event.c | 574 +-
src/drivers/driver_nl80211_monitor.c | 3 +
src/drivers/driver_nl80211_scan.c | 51 +-
src/drivers/driver_none.c | 8 -
src/drivers/driver_openbsd.c | 10 +-
src/drivers/driver_privsep.c | 18 +-
src/drivers/driver_wext.c | 95 +-
src/drivers/driver_wext.h | 4 -
src/drivers/drivers.mak | 22 +-
src/drivers/drivers.mk | 24 +-
src/drivers/nl80211_copy.h | 951 +-
src/eap_common/Makefile | 15 +-
src/eap_common/eap_common.c | 8 +-
src/eap_common/eap_common.h | 8 +-
src/eap_common/eap_defs.h | 4 +-
src/eap_common/eap_sim_common.c | 4 +
src/eap_common/eap_teap_common.c | 72 +-
src/eap_common/eap_teap_common.h | 22 +-
src/eap_peer/.gitignore | 1 +
src/eap_peer/Makefile | 18 +-
src/eap_peer/eap.c | 220 +-
src/eap_peer/eap.h | 13 +-
src/eap_peer/eap_aka.c | 50 +-
src/eap_peer/eap_config.h | 420 +-
src/eap_peer/eap_eke.c | 16 +-
src/eap_peer/eap_fast.c | 54 +-
src/eap_peer/eap_gpsk.c | 14 +-
src/eap_peer/eap_gtc.c | 8 +-
src/eap_peer/eap_i.h | 42 +-
src/eap_peer/eap_ikev2.c | 28 +-
src/eap_peer/eap_leap.c | 44 +-
src/eap_peer/eap_md5.c | 12 +-
src/eap_peer/eap_methods.c | 12 +-
src/eap_peer/eap_methods.h | 14 +-
src/eap_peer/eap_mschapv2.c | 32 +-
src/eap_peer/eap_otp.c | 8 +-
src/eap_peer/eap_pax.c | 50 +-
src/eap_peer/eap_peap.c | 71 +-
src/eap_peer/eap_psk.c | 22 +-
src/eap_peer/eap_pwd.c | 22 +-
src/eap_peer/eap_sake.c | 26 +-
src/eap_peer/eap_sim.c | 44 +-
src/eap_peer/eap_teap.c | 201 +-
src/eap_peer/eap_tls.c | 42 +-
src/eap_peer/eap_tls_common.c | 103 +-
src/eap_peer/eap_tls_common.h | 10 +-
src/eap_peer/eap_tnc.c | 32 +-
src/eap_peer/eap_ttls.c | 88 +-
src/eap_peer/eap_vendor_test.c | 16 +-
src/eap_peer/eap_wsc.c | 24 +-
src/eap_peer/ikev2.c | 10 +-
src/eap_peer/tncc.c | 5 +-
src/eap_server/Makefile | 15 +-
src/eap_server/eap.h | 172 +-
src/eap_server/eap_i.h | 67 +-
src/eap_server/eap_methods.h | 9 +-
src/eap_server/eap_server.c | 291 +-
src/eap_server/eap_server_aka.c | 74 +-
src/eap_server/eap_server_eke.c | 39 +-
src/eap_server/eap_server_fast.c | 106 +-
src/eap_server/eap_server_gpsk.c | 37 +-
src/eap_server/eap_server_gtc.c | 12 +-
src/eap_server/eap_server_identity.c | 14 +-
src/eap_server/eap_server_ikev2.c | 22 +-
src/eap_server/eap_server_md5.c | 14 +-
src/eap_server/eap_server_methods.c | 10 +-
src/eap_server/eap_server_mschapv2.c | 22 +-
src/eap_server/eap_server_pax.c | 32 +-
src/eap_server/eap_server_peap.c | 103 +-
src/eap_server/eap_server_psk.c | 34 +-
src/eap_server/eap_server_pwd.c | 22 +-
src/eap_server/eap_server_sake.c | 38 +-
src/eap_server/eap_server_sim.c | 66 +-
src/eap_server/eap_server_teap.c | 309 +-
src/eap_server/eap_server_tls.c | 54 +-
src/eap_server/eap_server_tls_common.c | 93 +-
src/eap_server/eap_server_tnc.c | 26 +-
src/eap_server/eap_server_ttls.c | 96 +-
src/eap_server/eap_server_vendor_test.c | 12 +-
src/eap_server/eap_server_wsc.c | 24 +-
src/eap_server/eap_tls_common.h | 2 +-
src/eap_server/tncs.c | 5 +-
src/eapol_auth/Makefile | 16 +-
src/eapol_auth/eapol_auth_sm.c | 204 +-
src/eapol_auth/eapol_auth_sm.h | 26 +-
src/eapol_auth/eapol_auth_sm_i.h | 40 +-
src/eapol_supp/Makefile | 15 +-
src/eapol_supp/eapol_supp_sm.c | 218 +-
src/eapol_supp/eapol_supp_sm.h | 29 +-
src/fst/fst.c | 25 +-
src/fst/fst.h | 23 +-
src/fst/fst_ctrl_aux.h | 4 +-
src/fst/fst_ctrl_iface.c | 48 +-
src/fst/fst_ctrl_iface.h | 2 +-
src/fst/fst_group.c | 10 +-
src/fst/fst_group.h | 4 +-
src/fst/fst_iface.c | 8 +-
src/fst/fst_iface.h | 8 +-
src/fst/fst_session.c | 96 +-
src/fst/fst_session.h | 12 +-
src/l2_packet/Makefile | 15 +-
src/l2_packet/l2_packet.h | 4 +
src/l2_packet/l2_packet_freebsd.c | 2 +-
src/l2_packet/l2_packet_linux.c | 11 +-
src/l2_packet/l2_packet_ndis.c | 3 +-
src/l2_packet/l2_packet_none.c | 4 +-
src/l2_packet/l2_packet_pcap.c | 4 +-
src/l2_packet/l2_packet_privsep.c | 3 +-
src/l2_packet/l2_packet_winpcap.c | 3 +
src/lib.rules | 38 +-
src/objs.mk | 3 +
src/p2p/Makefile | 15 +-
src/p2p/p2p.c | 45 +-
src/p2p/p2p.h | 14 +-
src/p2p/p2p_go_neg.c | 9 +
src/pae/ieee802_1x_cp.c | 177 +-
src/pae/ieee802_1x_cp.h | 10 +-
src/pae/ieee802_1x_kay.c | 610 +-
src/pae/ieee802_1x_kay.h | 68 +-
src/pae/ieee802_1x_kay_i.h | 40 +-
src/pae/ieee802_1x_secy_ops.c | 22 +-
src/pae/ieee802_1x_secy_ops.h | 8 +-
src/radius/.gitignore | 1 -
src/radius/Makefile | 16 +-
src/radius/radius.c | 2 +-
src/radius/radius.h | 3 +
src/radius/radius_client.c | 52 +-
src/radius/radius_client.h | 5 +
src/radius/radius_server.c | 283 +-
src/radius/radius_server.h | 142 +-
src/rsn_supp/Makefile | 16 +-
src/rsn_supp/pmksa_cache.c | 43 +-
src/rsn_supp/pmksa_cache.h | 1 +
src/rsn_supp/preauth.c | 24 +-
src/rsn_supp/tdls.c | 69 +-
src/rsn_supp/wpa.c | 737 +-
src/rsn_supp/wpa.h | 82 +-
src/rsn_supp/wpa_ft.c | 399 +-
src/rsn_supp/wpa_i.h | 88 +-
src/rsn_supp/wpa_ie.c | 319 +-
src/rsn_supp/wpa_ie.h | 52 +-
src/tls/.gitignore | 1 -
src/tls/Makefile | 17 +-
src/tls/asn1.c | 396 +-
src/tls/asn1.h | 146 +-
src/tls/pkcs1.c | 55 +-
src/tls/pkcs5.c | 78 +-
src/tls/pkcs8.c | 59 +-
src/tls/rsa.c | 23 +-
src/tls/tlsv1_client.c | 29 +-
src/tls/tlsv1_client_i.h | 4 +-
src/tls/tlsv1_client_ocsp.c | 180 +-
src/tls/tlsv1_client_read.c | 10 +-
src/tls/tlsv1_client_write.c | 18 +-
src/tls/tlsv1_cred.c | 247 +-
src/tls/x509v3.c | 419 +-
src/tls/x509v3.h | 7 +
src/utils/.gitignore | 1 -
src/utils/Makefile | 17 +-
src/utils/base64.c | 59 +-
src/utils/base64.h | 13 +-
src/utils/browser-android.c | 2 +-
src/utils/browser-system.c | 2 +-
src/utils/browser-wpadebug.c | 2 +-
src/utils/browser.c | 210 +-
src/utils/browser.h | 4 +-
src/utils/common.c | 38 +-
src/utils/common.h | 8 +-
src/utils/config.c | 97 +
src/utils/config.h | 29 +
src/utils/eloop.c | 47 +-
src/utils/eloop_win.c | 8 +-
src/utils/ext_password.c | 3 +
src/utils/ext_password_file.c | 136 +
src/utils/ext_password_i.h | 4 +
src/utils/http-utils.h | 6 +-
src/utils/includes.h | 1 +
src/utils/json.c | 122 +-
src/utils/json.h | 15 +
src/utils/list.h | 8 +-
src/utils/os_internal.c | 6 +
src/utils/os_unix.c | 13 +-
src/utils/platform.h | 23 +-
src/utils/radiotap.c | 12 +-
src/utils/radiotap.h | 405 +-
src/utils/state_machine.h | 8 +-
src/utils/trace.c | 11 +
src/utils/utils_module_tests.c | 53 +-
src/utils/wpa_debug.c | 149 +-
src/utils/wpa_debug.h | 3 -
src/utils/wpabuf.h | 27 +
src/utils/xml_libxml2.c | 2 +-
src/wps/Makefile | 15 +-
src/wps/upnp_xml.c | 2 +-
src/wps/wps.h | 19 +-
src/wps/wps_attr_build.c | 15 +-
src/wps/wps_attr_process.c | 9 +-
src/wps/wps_dev_attr.c | 17 +
src/wps/wps_dev_attr.h | 1 +
src/wps/wps_enrollee.c | 11 +
src/wps/wps_er.c | 4 +-
src/wps/wps_registrar.c | 97 +-
src/wps/wps_upnp.c | 25 +-
src/wps/wps_upnp_ap.c | 4 +-
src/wps/wps_upnp_event.c | 27 +-
src/wps/wps_upnp_i.h | 9 +-
src/wps/wps_upnp_web.c | 4 +-
tests/.gitignore | 3 +
tests/Makefile | 99 +
tests/README | 123 +
tests/cipher-and-key-mgmt-testing.txt | 377 +
tests/fuzzing/README | 23 +
tests/fuzzing/ap-mgmt/.gitignore | 1 +
tests/fuzzing/ap-mgmt/Makefile | 44 +
tests/fuzzing/ap-mgmt/ap-mgmt.c | 167 +
.../fuzzing/ap-mgmt/corpus/multi-sae-ffc.dat | Bin 0 -> 506 bytes
tests/fuzzing/ap-mgmt/corpus/multi-sae.dat | Bin 0 -> 346 bytes
tests/fuzzing/ap-mgmt/corpus/multi.dat | Bin 0 -> 246 bytes
tests/fuzzing/asn1/.gitignore | 1 +
tests/fuzzing/asn1/Makefile | 23 +
tests/fuzzing/asn1/asn1.c | 184 +
tests/fuzzing/asn1/corpus/ca.der | Bin 0 -> 560 bytes
.../asn1/corpus/ocsp-multi-server-cache.der | Bin 0 -> 346 bytes
tests/fuzzing/asn1/corpus/ocsp-req.der | Bin 0 -> 76 bytes
tests/fuzzing/build-test.sh | 19 +
tests/fuzzing/dpp-uri/.gitignore | 1 +
tests/fuzzing/dpp-uri/Makefile | 43 +
tests/fuzzing/dpp-uri/corpus/1.dat | 1 +
tests/fuzzing/dpp-uri/corpus/2.dat | 1 +
tests/fuzzing/dpp-uri/corpus/3.dat | 1 +
tests/fuzzing/dpp-uri/dpp-uri.c | 51 +
tests/fuzzing/eap-aka-peer/.gitignore | 1 +
tests/fuzzing/eap-aka-peer/Makefile | 26 +
tests/fuzzing/eap-aka-peer/corpus/server.msg | Bin 0 -> 520 bytes
tests/fuzzing/eap-aka-peer/eap-aka-peer.c | 131 +
tests/fuzzing/eap-mschapv2-peer/.gitignore | 1 +
tests/fuzzing/eap-mschapv2-peer/Makefile | 25 +
.../eap-mschapv2-peer/corpus/server.msg | Bin 0 -> 304 bytes
.../eap-mschapv2-peer/eap-mschapv2-peer.c | 152 +
tests/fuzzing/eap-sim-peer/.gitignore | 1 +
tests/fuzzing/eap-sim-peer/Makefile | 26 +
tests/fuzzing/eap-sim-peer/corpus/server.msg | Bin 0 -> 340 bytes
tests/fuzzing/eap-sim-peer/eap-sim-peer.c | 125 +
tests/fuzzing/eapol-key-auth/.gitignore | 1 +
tests/fuzzing/eapol-key-auth/Makefile | 34 +
tests/fuzzing/eapol-key-auth/corpus/supp.msg | Bin 0 -> 549 bytes
tests/fuzzing/eapol-key-auth/eapol-key-auth.c | 328 +
tests/fuzzing/eapol-key-supp/.gitignore | 1 +
tests/fuzzing/eapol-key-supp/Makefile | 30 +
tests/fuzzing/eapol-key-supp/corpus/auth.msg | Bin 0 -> 580 bytes
tests/fuzzing/eapol-key-supp/eapol-key-supp.c | 331 +
tests/fuzzing/eapol-supp/.gitignore | 1 +
tests/fuzzing/eapol-supp/Makefile | 28 +
.../eapol-supp/corpus/eap-req-identity.dat | Bin 0 -> 9 bytes
.../fuzzing/eapol-supp/corpus/eap-req-sim.dat | Bin 0 -> 24 bytes
.../eapol-supp/corpus/eapol-key-m1.dat | Bin 0 -> 99 bytes
tests/fuzzing/eapol-supp/eapol-supp.c | 198 +
tests/fuzzing/fuzzer-common.c | 56 +
tests/fuzzing/fuzzer-common.h | 14 +
tests/fuzzing/json/.gitignore | 1 +
tests/fuzzing/json/Makefile | 23 +
tests/fuzzing/json/corpus/1.json | 1 +
tests/fuzzing/json/corpus/2.json | 1 +
tests/fuzzing/json/corpus/3.json | 1 +
tests/fuzzing/json/json.c | 38 +
tests/fuzzing/p2p/.gitignore | 1 +
tests/fuzzing/p2p/Makefile | 23 +
tests/fuzzing/p2p/corpus/go-neg-req.dat | Bin 0 -> 155 bytes
tests/fuzzing/p2p/corpus/invitation-req.dat | Bin 0 -> 123 bytes
tests/fuzzing/p2p/corpus/p2ps-pd-req.dat | Bin 0 -> 189 bytes
tests/fuzzing/p2p/corpus/proberesp-go.dat | Bin 0 -> 306 bytes
tests/fuzzing/p2p/corpus/proberesp.dat | Bin 0 -> 209 bytes
tests/fuzzing/p2p/p2p.c | 178 +
tests/fuzzing/rules.include | 31 +
tests/fuzzing/sae/.gitignore | 1 +
tests/fuzzing/sae/Makefile | 28 +
.../corpus/sae-commit-h2e-rejected-groups.dat | Bin 0 -> 102 bytes
.../sae/corpus/sae-commit-h2e-token.dat | Bin 0 -> 101 bytes
tests/fuzzing/sae/corpus/sae-commit-pw-id.dat | Bin 0 -> 101 bytes
tests/fuzzing/sae/corpus/sae-commit-token.dat | Bin 0 -> 130 bytes
tests/fuzzing/sae/corpus/sae-commit-valid.dat | Bin 0 -> 98 bytes
tests/fuzzing/sae/sae.c | 39 +
tests/fuzzing/tls-client/.gitignore | 1 +
tests/fuzzing/tls-client/Makefile | 32 +
tests/fuzzing/tls-client/corpus/server.msg | Bin 0 -> 1902 bytes
tests/fuzzing/tls-client/tls-client.c | 154 +
tests/fuzzing/tls-server/.gitignore | 1 +
tests/fuzzing/tls-server/Makefile | 32 +
tests/fuzzing/tls-server/corpus/client.msg | Bin 0 -> 391 bytes
tests/fuzzing/tls-server/tls-server.c | 157 +
tests/fuzzing/wnm/.gitignore | 1 +
tests/fuzzing/wnm/Makefile | 60 +
tests/fuzzing/wnm/corpus/bss-tm-req.dat | Bin 0 -> 31 bytes
tests/fuzzing/wnm/corpus/oss-fuzz-0001.dat | Bin 0 -> 64 bytes
tests/fuzzing/wnm/corpus/oss-fuzz-0002.dat | Bin 0 -> 104 bytes
tests/fuzzing/wnm/corpus/wnm-notif.dat | Bin 0 -> 56 bytes
tests/fuzzing/wnm/wnm.c | 99 +
tests/fuzzing/x509/.gitignore | 1 +
tests/fuzzing/x509/Makefile | 27 +
tests/fuzzing/x509/corpus/ca.der | Bin 0 -> 560 bytes
tests/fuzzing/x509/corpus/oss-fuzz-15408 | 1 +
tests/fuzzing/x509/x509.c | 25 +
tests/hwsim/.gitignore | 1 +
tests/hwsim/README | 220 +
tests/hwsim/auth_serv/as.conf | 27 +
tests/hwsim/auth_serv/as2.conf | 24 +
tests/hwsim/auth_serv/ca-and-crl-expired.pem | 90 +
tests/hwsim/auth_serv/ca-and-crl.pem | 90 +
tests/hwsim/auth_serv/ca-incorrect-key.pem | 28 +
tests/hwsim/auth_serv/ca-incorrect.der | Bin 0 -> 902 bytes
tests/hwsim/auth_serv/ca-incorrect.pem | 79 +
tests/hwsim/auth_serv/ca-key.pem | 28 +
tests/hwsim/auth_serv/ca.der | Bin 0 -> 868 bytes
tests/hwsim/auth_serv/ca.pem | 79 +
tests/hwsim/auth_serv/dh.conf | 8 +
tests/hwsim/auth_serv/dh2.conf | 8 +
tests/hwsim/auth_serv/dh_param_3072.pem | 11 +
tests/hwsim/auth_serv/dsaparam.pem | 14 +
tests/hwsim/auth_serv/eap_user.conf | 167 +
tests/hwsim/auth_serv/eap_user_vlan.conf | 7 +
tests/hwsim/auth_serv/ec-ca-openssl.cnf | 111 +
tests/hwsim/auth_serv/ec-ca.key | 8 +
tests/hwsim/auth_serv/ec-ca.pem | 13 +
tests/hwsim/auth_serv/ec-generate.sh | 53 +
tests/hwsim/auth_serv/ec-server.key | 8 +
tests/hwsim/auth_serv/ec-server.pem | 53 +
tests/hwsim/auth_serv/ec-user.key | 8 +
tests/hwsim/auth_serv/ec-user.pem | 52 +
tests/hwsim/auth_serv/ec2-ca.key | 9 +
tests/hwsim/auth_serv/ec2-ca.pem | 15 +
tests/hwsim/auth_serv/ec2-generate.sh | 67 +
tests/hwsim/auth_serv/ec2-server.key | 9 +
tests/hwsim/auth_serv/ec2-server.pem | 58 +
tests/hwsim/auth_serv/ec2-user-p256.key | 8 +
tests/hwsim/auth_serv/ec2-user-p256.pem | 56 +
tests/hwsim/auth_serv/ec2-user.key | 9 +
tests/hwsim/auth_serv/ec2-user.pem | 57 +
tests/hwsim/auth_serv/hlr_auc_gw.gsm | 17 +
tests/hwsim/auth_serv/hlr_auc_gw.milenage_db | 16 +
.../auth_serv/iCA-server/ca-and-root.pem | 160 +
tests/hwsim/auth_serv/iCA-server/cacert.pem | 81 +
tests/hwsim/auth_serv/iCA-server/careq.pem | 16 +
tests/hwsim/auth_serv/iCA-server/index.txt | 2 +
.../hwsim/auth_serv/iCA-server/index.txt.attr | 1 +
.../auth_serv/iCA-server/private/cakey.pem | 28 +
tests/hwsim/auth_serv/iCA-server/serial | 1 +
.../auth_serv/iCA-server/server-revoked.key | 28 +
.../auth_serv/iCA-server/server-revoked.pem | 86 +
.../auth_serv/iCA-server/server-revoked.req | 16 +
.../iCA-server/server-revoked_and_ica.pem | 167 +
tests/hwsim/auth_serv/iCA-server/server.key | 28 +
tests/hwsim/auth_serv/iCA-server/server.pem | 86 +
tests/hwsim/auth_serv/iCA-server/server.req | 16 +
.../auth_serv/iCA-server/server_and_ica.pem | 167 +
.../hwsim/auth_serv/iCA-user/ca-and-root.pem | 160 +
tests/hwsim/auth_serv/iCA-user/cacert.pem | 81 +
tests/hwsim/auth_serv/iCA-user/careq.pem | 16 +
tests/hwsim/auth_serv/iCA-user/index.txt | 1 +
tests/hwsim/auth_serv/iCA-user/index.txt.attr | 1 +
.../auth_serv/iCA-user/private/cakey.pem | 28 +
tests/hwsim/auth_serv/iCA-user/serial | 1 +
tests/hwsim/auth_serv/iCA-user/user.key | 28 +
tests/hwsim/auth_serv/iCA-user/user.pem | 85 +
tests/hwsim/auth_serv/iCA-user/user.req | 16 +
.../hwsim/auth_serv/iCA-user/user_and_ica.pem | 166 +
tests/hwsim/auth_serv/ica-generate.sh | 87 +
tests/hwsim/auth_serv/index-revoked.txt | 8 +
tests/hwsim/auth_serv/index-unknown.txt | 1 +
tests/hwsim/auth_serv/index.txt | 8 +
.../auth_serv/ocsp-multi-server-cache.der | Bin 0 -> 493 bytes
tests/hwsim/auth_serv/ocsp-req.der | Bin 0 -> 76 bytes
tests/hwsim/auth_serv/ocsp-responder.csr | 16 +
tests/hwsim/auth_serv/ocsp-responder.key | 28 +
tests/hwsim/auth_serv/ocsp-responder.pem | 76 +
tests/hwsim/auth_serv/ocsp-server-cache.der | Bin 0 -> 490 bytes
.../auth_serv/ocsp-server-cache.der-invalid | Bin 0 -> 343 bytes
tests/hwsim/auth_serv/openssl2.cnf | 147 +
tests/hwsim/auth_serv/radius_clients.conf | 1 +
.../hwsim/auth_serv/radius_clients_ipv6.conf | 1 +
.../hwsim/auth_serv/radius_clients_none.conf | 4 +
tests/hwsim/auth_serv/rootCA/index.txt | 6 +
tests/hwsim/auth_serv/rootCA/index.txt.attr | 1 +
tests/hwsim/auth_serv/rootCA/serial | 1 +
tests/hwsim/auth_serv/rsa3072-ca.key | 40 +
tests/hwsim/auth_serv/rsa3072-ca.pem | 27 +
tests/hwsim/auth_serv/rsa3072-generate.sh | 83 +
tests/hwsim/auth_serv/rsa3072-server.key | 40 +
tests/hwsim/auth_serv/rsa3072-server.pem | 106 +
tests/hwsim/auth_serv/rsa3072-server.req | 22 +
.../hwsim/auth_serv/rsa3072-user-rsa2048.key | 28 +
.../hwsim/auth_serv/rsa3072-user-rsa2048.pem | 96 +
.../hwsim/auth_serv/rsa3072-user-rsa2048.req | 16 +
tests/hwsim/auth_serv/rsa3072-user.key | 40 +
tests/hwsim/auth_serv/rsa3072-user.pem | 106 +
tests/hwsim/auth_serv/rsa3072-user.req | 21 +
tests/hwsim/auth_serv/server-certpol.csr | 22 +
tests/hwsim/auth_serv/server-certpol.key | 40 +
tests/hwsim/auth_serv/server-certpol.pem | 102 +
tests/hwsim/auth_serv/server-certpol2.csr | 22 +
tests/hwsim/auth_serv/server-certpol2.key | 40 +
tests/hwsim/auth_serv/server-certpol2.pem | 102 +
.../auth_serv/server-eku-client-server.csr | 16 +
.../auth_serv/server-eku-client-server.key | 28 +
.../auth_serv/server-eku-client-server.pem | 85 +
tests/hwsim/auth_serv/server-eku-client.csr | 16 +
tests/hwsim/auth_serv/server-eku-client.key | 28 +
tests/hwsim/auth_serv/server-eku-client.pem | 85 +
tests/hwsim/auth_serv/server-expired.csr | 16 +
tests/hwsim/auth_serv/server-expired.key | 28 +
tests/hwsim/auth_serv/server-expired.pem | 85 +
tests/hwsim/auth_serv/server-extra.pkcs12 | Bin 0 -> 3418 bytes
.../hwsim/auth_serv/server-long-duration.csr | 27 +
.../hwsim/auth_serv/server-long-duration.key | 52 +
.../hwsim/auth_serv/server-long-duration.pem | 107 +
tests/hwsim/auth_serv/server-no-dnsname.csr | 16 +
tests/hwsim/auth_serv/server-no-dnsname.key | 28 +
tests/hwsim/auth_serv/server-no-dnsname.pem | 85 +
tests/hwsim/auth_serv/server.csr | 16 +
tests/hwsim/auth_serv/server.key | 28 +
tests/hwsim/auth_serv/server.pem | 87 +
tests/hwsim/auth_serv/server.pkcs12 | Bin 0 -> 2549 bytes
tests/hwsim/auth_serv/sha384-server.key | 40 +
tests/hwsim/auth_serv/sha384-server.pem | 115 +
tests/hwsim/auth_serv/sha384-user.key | 38 +
tests/hwsim/auth_serv/sha384-user.pem | 113 +
tests/hwsim/auth_serv/sha512-ca.key | 52 +
tests/hwsim/auth_serv/sha512-ca.pem | 32 +
tests/hwsim/auth_serv/sha512-generate.sh | 75 +
tests/hwsim/auth_serv/sha512-server.key | 45 +
tests/hwsim/auth_serv/sha512-server.pem | 120 +
tests/hwsim/auth_serv/sha512-user.key | 44 +
tests/hwsim/auth_serv/sha512-user.pem | 119 +
tests/hwsim/auth_serv/update.sh | 181 +
tests/hwsim/auth_serv/user.csr | 16 +
tests/hwsim/auth_serv/user.key | 28 +
tests/hwsim/auth_serv/user.key.pkcs8 | 30 +
tests/hwsim/auth_serv/user.key.pkcs8.pkcs5v15 | 29 +
tests/hwsim/auth_serv/user.pem | 85 +
tests/hwsim/auth_serv/user.pkcs12 | Bin 0 -> 2517 bytes
tests/hwsim/auth_serv/user.rsa-key | 27 +
tests/hwsim/auth_serv/user2.pkcs12 | Bin 0 -> 3558 bytes
tests/hwsim/auth_serv/user3.pkcs12 | Bin 0 -> 3524 bytes
tests/hwsim/build.sh | 83 +
tests/hwsim/check_kernel.py | 31 +
tests/hwsim/devdetail.xml | 47 +
tests/hwsim/devinfo.xml | 7 +
tests/hwsim/dictionary.radius | 20 +
tests/hwsim/example-hostapd.config | 115 +
tests/hwsim/example-setup.txt | 191 +
tests/hwsim/example-wpa_supplicant.config | 160 +
tests/hwsim/fst_module_aux.py | 832 ++
tests/hwsim/fst_test_common.py | 97 +
tests/hwsim/hostapd.py | 870 ++
tests/hwsim/hostapd.vlan | 2 +
tests/hwsim/hostapd.vlan2 | 3 +
tests/hwsim/hostapd.wlan3.vlan | 2 +
tests/hwsim/hostapd.wlan4.vlan | 2 +
tests/hwsim/hostapd.wpa_psk | 5 +
tests/hwsim/hwsim.py | 114 +
tests/hwsim/hwsim_utils.py | 246 +
tests/hwsim/multi-bss-acs.conf | 28 +
tests/hwsim/multi-bss-iface-per_sta_vif.conf | 42 +
tests/hwsim/multi-bss-iface.conf | 40 +
tests/hwsim/multi-bss.conf | 21 +
tests/hwsim/netlink.py | 237 +
tests/hwsim/nl80211.py | 357 +
tests/hwsim/owe-bss-1.conf | 12 +
tests/hwsim/owe-bss-2.conf | 16 +
tests/hwsim/p2p0.conf | 3 +
tests/hwsim/p2p1.conf | 3 +
tests/hwsim/p2p2.conf | 3 +
tests/hwsim/p2p_utils.py | 394 +
tests/hwsim/pps-mo-1.xml | 62 +
tests/hwsim/radius_das.py | 47 +
tests/hwsim/remotehost.py | 258 +
tests/hwsim/rfkill.py | 152 +
tests/hwsim/run-all.sh | 162 +
tests/hwsim/run-tests.py | 692 +
tests/hwsim/start.sh | 213 +
tests/hwsim/stop.sh | 80 +
tests/hwsim/test_ap_acs.py | 688 +
tests/hwsim/test_ap_ciphers.py | 1200 ++
tests/hwsim/test_ap_config.py | 581 +
tests/hwsim/test_ap_csa.py | 189 +
tests/hwsim/test_ap_dynamic.py | 586 +
tests/hwsim/test_ap_eap.py | 7491 +++++++++++
tests/hwsim/test_ap_ft.py | 3437 +++++
tests/hwsim/test_ap_hs20.py | 6496 ++++++++++
tests/hwsim/test_ap_ht.py | 1609 +++
tests/hwsim/test_ap_mixed.py | 101 +
tests/hwsim/test_ap_open.py | 1017 ++
tests/hwsim/test_ap_params.py | 911 ++
tests/hwsim/test_ap_pmf.py | 1204 ++
tests/hwsim/test_ap_psk.py | 3537 ++++++
tests/hwsim/test_ap_qosmap.py | 169 +
tests/hwsim/test_ap_roam.py | 395 +
tests/hwsim/test_ap_tdls.py | 652 +
tests/hwsim/test_ap_track.py | 405 +
tests/hwsim/test_ap_vht.py | 1333 ++
tests/hwsim/test_ap_vlan.py | 807 ++
tests/hwsim/test_ap_wps.py | 10466 ++++++++++++++++
tests/hwsim/test_authsrv.py | 262 +
tests/hwsim/test_autoscan.py | 81 +
tests/hwsim/test_bgscan.py | 315 +
tests/hwsim/test_cert_check.py | 312 +
tests/hwsim/test_cfg80211.py | 150 +
tests/hwsim/test_connect_cmd.py | 235 +
tests/hwsim/test_dbus.py | 6093 +++++++++
tests/hwsim/test_dfs.py | 767 ++
tests/hwsim/test_dpp.py | 6350 ++++++++++
tests/hwsim/test_eap.py | 602 +
tests/hwsim/test_eap_proto.py | 10377 +++++++++++++++
tests/hwsim/test_erp.py | 741 ++
tests/hwsim/test_ext_password.py | 112 +
tests/hwsim/test_fils.py | 2360 ++++
tests/hwsim/test_fst_config.py | 553 +
tests/hwsim/test_fst_module.py | 2825 +++++
tests/hwsim/test_gas.py | 2053 +++
tests/hwsim/test_hapd_ctrl.py | 1071 ++
tests/hwsim/test_he.py | 1170 ++
tests/hwsim/test_hostapd_oom.py | 173 +
tests/hwsim/test_hs20_filter.py | 205 +
tests/hwsim/test_hs20_pps_mo.py | 43 +
tests/hwsim/test_ibss.py | 601 +
tests/hwsim/test_ieee8021x.py | 514 +
tests/hwsim/test_kernel.py | 128 +
tests/hwsim/test_macsec.py | 890 ++
tests/hwsim/test_mbo.py | 596 +
tests/hwsim/test_module_tests.py | 28 +
tests/hwsim/test_monitor_interface.py | 94 +
tests/hwsim/test_multi_ap.py | 353 +
tests/hwsim/test_nfc_p2p.py | 848 ++
tests/hwsim/test_nfc_wps.py | 709 ++
tests/hwsim/test_oce.py | 185 +
tests/hwsim/test_ocv.py | 1204 ++
tests/hwsim/test_offchannel_tx.py | 50 +
tests/hwsim/test_owe.py | 928 ++
tests/hwsim/test_p2p_autogo.py | 936 ++
tests/hwsim/test_p2p_channel.py | 1384 ++
tests/hwsim/test_p2p_concurrency.py | 286 +
tests/hwsim/test_p2p_device.py | 552 +
tests/hwsim/test_p2p_discovery.py | 820 ++
tests/hwsim/test_p2p_ext.py | 384 +
tests/hwsim/test_p2p_grpform.py | 1185 ++
tests/hwsim/test_p2p_invitation.py | 195 +
tests/hwsim/test_p2p_messages.py | 2143 ++++
tests/hwsim/test_p2p_persistent.py | 676 +
tests/hwsim/test_p2p_service.py | 586 +
tests/hwsim/test_p2p_set.py | 128 +
tests/hwsim/test_p2p_wifi_display.py | 475 +
tests/hwsim/test_p2ps.py | 1689 +++
tests/hwsim/test_pasn.py | 683 +
tests/hwsim/test_pmksa_cache.py | 1253 ++
tests/hwsim/test_radio_work.py | 133 +
tests/hwsim/test_radius.py | 1710 +++
tests/hwsim/test_rfkill.py | 242 +
tests/hwsim/test_rrm.py | 2128 ++++
tests/hwsim/test_sae.py | 2722 ++++
tests/hwsim/test_sae_pk.py | 462 +
tests/hwsim/test_scan.py | 2025 +++
tests/hwsim/test_sigma_dut.py | 5264 ++++++++
tests/hwsim/test_ssid.py | 127 +
tests/hwsim/test_sta_dynamic.py | 329 +
tests/hwsim/test_suite_b.py | 739 ++
tests/hwsim/test_tnc.py | 194 +
tests/hwsim/test_wep.py | 172 +
tests/hwsim/test_wext.py | 254 +
tests/hwsim/test_wmediumd.py | 480 +
tests/hwsim/test_wnm.py | 1951 +++
tests/hwsim/test_wpas_ap.py | 905 ++
tests/hwsim/test_wpas_config.py | 656 +
tests/hwsim/test_wpas_ctrl.py | 2149 ++++
tests/hwsim/test_wpas_mesh.py | 2534 ++++
tests/hwsim/test_wpas_wmm_ac.py | 400 +
tests/hwsim/tnc/.gitignore | 4 +
tests/hwsim/tnc/Makefile | 23 +
tests/hwsim/tnc/hostap2_imc.c | 183 +
tests/hwsim/tnc/hostap2_imv.c | 203 +
tests/hwsim/tnc/hostap_imc.c | 72 +
tests/hwsim/tnc/hostap_imv.c | 66 +
tests/hwsim/tnc/tnc_config | 4 +
tests/hwsim/tshark.py | 124 +
tests/hwsim/utils.py | 314 +
tests/hwsim/vm/.gitignore | 1 +
tests/hwsim/vm/README | 80 +
tests/hwsim/vm/bisect-run.sh | 43 +
tests/hwsim/vm/build-codecov.sh | 57 +
tests/hwsim/vm/combine-codecov.sh | 39 +
tests/hwsim/vm/dbus.conf | 34 +
tests/hwsim/vm/example-vm-setup.txt | 95 +
tests/hwsim/vm/inside.sh | 164 +
tests/hwsim/vm/kernel-config | 175 +
tests/hwsim/vm/kernel-config.uml | 131 +
tests/hwsim/vm/parallel-vm.py | 669 +
tests/hwsim/vm/process-codecov.sh | 36 +
tests/hwsim/vm/uevent.sh | 9 +
tests/hwsim/vm/vm-run.sh | 202 +
tests/hwsim/w1fi_logo.png | Bin 0 -> 7549 bytes
tests/hwsim/wlantest.py | 277 +
tests/hwsim/wpasupplicant.py | 1649 +++
tests/hwsim/wps-ctrl-cred | Bin 0 -> 67 bytes
tests/hwsim/wps-ctrl-cred2 | Bin 0 -> 59 bytes
tests/hwsim/wps-mixed-cred | Bin 0 -> 112 bytes
tests/hwsim/wps-wep-cred | Bin 0 -> 53 bytes
tests/remote/config.py | 87 +
tests/remote/hwsim_wrapper.py | 126 +
tests/remote/monitor.py | 193 +
tests/remote/run-tests.py | 408 +
tests/remote/rutils.py | 567 +
tests/remote/test_devices.py | 124 +
tests/remote/test_example.py | 141 +
tests/remote/test_monitor.py | 52 +
tests/test-aes.c | 624 +
tests/test-base64.c | 42 +
tests/test-https.c | 225 +
tests/test-https_server.c | 275 +
tests/test-list.c | 72 +
tests/test-md4.c | 93 +
tests/test-milenage.c | 814 ++
tests/test-rc4.c | 250 +
tests/test-rsa-sig-ver.c | 206 +
tests/test-sha1.c | 119 +
tests/test-sha256.c | 119 +
tests/test-x509v3.c | 62 +
tests/test_x509v3_nist.sh | 144 +
tests/test_x509v3_nist2.sh | 177 +
wlantest/.gitignore | 4 +
wlantest/Makefile | 87 +
wlantest/bip.c | 133 +
wlantest/bss.c | 373 +
wlantest/ccmp.c | 367 +
wlantest/ctrl.c | 1471 +++
wlantest/gcmp.c | 160 +
wlantest/inject.c | 341 +
wlantest/monitor.c | 172 +
wlantest/process.c | 409 +
wlantest/readpcap.c | 190 +
wlantest/rx_data.c | 904 ++
wlantest/rx_eapol.c | 1317 ++
wlantest/rx_ip.c | 184 +
wlantest/rx_mgmt.c | 2642 ++++
wlantest/rx_tdls.c | 618 +
wlantest/sta.c | 232 +
wlantest/test_vectors.c | 937 ++
wlantest/tkip.c | 428 +
wlantest/wep.c | 104 +
wlantest/wired.c | 295 +
wlantest/wlantest.c | 505 +
wlantest/wlantest.h | 336 +
wlantest/wlantest_cli.c | 1865 +++
wlantest/wlantest_ctrl.h | 171 +
wlantest/writepcap.c | 373 +
wpa_supplicant/.gitignore | 14 +
wpa_supplicant/Android.mk | 114 +-
wpa_supplicant/ChangeLog | 10 +-
wpa_supplicant/Makefile | 383 +-
wpa_supplicant/README | 4 +-
wpa_supplicant/README-DPP | 71 +-
wpa_supplicant/README-HS20 | 2 +-
wpa_supplicant/android.config | 16 +-
wpa_supplicant/ap.c | 223 +-
wpa_supplicant/binder/binder.h | 2 +-
wpa_supplicant/blacklist.c | 141 -
wpa_supplicant/blacklist.h | 24 -
wpa_supplicant/bss.c | 145 +-
wpa_supplicant/bss.h | 25 +-
wpa_supplicant/bssid_ignore.c | 221 +
wpa_supplicant/bssid_ignore.h | 33 +
wpa_supplicant/config.c | 644 +-
wpa_supplicant/config.h | 129 +-
wpa_supplicant/config_file.c | 243 +-
wpa_supplicant/config_ssid.h | 155 +-
wpa_supplicant/config_winreg.c | 39 +-
wpa_supplicant/ctrl_iface.c | 1153 +-
wpa_supplicant/ctrl_iface.h | 6 +-
wpa_supplicant/ctrl_iface_named_pipe.c | 2 +-
wpa_supplicant/ctrl_iface_udp.c | 57 +-
wpa_supplicant/ctrl_iface_unix.c | 30 +-
wpa_supplicant/dbus/dbus_common.c | 21 +-
wpa_supplicant/dbus/dbus_new.c | 76 +-
wpa_supplicant/dbus/dbus_new_handlers.c | 424 +-
wpa_supplicant/dbus/dbus_new_handlers.h | 6 +
wpa_supplicant/dbus/dbus_new_handlers_p2p.c | 77 +-
wpa_supplicant/dbus/dbus_new_introspect.c | 2 +-
wpa_supplicant/defconfig | 45 +-
wpa_supplicant/doc/docbook/.gitignore | 1 +
wpa_supplicant/doc/docbook/eapol_test.8 | 124 -
wpa_supplicant/doc/docbook/eapol_test.sgml | 4 +
wpa_supplicant/doc/docbook/manpage.links | 0
wpa_supplicant/doc/docbook/manpage.refs | 4 -
wpa_supplicant/doc/docbook/wpa_background.8 | 84 -
.../doc/docbook/wpa_background.sgml | 4 +
wpa_supplicant/doc/docbook/wpa_cli.8 | 219 -
wpa_supplicant/doc/docbook/wpa_cli.sgml | 4 +
wpa_supplicant/doc/docbook/wpa_gui.8 | 60 -
wpa_supplicant/doc/docbook/wpa_gui.sgml | 4 +
wpa_supplicant/doc/docbook/wpa_passphrase.8 | 40 -
.../doc/docbook/wpa_passphrase.sgml | 4 +
wpa_supplicant/doc/docbook/wpa_priv.8 | 120 -
wpa_supplicant/doc/docbook/wpa_priv.sgml | 4 +
wpa_supplicant/doc/docbook/wpa_supplicant.8 | 553 -
.../doc/docbook/wpa_supplicant.conf.5 | 225 -
.../doc/docbook/wpa_supplicant.conf.sgml | 4 +
.../doc/docbook/wpa_supplicant.sgml | 4 +
wpa_supplicant/dpp_supplicant.c | 1801 ++-
wpa_supplicant/dpp_supplicant.h | 15 +
wpa_supplicant/driver_i.h | 107 +-
wpa_supplicant/eapol_test.c | 9 +-
wpa_supplicant/events.c | 1555 ++-
wpa_supplicant/examples/dpp-nfc.py | 1186 ++
wpa_supplicant/examples/p2p-action-udhcp.sh | 4 +-
wpa_supplicant/examples/p2p-action.sh | 4 +-
wpa_supplicant/examples/p2p/p2p_connect.py | 18 +-
wpa_supplicant/examples/p2p/p2p_disconnect.py | 2 +-
wpa_supplicant/examples/p2p/p2p_find.py | 2 +-
wpa_supplicant/examples/p2p/p2p_flush.py | 2 +-
wpa_supplicant/examples/p2p/p2p_group_add.py | 14 +-
wpa_supplicant/examples/p2p/p2p_invite.py | 10 +-
wpa_supplicant/examples/p2p/p2p_listen.py | 2 +-
wpa_supplicant/examples/p2p/p2p_stop_find.py | 2 +-
wpa_supplicant/examples/udhcpd-p2p.conf | 12 +-
wpa_supplicant/gas_query.c | 60 +-
wpa_supplicant/gas_query.h | 2 +-
wpa_supplicant/hs20_supplicant.c | 30 +-
wpa_supplicant/ibss_rsn.c | 45 +-
wpa_supplicant/interworking.c | 66 +-
wpa_supplicant/interworking.h | 2 +-
wpa_supplicant/mbo.c | 30 +
wpa_supplicant/mesh.c | 243 +-
wpa_supplicant/mesh.h | 6 +-
wpa_supplicant/mesh_mpm.c | 49 +-
wpa_supplicant/mesh_rsn.c | 26 +-
wpa_supplicant/nmake.mak | 2 +-
wpa_supplicant/notify.c | 10 +-
wpa_supplicant/offchannel.c | 6 +-
wpa_supplicant/op_classes.c | 239 +-
wpa_supplicant/p2p_supplicant.c | 407 +-
wpa_supplicant/p2p_supplicant.h | 16 +-
wpa_supplicant/pasn_supplicant.c | 1584 +++
wpa_supplicant/preauth_test.c | 14 +-
wpa_supplicant/robust_av.c | 155 +
wpa_supplicant/rrm.c | 91 +-
wpa_supplicant/scan.c | 489 +-
wpa_supplicant/scan.h | 31 +
wpa_supplicant/sme.c | 521 +-
wpa_supplicant/sme.h | 8 +-
.../wpa_supplicant-nl80211.service.arg.in | 2 +-
.../wpa_supplicant-wired.service.arg.in | 2 +-
.../systemd/wpa_supplicant.service.arg.in | 2 +-
wpa_supplicant/twt.c | 142 +
.../vs2005/eapol_test/eapol_test.vcproj | 6 +-
.../wpa_supplicant/wpa_supplicant.vcproj | 6 +-
wpa_supplicant/vs2005/wpasvc/wpasvc.vcproj | 6 +-
wpa_supplicant/wmm_ac.c | 2 +-
wpa_supplicant/wnm_sta.c | 29 +-
wpa_supplicant/wpa_cli.c | 339 +-
wpa_supplicant/wpa_gui-qt4/icons/.gitignore | 2 +
wpa_supplicant/wpa_gui-qt4/icons/Makefile | 18 +-
wpa_supplicant/wpa_gui-qt4/peers.cpp | 4 +-
wpa_supplicant/wpa_gui-qt4/wpagui.cpp | 19 +-
wpa_supplicant/wpa_passphrase.c | 8 +-
wpa_supplicant/wpa_priv.c | 32 +-
wpa_supplicant/wpa_supplicant.c | 1191 +-
wpa_supplicant/wpa_supplicant.conf | 174 +-
wpa_supplicant/wpa_supplicant_i.h | 241 +-
wpa_supplicant/wpas_glue.c | 218 +-
wpa_supplicant/wpas_kay.c | 12 +-
wpa_supplicant/wpas_module_tests.c | 85 +-
wpa_supplicant/wps_supplicant.c | 76 +-
wpa_supplicant/wps_supplicant.h | 5 +
wpadebug/.gitignore | 4 +
wpadebug/AndroidManifest.xml | 86 +
wpadebug/README | 78 +
wpadebug/build.xml | 17 +
wpadebug/project.properties | 2 +
wpadebug/res/layout/cred_edit.xml | 117 +
wpadebug/res/layout/input_uri.xml | 26 +
wpadebug/res/layout/main.xml | 160 +
wpadebug/res/layout/qrcode.xml | 13 +
wpadebug/res/raw/shell_commands.txt | 2 +
wpadebug/res/raw/wpa_commands.txt | 9 +
.../w1/fi/wpadebug/CommandListActivity.java | 130 +
.../fi/wpadebug/DisplayMessageActivity.java | 49 +
wpadebug/src/w1/fi/wpadebug/InputUri.java | 108 +
wpadebug/src/w1/fi/wpadebug/MainActivity.java | 209 +
.../w1/fi/wpadebug/QrCodeDisplayActivity.java | 109 +
.../w1/fi/wpadebug/QrCodeReadActivity.java | 40 +
.../w1/fi/wpadebug/QrCodeScannerActivity.java | 82 +
wpadebug/src/w1/fi/wpadebug/WifiReceiver.java | 95 +
.../fi/wpadebug/WpaCommandListActivity.java | 112 +
.../src/w1/fi/wpadebug/WpaCredActivity.java | 263 +
.../w1/fi/wpadebug/WpaCredEditActivity.java | 55 +
.../src/w1/fi/wpadebug/WpaNfcActivity.java | 131 +
.../w1/fi/wpadebug/WpaWebViewActivity.java | 146 +
wpaspy/Makefile | 15 +
wpaspy/setup.py | 22 +
wpaspy/test.py | 82 +
wpaspy/wpaspy.c | 245 +
wpaspy/wpaspy.py | 149 +
1011 files changed, 241297 insertions(+), 22009 deletions(-)
create mode 100644 .gitignore
create mode 100644 Android.mk
create mode 100755 build_release
create mode 100644 doc/.gitignore
create mode 100644 doc/Makefile
create mode 100644 doc/code_structure.doxygen
create mode 100644 doc/ctrl_iface.doxygen
create mode 100644 doc/dbus.doxygen
create mode 100644 doc/directories.doxygen
create mode 100644 doc/doxygen.conf
create mode 100644 doc/driver_wrapper.doxygen
create mode 100644 doc/eap.doxygen
create mode 100644 doc/eap_server.doxygen
create mode 100644 doc/hostapd.fig
create mode 100644 doc/hostapd_ctrl_iface.doxygen
create mode 100644 doc/mainpage.doxygen
create mode 100644 doc/p2p.doxygen
create mode 100644 doc/p2p_arch.dot
create mode 100644 doc/p2p_arch2.dot
create mode 100644 doc/p2p_sm.dot
create mode 100644 doc/porting.doxygen
create mode 100644 doc/testing_tools.doxygen
create mode 100644 doc/wpa_supplicant.fig
create mode 100644 eap_example/.gitignore
create mode 100644 eap_example/Makefile
create mode 100644 eap_example/README
create mode 100644 eap_example/ca.pem
create mode 100644 eap_example/dh.conf
create mode 100644 eap_example/eap_example.c
create mode 100644 eap_example/eap_example_peer.c
create mode 100644 eap_example/eap_example_server.c
create mode 100644 eap_example/server-key.pem
create mode 100644 eap_example/server.key
create mode 100644 eap_example/server.pem
create mode 100644 hostapd/.gitignore
create mode 100644 hostapd/sae_pk_gen.c
create mode 100644 hs20/server/.gitignore
create mode 100644 hs20/server/Makefile
create mode 100755 hs20/server/ca/clean.sh
create mode 100644 hs20/server/ca/est-csrattrs.cnf
create mode 100755 hs20/server/ca/est-csrattrs.sh
create mode 100644 hs20/server/ca/hs20.oid
create mode 100755 hs20/server/ca/ocsp-req.sh
create mode 100755 hs20/server/ca/ocsp-responder-ica.sh
create mode 100755 hs20/server/ca/ocsp-responder.sh
create mode 100755 hs20/server/ca/ocsp-update-cache.sh
create mode 100644 hs20/server/ca/openssl-root.cnf
create mode 100644 hs20/server/ca/openssl.cnf
create mode 100755 hs20/server/ca/setup.sh
create mode 100644 hs20/server/ca/w1fi_logo.png
create mode 100644 hs20/server/hs20-osu-server.txt
create mode 100644 hs20/server/hs20_spp_server.c
create mode 100644 hs20/server/spp_server.c
create mode 100644 hs20/server/spp_server.h
create mode 100644 hs20/server/sql-example.txt
create mode 100644 hs20/server/sql.txt
create mode 100644 hs20/server/www/add-free.php
create mode 100644 hs20/server/www/add-mo.php
create mode 100644 hs20/server/www/cert-enroll.php
create mode 100644 hs20/server/www/config.php
create mode 100644 hs20/server/www/est.php
create mode 100644 hs20/server/www/free-remediation.php
create mode 100644 hs20/server/www/free.php
create mode 100644 hs20/server/www/redirect.php
create mode 100644 hs20/server/www/remediation-pw.php
create mode 100644 hs20/server/www/remediation.php
create mode 100644 hs20/server/www/signup.php
create mode 100644 hs20/server/www/spp.php
create mode 100644 hs20/server/www/terms.php
create mode 100644 hs20/server/www/users.php
create mode 100644 radius_example/.gitignore
create mode 100644 radius_example/Makefile
create mode 100644 radius_example/README
create mode 100644 radius_example/radius_example.c
delete mode 100644 src/ap/iapp.c
delete mode 100644 src/ap/iapp.h
create mode 100644 src/build.rules
create mode 100644 src/common/brcm_vendor.h
create mode 100644 src/common/dpp_auth.c
create mode 100644 src/common/dpp_backup.c
create mode 100644 src/common/dpp_crypto.c
create mode 100644 src/common/dpp_i.h
create mode 100644 src/common/dpp_pkex.c
create mode 100644 src/common/dpp_reconfig.c
create mode 100644 src/common/dpp_tcp.c
create mode 100644 src/common/ptksa_cache.c
create mode 100644 src/common/ptksa_cache.h
create mode 100644 src/common/sae_pk.c
delete mode 100644 src/crypto/.gitignore
create mode 100644 src/crypto/sha384-tlsprf.c
delete mode 100644 src/drivers/.gitignore
create mode 100644 src/eap_peer/.gitignore
create mode 100644 src/objs.mk
delete mode 100644 src/radius/.gitignore
delete mode 100644 src/tls/.gitignore
delete mode 100644 src/utils/.gitignore
create mode 100644 src/utils/config.c
create mode 100644 src/utils/config.h
create mode 100644 src/utils/ext_password_file.c
create mode 100644 tests/.gitignore
create mode 100644 tests/Makefile
create mode 100644 tests/README
create mode 100644 tests/cipher-and-key-mgmt-testing.txt
create mode 100644 tests/fuzzing/README
create mode 100644 tests/fuzzing/ap-mgmt/.gitignore
create mode 100644 tests/fuzzing/ap-mgmt/Makefile
create mode 100644 tests/fuzzing/ap-mgmt/ap-mgmt.c
create mode 100644 tests/fuzzing/ap-mgmt/corpus/multi-sae-ffc.dat
create mode 100644 tests/fuzzing/ap-mgmt/corpus/multi-sae.dat
create mode 100644 tests/fuzzing/ap-mgmt/corpus/multi.dat
create mode 100644 tests/fuzzing/asn1/.gitignore
create mode 100644 tests/fuzzing/asn1/Makefile
create mode 100644 tests/fuzzing/asn1/asn1.c
create mode 100644 tests/fuzzing/asn1/corpus/ca.der
create mode 100644 tests/fuzzing/asn1/corpus/ocsp-multi-server-cache.der
create mode 100644 tests/fuzzing/asn1/corpus/ocsp-req.der
create mode 100755 tests/fuzzing/build-test.sh
create mode 100644 tests/fuzzing/dpp-uri/.gitignore
create mode 100644 tests/fuzzing/dpp-uri/Makefile
create mode 100644 tests/fuzzing/dpp-uri/corpus/1.dat
create mode 100644 tests/fuzzing/dpp-uri/corpus/2.dat
create mode 100644 tests/fuzzing/dpp-uri/corpus/3.dat
create mode 100644 tests/fuzzing/dpp-uri/dpp-uri.c
create mode 100644 tests/fuzzing/eap-aka-peer/.gitignore
create mode 100644 tests/fuzzing/eap-aka-peer/Makefile
create mode 100644 tests/fuzzing/eap-aka-peer/corpus/server.msg
create mode 100644 tests/fuzzing/eap-aka-peer/eap-aka-peer.c
create mode 100644 tests/fuzzing/eap-mschapv2-peer/.gitignore
create mode 100644 tests/fuzzing/eap-mschapv2-peer/Makefile
create mode 100644 tests/fuzzing/eap-mschapv2-peer/corpus/server.msg
create mode 100644 tests/fuzzing/eap-mschapv2-peer/eap-mschapv2-peer.c
create mode 100644 tests/fuzzing/eap-sim-peer/.gitignore
create mode 100644 tests/fuzzing/eap-sim-peer/Makefile
create mode 100644 tests/fuzzing/eap-sim-peer/corpus/server.msg
create mode 100644 tests/fuzzing/eap-sim-peer/eap-sim-peer.c
create mode 100644 tests/fuzzing/eapol-key-auth/.gitignore
create mode 100644 tests/fuzzing/eapol-key-auth/Makefile
create mode 100644 tests/fuzzing/eapol-key-auth/corpus/supp.msg
create mode 100644 tests/fuzzing/eapol-key-auth/eapol-key-auth.c
create mode 100644 tests/fuzzing/eapol-key-supp/.gitignore
create mode 100644 tests/fuzzing/eapol-key-supp/Makefile
create mode 100644 tests/fuzzing/eapol-key-supp/corpus/auth.msg
create mode 100644 tests/fuzzing/eapol-key-supp/eapol-key-supp.c
create mode 100644 tests/fuzzing/eapol-supp/.gitignore
create mode 100644 tests/fuzzing/eapol-supp/Makefile
create mode 100644 tests/fuzzing/eapol-supp/corpus/eap-req-identity.dat
create mode 100644 tests/fuzzing/eapol-supp/corpus/eap-req-sim.dat
create mode 100644 tests/fuzzing/eapol-supp/corpus/eapol-key-m1.dat
create mode 100644 tests/fuzzing/eapol-supp/eapol-supp.c
create mode 100644 tests/fuzzing/fuzzer-common.c
create mode 100644 tests/fuzzing/fuzzer-common.h
create mode 100644 tests/fuzzing/json/.gitignore
create mode 100644 tests/fuzzing/json/Makefile
create mode 100644 tests/fuzzing/json/corpus/1.json
create mode 100644 tests/fuzzing/json/corpus/2.json
create mode 100644 tests/fuzzing/json/corpus/3.json
create mode 100644 tests/fuzzing/json/json.c
create mode 100644 tests/fuzzing/p2p/.gitignore
create mode 100644 tests/fuzzing/p2p/Makefile
create mode 100644 tests/fuzzing/p2p/corpus/go-neg-req.dat
create mode 100644 tests/fuzzing/p2p/corpus/invitation-req.dat
create mode 100644 tests/fuzzing/p2p/corpus/p2ps-pd-req.dat
create mode 100644 tests/fuzzing/p2p/corpus/proberesp-go.dat
create mode 100644 tests/fuzzing/p2p/corpus/proberesp.dat
create mode 100644 tests/fuzzing/p2p/p2p.c
create mode 100644 tests/fuzzing/rules.include
create mode 100644 tests/fuzzing/sae/.gitignore
create mode 100644 tests/fuzzing/sae/Makefile
create mode 100644 tests/fuzzing/sae/corpus/sae-commit-h2e-rejected-groups.dat
create mode 100644 tests/fuzzing/sae/corpus/sae-commit-h2e-token.dat
create mode 100644 tests/fuzzing/sae/corpus/sae-commit-pw-id.dat
create mode 100644 tests/fuzzing/sae/corpus/sae-commit-token.dat
create mode 100644 tests/fuzzing/sae/corpus/sae-commit-valid.dat
create mode 100644 tests/fuzzing/sae/sae.c
create mode 100644 tests/fuzzing/tls-client/.gitignore
create mode 100644 tests/fuzzing/tls-client/Makefile
create mode 100644 tests/fuzzing/tls-client/corpus/server.msg
create mode 100644 tests/fuzzing/tls-client/tls-client.c
create mode 100644 tests/fuzzing/tls-server/.gitignore
create mode 100644 tests/fuzzing/tls-server/Makefile
create mode 100644 tests/fuzzing/tls-server/corpus/client.msg
create mode 100644 tests/fuzzing/tls-server/tls-server.c
create mode 100644 tests/fuzzing/wnm/.gitignore
create mode 100644 tests/fuzzing/wnm/Makefile
create mode 100644 tests/fuzzing/wnm/corpus/bss-tm-req.dat
create mode 100644 tests/fuzzing/wnm/corpus/oss-fuzz-0001.dat
create mode 100644 tests/fuzzing/wnm/corpus/oss-fuzz-0002.dat
create mode 100644 tests/fuzzing/wnm/corpus/wnm-notif.dat
create mode 100644 tests/fuzzing/wnm/wnm.c
create mode 100644 tests/fuzzing/x509/.gitignore
create mode 100644 tests/fuzzing/x509/Makefile
create mode 100644 tests/fuzzing/x509/corpus/ca.der
create mode 100644 tests/fuzzing/x509/corpus/oss-fuzz-15408
create mode 100644 tests/fuzzing/x509/x509.c
create mode 100644 tests/hwsim/.gitignore
create mode 100644 tests/hwsim/README
create mode 100644 tests/hwsim/auth_serv/as.conf
create mode 100644 tests/hwsim/auth_serv/as2.conf
create mode 100644 tests/hwsim/auth_serv/ca-and-crl-expired.pem
create mode 100644 tests/hwsim/auth_serv/ca-and-crl.pem
create mode 100644 tests/hwsim/auth_serv/ca-incorrect-key.pem
create mode 100644 tests/hwsim/auth_serv/ca-incorrect.der
create mode 100644 tests/hwsim/auth_serv/ca-incorrect.pem
create mode 100644 tests/hwsim/auth_serv/ca-key.pem
create mode 100644 tests/hwsim/auth_serv/ca.der
create mode 100644 tests/hwsim/auth_serv/ca.pem
create mode 100644 tests/hwsim/auth_serv/dh.conf
create mode 100644 tests/hwsim/auth_serv/dh2.conf
create mode 100644 tests/hwsim/auth_serv/dh_param_3072.pem
create mode 100644 tests/hwsim/auth_serv/dsaparam.pem
create mode 100644 tests/hwsim/auth_serv/eap_user.conf
create mode 100644 tests/hwsim/auth_serv/eap_user_vlan.conf
create mode 100644 tests/hwsim/auth_serv/ec-ca-openssl.cnf
create mode 100644 tests/hwsim/auth_serv/ec-ca.key
create mode 100644 tests/hwsim/auth_serv/ec-ca.pem
create mode 100755 tests/hwsim/auth_serv/ec-generate.sh
create mode 100644 tests/hwsim/auth_serv/ec-server.key
create mode 100644 tests/hwsim/auth_serv/ec-server.pem
create mode 100644 tests/hwsim/auth_serv/ec-user.key
create mode 100644 tests/hwsim/auth_serv/ec-user.pem
create mode 100644 tests/hwsim/auth_serv/ec2-ca.key
create mode 100644 tests/hwsim/auth_serv/ec2-ca.pem
create mode 100755 tests/hwsim/auth_serv/ec2-generate.sh
create mode 100644 tests/hwsim/auth_serv/ec2-server.key
create mode 100644 tests/hwsim/auth_serv/ec2-server.pem
create mode 100644 tests/hwsim/auth_serv/ec2-user-p256.key
create mode 100644 tests/hwsim/auth_serv/ec2-user-p256.pem
create mode 100644 tests/hwsim/auth_serv/ec2-user.key
create mode 100644 tests/hwsim/auth_serv/ec2-user.pem
create mode 100644 tests/hwsim/auth_serv/hlr_auc_gw.gsm
create mode 100644 tests/hwsim/auth_serv/hlr_auc_gw.milenage_db
create mode 100644 tests/hwsim/auth_serv/iCA-server/ca-and-root.pem
create mode 100644 tests/hwsim/auth_serv/iCA-server/cacert.pem
create mode 100644 tests/hwsim/auth_serv/iCA-server/careq.pem
create mode 100644 tests/hwsim/auth_serv/iCA-server/index.txt
create mode 100644 tests/hwsim/auth_serv/iCA-server/index.txt.attr
create mode 100644 tests/hwsim/auth_serv/iCA-server/private/cakey.pem
create mode 100644 tests/hwsim/auth_serv/iCA-server/serial
create mode 100644 tests/hwsim/auth_serv/iCA-server/server-revoked.key
create mode 100644 tests/hwsim/auth_serv/iCA-server/server-revoked.pem
create mode 100644 tests/hwsim/auth_serv/iCA-server/server-revoked.req
create mode 100644 tests/hwsim/auth_serv/iCA-server/server-revoked_and_ica.pem
create mode 100644 tests/hwsim/auth_serv/iCA-server/server.key
create mode 100644 tests/hwsim/auth_serv/iCA-server/server.pem
create mode 100644 tests/hwsim/auth_serv/iCA-server/server.req
create mode 100644 tests/hwsim/auth_serv/iCA-server/server_and_ica.pem
create mode 100644 tests/hwsim/auth_serv/iCA-user/ca-and-root.pem
create mode 100644 tests/hwsim/auth_serv/iCA-user/cacert.pem
create mode 100644 tests/hwsim/auth_serv/iCA-user/careq.pem
create mode 100644 tests/hwsim/auth_serv/iCA-user/index.txt
create mode 100644 tests/hwsim/auth_serv/iCA-user/index.txt.attr
create mode 100644 tests/hwsim/auth_serv/iCA-user/private/cakey.pem
create mode 100644 tests/hwsim/auth_serv/iCA-user/serial
create mode 100644 tests/hwsim/auth_serv/iCA-user/user.key
create mode 100644 tests/hwsim/auth_serv/iCA-user/user.pem
create mode 100644 tests/hwsim/auth_serv/iCA-user/user.req
create mode 100644 tests/hwsim/auth_serv/iCA-user/user_and_ica.pem
create mode 100755 tests/hwsim/auth_serv/ica-generate.sh
create mode 100644 tests/hwsim/auth_serv/index-revoked.txt
create mode 100644 tests/hwsim/auth_serv/index-unknown.txt
create mode 100644 tests/hwsim/auth_serv/index.txt
create mode 100644 tests/hwsim/auth_serv/ocsp-multi-server-cache.der
create mode 100644 tests/hwsim/auth_serv/ocsp-req.der
create mode 100644 tests/hwsim/auth_serv/ocsp-responder.csr
create mode 100644 tests/hwsim/auth_serv/ocsp-responder.key
create mode 100644 tests/hwsim/auth_serv/ocsp-responder.pem
create mode 100644 tests/hwsim/auth_serv/ocsp-server-cache.der
create mode 100644 tests/hwsim/auth_serv/ocsp-server-cache.der-invalid
create mode 100644 tests/hwsim/auth_serv/openssl2.cnf
create mode 100644 tests/hwsim/auth_serv/radius_clients.conf
create mode 100644 tests/hwsim/auth_serv/radius_clients_ipv6.conf
create mode 100644 tests/hwsim/auth_serv/radius_clients_none.conf
create mode 100644 tests/hwsim/auth_serv/rootCA/index.txt
create mode 100644 tests/hwsim/auth_serv/rootCA/index.txt.attr
create mode 100644 tests/hwsim/auth_serv/rootCA/serial
create mode 100644 tests/hwsim/auth_serv/rsa3072-ca.key
create mode 100644 tests/hwsim/auth_serv/rsa3072-ca.pem
create mode 100755 tests/hwsim/auth_serv/rsa3072-generate.sh
create mode 100644 tests/hwsim/auth_serv/rsa3072-server.key
create mode 100644 tests/hwsim/auth_serv/rsa3072-server.pem
create mode 100644 tests/hwsim/auth_serv/rsa3072-server.req
create mode 100644 tests/hwsim/auth_serv/rsa3072-user-rsa2048.key
create mode 100644 tests/hwsim/auth_serv/rsa3072-user-rsa2048.pem
create mode 100644 tests/hwsim/auth_serv/rsa3072-user-rsa2048.req
create mode 100644 tests/hwsim/auth_serv/rsa3072-user.key
create mode 100644 tests/hwsim/auth_serv/rsa3072-user.pem
create mode 100644 tests/hwsim/auth_serv/rsa3072-user.req
create mode 100644 tests/hwsim/auth_serv/server-certpol.csr
create mode 100644 tests/hwsim/auth_serv/server-certpol.key
create mode 100644 tests/hwsim/auth_serv/server-certpol.pem
create mode 100644 tests/hwsim/auth_serv/server-certpol2.csr
create mode 100644 tests/hwsim/auth_serv/server-certpol2.key
create mode 100644 tests/hwsim/auth_serv/server-certpol2.pem
create mode 100644 tests/hwsim/auth_serv/server-eku-client-server.csr
create mode 100644 tests/hwsim/auth_serv/server-eku-client-server.key
create mode 100644 tests/hwsim/auth_serv/server-eku-client-server.pem
create mode 100644 tests/hwsim/auth_serv/server-eku-client.csr
create mode 100644 tests/hwsim/auth_serv/server-eku-client.key
create mode 100644 tests/hwsim/auth_serv/server-eku-client.pem
create mode 100644 tests/hwsim/auth_serv/server-expired.csr
create mode 100644 tests/hwsim/auth_serv/server-expired.key
create mode 100644 tests/hwsim/auth_serv/server-expired.pem
create mode 100644 tests/hwsim/auth_serv/server-extra.pkcs12
create mode 100644 tests/hwsim/auth_serv/server-long-duration.csr
create mode 100644 tests/hwsim/auth_serv/server-long-duration.key
create mode 100644 tests/hwsim/auth_serv/server-long-duration.pem
create mode 100644 tests/hwsim/auth_serv/server-no-dnsname.csr
create mode 100644 tests/hwsim/auth_serv/server-no-dnsname.key
create mode 100644 tests/hwsim/auth_serv/server-no-dnsname.pem
create mode 100644 tests/hwsim/auth_serv/server.csr
create mode 100644 tests/hwsim/auth_serv/server.key
create mode 100644 tests/hwsim/auth_serv/server.pem
create mode 100644 tests/hwsim/auth_serv/server.pkcs12
create mode 100644 tests/hwsim/auth_serv/sha384-server.key
create mode 100644 tests/hwsim/auth_serv/sha384-server.pem
create mode 100644 tests/hwsim/auth_serv/sha384-user.key
create mode 100644 tests/hwsim/auth_serv/sha384-user.pem
create mode 100644 tests/hwsim/auth_serv/sha512-ca.key
create mode 100644 tests/hwsim/auth_serv/sha512-ca.pem
create mode 100755 tests/hwsim/auth_serv/sha512-generate.sh
create mode 100644 tests/hwsim/auth_serv/sha512-server.key
create mode 100644 tests/hwsim/auth_serv/sha512-server.pem
create mode 100644 tests/hwsim/auth_serv/sha512-user.key
create mode 100644 tests/hwsim/auth_serv/sha512-user.pem
create mode 100755 tests/hwsim/auth_serv/update.sh
create mode 100644 tests/hwsim/auth_serv/user.csr
create mode 100644 tests/hwsim/auth_serv/user.key
create mode 100644 tests/hwsim/auth_serv/user.key.pkcs8
create mode 100644 tests/hwsim/auth_serv/user.key.pkcs8.pkcs5v15
create mode 100644 tests/hwsim/auth_serv/user.pem
create mode 100644 tests/hwsim/auth_serv/user.pkcs12
create mode 100644 tests/hwsim/auth_serv/user.rsa-key
create mode 100644 tests/hwsim/auth_serv/user2.pkcs12
create mode 100644 tests/hwsim/auth_serv/user3.pkcs12
create mode 100755 tests/hwsim/build.sh
create mode 100644 tests/hwsim/check_kernel.py
create mode 100644 tests/hwsim/devdetail.xml
create mode 100644 tests/hwsim/devinfo.xml
create mode 100644 tests/hwsim/dictionary.radius
create mode 100644 tests/hwsim/example-hostapd.config
create mode 100644 tests/hwsim/example-setup.txt
create mode 100644 tests/hwsim/example-wpa_supplicant.config
create mode 100644 tests/hwsim/fst_module_aux.py
create mode 100644 tests/hwsim/fst_test_common.py
create mode 100644 tests/hwsim/hostapd.py
create mode 100644 tests/hwsim/hostapd.vlan
create mode 100644 tests/hwsim/hostapd.vlan2
create mode 100644 tests/hwsim/hostapd.wlan3.vlan
create mode 100644 tests/hwsim/hostapd.wlan4.vlan
create mode 100644 tests/hwsim/hostapd.wpa_psk
create mode 100644 tests/hwsim/hwsim.py
create mode 100644 tests/hwsim/hwsim_utils.py
create mode 100644 tests/hwsim/multi-bss-acs.conf
create mode 100644 tests/hwsim/multi-bss-iface-per_sta_vif.conf
create mode 100644 tests/hwsim/multi-bss-iface.conf
create mode 100644 tests/hwsim/multi-bss.conf
create mode 100644 tests/hwsim/netlink.py
create mode 100644 tests/hwsim/nl80211.py
create mode 100644 tests/hwsim/owe-bss-1.conf
create mode 100644 tests/hwsim/owe-bss-2.conf
create mode 100644 tests/hwsim/p2p0.conf
create mode 100644 tests/hwsim/p2p1.conf
create mode 100644 tests/hwsim/p2p2.conf
create mode 100644 tests/hwsim/p2p_utils.py
create mode 100644 tests/hwsim/pps-mo-1.xml
create mode 100644 tests/hwsim/radius_das.py
create mode 100644 tests/hwsim/remotehost.py
create mode 100755 tests/hwsim/rfkill.py
create mode 100755 tests/hwsim/run-all.sh
create mode 100755 tests/hwsim/run-tests.py
create mode 100755 tests/hwsim/start.sh
create mode 100755 tests/hwsim/stop.sh
create mode 100644 tests/hwsim/test_ap_acs.py
create mode 100644 tests/hwsim/test_ap_ciphers.py
create mode 100644 tests/hwsim/test_ap_config.py
create mode 100644 tests/hwsim/test_ap_csa.py
create mode 100644 tests/hwsim/test_ap_dynamic.py
create mode 100644 tests/hwsim/test_ap_eap.py
create mode 100644 tests/hwsim/test_ap_ft.py
create mode 100644 tests/hwsim/test_ap_hs20.py
create mode 100644 tests/hwsim/test_ap_ht.py
create mode 100644 tests/hwsim/test_ap_mixed.py
create mode 100644 tests/hwsim/test_ap_open.py
create mode 100644 tests/hwsim/test_ap_params.py
create mode 100644 tests/hwsim/test_ap_pmf.py
create mode 100644 tests/hwsim/test_ap_psk.py
create mode 100644 tests/hwsim/test_ap_qosmap.py
create mode 100644 tests/hwsim/test_ap_roam.py
create mode 100644 tests/hwsim/test_ap_tdls.py
create mode 100644 tests/hwsim/test_ap_track.py
create mode 100644 tests/hwsim/test_ap_vht.py
create mode 100644 tests/hwsim/test_ap_vlan.py
create mode 100644 tests/hwsim/test_ap_wps.py
create mode 100644 tests/hwsim/test_authsrv.py
create mode 100644 tests/hwsim/test_autoscan.py
create mode 100644 tests/hwsim/test_bgscan.py
create mode 100644 tests/hwsim/test_cert_check.py
create mode 100644 tests/hwsim/test_cfg80211.py
create mode 100644 tests/hwsim/test_connect_cmd.py
create mode 100644 tests/hwsim/test_dbus.py
create mode 100644 tests/hwsim/test_dfs.py
create mode 100644 tests/hwsim/test_dpp.py
create mode 100644 tests/hwsim/test_eap.py
create mode 100644 tests/hwsim/test_eap_proto.py
create mode 100644 tests/hwsim/test_erp.py
create mode 100644 tests/hwsim/test_ext_password.py
create mode 100644 tests/hwsim/test_fils.py
create mode 100644 tests/hwsim/test_fst_config.py
create mode 100644 tests/hwsim/test_fst_module.py
create mode 100644 tests/hwsim/test_gas.py
create mode 100644 tests/hwsim/test_hapd_ctrl.py
create mode 100644 tests/hwsim/test_he.py
create mode 100644 tests/hwsim/test_hostapd_oom.py
create mode 100644 tests/hwsim/test_hs20_filter.py
create mode 100644 tests/hwsim/test_hs20_pps_mo.py
create mode 100644 tests/hwsim/test_ibss.py
create mode 100644 tests/hwsim/test_ieee8021x.py
create mode 100644 tests/hwsim/test_kernel.py
create mode 100644 tests/hwsim/test_macsec.py
create mode 100644 tests/hwsim/test_mbo.py
create mode 100644 tests/hwsim/test_module_tests.py
create mode 100644 tests/hwsim/test_monitor_interface.py
create mode 100644 tests/hwsim/test_multi_ap.py
create mode 100644 tests/hwsim/test_nfc_p2p.py
create mode 100644 tests/hwsim/test_nfc_wps.py
create mode 100644 tests/hwsim/test_oce.py
create mode 100644 tests/hwsim/test_ocv.py
create mode 100644 tests/hwsim/test_offchannel_tx.py
create mode 100644 tests/hwsim/test_owe.py
create mode 100644 tests/hwsim/test_p2p_autogo.py
create mode 100644 tests/hwsim/test_p2p_channel.py
create mode 100644 tests/hwsim/test_p2p_concurrency.py
create mode 100644 tests/hwsim/test_p2p_device.py
create mode 100644 tests/hwsim/test_p2p_discovery.py
create mode 100644 tests/hwsim/test_p2p_ext.py
create mode 100644 tests/hwsim/test_p2p_grpform.py
create mode 100644 tests/hwsim/test_p2p_invitation.py
create mode 100644 tests/hwsim/test_p2p_messages.py
create mode 100644 tests/hwsim/test_p2p_persistent.py
create mode 100644 tests/hwsim/test_p2p_service.py
create mode 100644 tests/hwsim/test_p2p_set.py
create mode 100644 tests/hwsim/test_p2p_wifi_display.py
create mode 100644 tests/hwsim/test_p2ps.py
create mode 100644 tests/hwsim/test_pasn.py
create mode 100644 tests/hwsim/test_pmksa_cache.py
create mode 100644 tests/hwsim/test_radio_work.py
create mode 100644 tests/hwsim/test_radius.py
create mode 100644 tests/hwsim/test_rfkill.py
create mode 100644 tests/hwsim/test_rrm.py
create mode 100644 tests/hwsim/test_sae.py
create mode 100644 tests/hwsim/test_sae_pk.py
create mode 100644 tests/hwsim/test_scan.py
create mode 100644 tests/hwsim/test_sigma_dut.py
create mode 100644 tests/hwsim/test_ssid.py
create mode 100644 tests/hwsim/test_sta_dynamic.py
create mode 100644 tests/hwsim/test_suite_b.py
create mode 100644 tests/hwsim/test_tnc.py
create mode 100644 tests/hwsim/test_wep.py
create mode 100644 tests/hwsim/test_wext.py
create mode 100644 tests/hwsim/test_wmediumd.py
create mode 100644 tests/hwsim/test_wnm.py
create mode 100644 tests/hwsim/test_wpas_ap.py
create mode 100644 tests/hwsim/test_wpas_config.py
create mode 100644 tests/hwsim/test_wpas_ctrl.py
create mode 100644 tests/hwsim/test_wpas_mesh.py
create mode 100644 tests/hwsim/test_wpas_wmm_ac.py
create mode 100644 tests/hwsim/tnc/.gitignore
create mode 100644 tests/hwsim/tnc/Makefile
create mode 100644 tests/hwsim/tnc/hostap2_imc.c
create mode 100644 tests/hwsim/tnc/hostap2_imv.c
create mode 100644 tests/hwsim/tnc/hostap_imc.c
create mode 100644 tests/hwsim/tnc/hostap_imv.c
create mode 100644 tests/hwsim/tnc/tnc_config
create mode 100644 tests/hwsim/tshark.py
create mode 100644 tests/hwsim/utils.py
create mode 100644 tests/hwsim/vm/.gitignore
create mode 100644 tests/hwsim/vm/README
create mode 100755 tests/hwsim/vm/bisect-run.sh
create mode 100755 tests/hwsim/vm/build-codecov.sh
create mode 100755 tests/hwsim/vm/combine-codecov.sh
create mode 100644 tests/hwsim/vm/dbus.conf
create mode 100644 tests/hwsim/vm/example-vm-setup.txt
create mode 100755 tests/hwsim/vm/inside.sh
create mode 100644 tests/hwsim/vm/kernel-config
create mode 100644 tests/hwsim/vm/kernel-config.uml
create mode 100755 tests/hwsim/vm/parallel-vm.py
create mode 100755 tests/hwsim/vm/process-codecov.sh
create mode 100755 tests/hwsim/vm/uevent.sh
create mode 100755 tests/hwsim/vm/vm-run.sh
create mode 100644 tests/hwsim/w1fi_logo.png
create mode 100644 tests/hwsim/wlantest.py
create mode 100644 tests/hwsim/wpasupplicant.py
create mode 100644 tests/hwsim/wps-ctrl-cred
create mode 100644 tests/hwsim/wps-ctrl-cred2
create mode 100644 tests/hwsim/wps-mixed-cred
create mode 100644 tests/hwsim/wps-wep-cred
create mode 100644 tests/remote/config.py
create mode 100644 tests/remote/hwsim_wrapper.py
create mode 100644 tests/remote/monitor.py
create mode 100755 tests/remote/run-tests.py
create mode 100644 tests/remote/rutils.py
create mode 100644 tests/remote/test_devices.py
create mode 100644 tests/remote/test_example.py
create mode 100644 tests/remote/test_monitor.py
create mode 100644 tests/test-aes.c
create mode 100644 tests/test-base64.c
create mode 100644 tests/test-https.c
create mode 100644 tests/test-https_server.c
create mode 100644 tests/test-list.c
create mode 100644 tests/test-md4.c
create mode 100644 tests/test-milenage.c
create mode 100644 tests/test-rc4.c
create mode 100644 tests/test-rsa-sig-ver.c
create mode 100644 tests/test-sha1.c
create mode 100644 tests/test-sha256.c
create mode 100644 tests/test-x509v3.c
create mode 100755 tests/test_x509v3_nist.sh
create mode 100755 tests/test_x509v3_nist2.sh
create mode 100644 wlantest/.gitignore
create mode 100644 wlantest/Makefile
create mode 100644 wlantest/bip.c
create mode 100644 wlantest/bss.c
create mode 100644 wlantest/ccmp.c
create mode 100644 wlantest/ctrl.c
create mode 100644 wlantest/gcmp.c
create mode 100644 wlantest/inject.c
create mode 100644 wlantest/monitor.c
create mode 100644 wlantest/process.c
create mode 100644 wlantest/readpcap.c
create mode 100644 wlantest/rx_data.c
create mode 100644 wlantest/rx_eapol.c
create mode 100644 wlantest/rx_ip.c
create mode 100644 wlantest/rx_mgmt.c
create mode 100644 wlantest/rx_tdls.c
create mode 100644 wlantest/sta.c
create mode 100644 wlantest/test_vectors.c
create mode 100644 wlantest/tkip.c
create mode 100644 wlantest/wep.c
create mode 100644 wlantest/wired.c
create mode 100644 wlantest/wlantest.c
create mode 100644 wlantest/wlantest.h
create mode 100644 wlantest/wlantest_cli.c
create mode 100644 wlantest/wlantest_ctrl.h
create mode 100644 wlantest/writepcap.c
delete mode 100644 wpa_supplicant/blacklist.c
delete mode 100644 wpa_supplicant/blacklist.h
create mode 100644 wpa_supplicant/bssid_ignore.c
create mode 100644 wpa_supplicant/bssid_ignore.h
delete mode 100644 wpa_supplicant/doc/docbook/eapol_test.8
delete mode 100644 wpa_supplicant/doc/docbook/manpage.links
delete mode 100644 wpa_supplicant/doc/docbook/manpage.refs
delete mode 100644 wpa_supplicant/doc/docbook/wpa_background.8
delete mode 100644 wpa_supplicant/doc/docbook/wpa_cli.8
delete mode 100644 wpa_supplicant/doc/docbook/wpa_gui.8
delete mode 100644 wpa_supplicant/doc/docbook/wpa_passphrase.8
delete mode 100644 wpa_supplicant/doc/docbook/wpa_priv.8
delete mode 100644 wpa_supplicant/doc/docbook/wpa_supplicant.8
delete mode 100644 wpa_supplicant/doc/docbook/wpa_supplicant.conf.5
create mode 100755 wpa_supplicant/examples/dpp-nfc.py
create mode 100644 wpa_supplicant/pasn_supplicant.c
create mode 100644 wpa_supplicant/robust_av.c
create mode 100644 wpa_supplicant/twt.c
create mode 100644 wpa_supplicant/wpa_gui-qt4/icons/.gitignore
create mode 100644 wpadebug/.gitignore
create mode 100644 wpadebug/AndroidManifest.xml
create mode 100644 wpadebug/README
create mode 100644 wpadebug/build.xml
create mode 100644 wpadebug/project.properties
create mode 100644 wpadebug/res/layout/cred_edit.xml
create mode 100644 wpadebug/res/layout/input_uri.xml
create mode 100644 wpadebug/res/layout/main.xml
create mode 100644 wpadebug/res/layout/qrcode.xml
create mode 100644 wpadebug/res/raw/shell_commands.txt
create mode 100644 wpadebug/res/raw/wpa_commands.txt
create mode 100644 wpadebug/src/w1/fi/wpadebug/CommandListActivity.java
create mode 100644 wpadebug/src/w1/fi/wpadebug/DisplayMessageActivity.java
create mode 100644 wpadebug/src/w1/fi/wpadebug/InputUri.java
create mode 100644 wpadebug/src/w1/fi/wpadebug/MainActivity.java
create mode 100644 wpadebug/src/w1/fi/wpadebug/QrCodeDisplayActivity.java
create mode 100644 wpadebug/src/w1/fi/wpadebug/QrCodeReadActivity.java
create mode 100644 wpadebug/src/w1/fi/wpadebug/QrCodeScannerActivity.java
create mode 100644 wpadebug/src/w1/fi/wpadebug/WifiReceiver.java
create mode 100644 wpadebug/src/w1/fi/wpadebug/WpaCommandListActivity.java
create mode 100644 wpadebug/src/w1/fi/wpadebug/WpaCredActivity.java
create mode 100644 wpadebug/src/w1/fi/wpadebug/WpaCredEditActivity.java
create mode 100644 wpadebug/src/w1/fi/wpadebug/WpaNfcActivity.java
create mode 100644 wpadebug/src/w1/fi/wpadebug/WpaWebViewActivity.java
create mode 100644 wpaspy/Makefile
create mode 100644 wpaspy/setup.py
create mode 100755 wpaspy/test.py
create mode 100644 wpaspy/wpaspy.c
create mode 100644 wpaspy/wpaspy.py
diff --git a/.gitignore b/.gitignore
new file mode 100644
index 000000000000..b064303ced30
--- /dev/null
+++ b/.gitignore
@@ -0,0 +1,8 @@
+*.pyc
+*~
+tests/hwsim/logs
+tests/remote/logs
+wpaspy/build
+**/parallel-vm.log
+tags
+build/
diff --git a/Android.mk b/Android.mk
new file mode 100644
index 000000000000..bd7a4097444b
--- /dev/null
+++ b/Android.mk
@@ -0,0 +1,10 @@
+LOCAL_PATH:= $(call my-dir)
+
+ifneq ($(filter VER_0_8_X VER_2_1_DEVEL,$(WPA_SUPPLICANT_VERSION)),)
+# The order of the 2 Android.mks does matter!
+# TODO: Clean up the Android.mks, reset all the temporary variables at the
+# end of each Android.mk, so that one Android.mk doesn't depend on variables
+# set up in the other Android.mk.
+include $(LOCAL_PATH)/hostapd/Android.mk \
+ $(LOCAL_PATH)/wpa_supplicant/Android.mk
+endif
diff --git a/CONTRIBUTIONS b/CONTRIBUTIONS
index c81ad640995a..1b4caf7ac811 100644
--- a/CONTRIBUTIONS
+++ b/CONTRIBUTIONS
@@ -56,6 +56,9 @@ In general, the best way of generating a suitable formatted patch file
is by committing the changes to a cloned git repository and using git
format-patch. The patch can then be sent, e.g., with git send-email.
+A list of pending patches waiting for review is available in
+Patchwork: https://patchwork.ozlabs.org/project/hostap/list/
+
History of license and contributions terms
------------------------------------------
@@ -140,7 +143,7 @@ The license terms used for hostap.git files
Modified BSD license (no advertisement clause):
-Copyright (c) 2002-2019, Jouni Malinen and contributors
+Copyright (c) 2002-2021, Jouni Malinen and contributors
All Rights Reserved.
Redistribution and use in source and binary forms, with or without
diff --git a/build_release b/build_release
new file mode 100755
index 000000000000..3aa9bf31963a
--- /dev/null
+++ b/build_release
@@ -0,0 +1,47 @@
+#!/bin/sh
+
+set -e
+
+if [ -z "$1" ]; then
+ echo "build_release "
+ exit 1
+fi
+
+TMP=tmp.build_release
+RELDIR=`pwd`/Release
+VER=$1
+NOW=`date +%Y-%m-%d`
+
+echo "Version: $VER - $NOW"
+
+DATEw=`head -n 3 wpa_supplicant/ChangeLog | tail -n 1 | sed "s/ .*//"`
+DATEh=`head -n 3 hostapd/ChangeLog | tail -n 1 | sed "s/ .*//"`
+
+if [ "$DATEw" != "$NOW" -o "$DATEh" != "$NOW" ]; then
+ echo "NOTE! Date mismatch in ChangeLog: wpa_supplicant $DATEw hostapd $DATEh != $NOW"
+fi
+
+if [ -r $TMP ]; then
+ echo "Temporary directory '$TMP' exists. Remove it before running this."
+ exit 1
+fi
+
+mkdir $TMP
+mkdir -p $RELDIR
+
+git archive --format=tar --prefix=wpa-$VER/ HEAD \
+ README COPYING CONTRIBUTIONS src wpa_supplicant hostapd hs20 |
+ gzip > $RELDIR/wpa-$VER.tar.gz
+git archive --format=tar --prefix=hostapd-$VER/ HEAD \
+ README COPYING CONTRIBUTIONS src hostapd |
+ gzip > $RELDIR/hostapd-$VER.tar.gz
+git archive --format=tar --prefix=wpa_supplicant-$VER/ HEAD \
+ README COPYING CONTRIBUTIONS src wpa_supplicant hs20/client |
+ tar --directory=$TMP -xf -
+
+cd $TMP
+make -C wpa_supplicant-$VER/wpa_supplicant/doc/docbook man
+rm -f wpa_supplicant-$VER/wpa_supplicant/doc/docbook/manpage.{links,refs}
+tar czf $RELDIR/wpa_supplicant-$VER.tar.gz wpa_supplicant-$VER
+cd ..
+rm -r $TMP
diff --git a/doc/.gitignore b/doc/.gitignore
new file mode 100644
index 000000000000..28c3fe4e99c3
--- /dev/null
+++ b/doc/.gitignore
@@ -0,0 +1,14 @@
+doxygen.warnings
+hostapd.eps
+hostapd.png
+html
+latex
+p2p_arch.eps
+p2p_arch.png
+p2p_arch2.eps
+p2p_arch2.png
+p2p_sm.eps
+p2p_sm.png
+wpa_supplicant.eps
+wpa_supplicant.png
+wpa_supplicant-devel.pdf
diff --git a/doc/Makefile b/doc/Makefile
new file mode 100644
index 000000000000..62af04a74f1f
--- /dev/null
+++ b/doc/Makefile
@@ -0,0 +1,42 @@
+all: docs
+
+%.eps: %.fig
+ fig2dev -L eps $*.fig $*.eps
+
+%.png: %.fig
+ fig2dev -L png -m 3 $*.fig | pngtopnm | pnmscale 0.4 | pnmtopng \
+ > $*.png
+
+%.png: %.dot
+ dot $*.dot -Tpng -o $*.png
+
+%.eps: %.dot
+ dot $*.dot -Tps -o $*.eps
+
+_wpa_supplicant.png: wpa_supplicant.png
+ cp $< $@
+
+_wpa_supplicant.eps: wpa_supplicant.eps
+ cp $< $@
+
+docs-pics: wpa_supplicant.png wpa_supplicant.eps hostapd.png hostapd.eps p2p_sm.png p2p_sm.eps p2p_arch.png p2p_arch.eps p2p_arch2.png p2p_arch2.eps _wpa_supplicant.png _wpa_supplicant.eps
+
+docs: docs-pics
+ (cd ..; doxygen doc/doxygen.conf; cd doc)
+ $(MAKE) -C latex
+ cp latex/refman.pdf wpa_supplicant-devel.pdf
+
+html: docs-pics
+ (cd ..; doxygen doc/doxygen.conf; cd doc)
+
+clean:
+ rm -f *~
+ rm -f wpa_supplicant.eps wpa_supplicant.png
+ rm -f _wpa_supplicant.png _wpa_supplicant.eps
+ rm -f hostapd.eps hostapd.png
+ rm -f p2p_sm.eps p2p_sm.png
+ rm -f p2p_arch.eps p2p_arch.png
+ rm -f p2p_arch2.eps p2p_arch2.png
+ rm -f doxygen.warnings
+ rm -rf html latex
+ rm -f wpa_supplicant-devel.pdf
diff --git a/doc/code_structure.doxygen b/doc/code_structure.doxygen
new file mode 100644
index 000000000000..454f179753d3
--- /dev/null
+++ b/doc/code_structure.doxygen
@@ -0,0 +1,315 @@
+/**
+\page code_structure Structure of the source code
+
+[ \ref _wpa_supplicant_core "wpa_supplicant core functionality" |
+\ref generic_helper_func "Generic helper functions" |
+\ref crypto_func "Cryptographic functions" |
+\ref tls_func "TLS library" |
+\ref configuration "Configuration" |
+\ref ctrl_iface "Control interface" |
+\ref wpa_code "WPA supplicant" |
+\ref eap_peer "EAP peer" |
+\ref eapol_supp "EAPOL supplicant" |
+\ref win_port "Windows port" |
+\ref test_programs "Test programs" ]
+
+wpa_supplicant implementation is divided into number of independent
+modules. Core code includes functionality for controlling the network
+selection, association, and configuration. Independent modules include
+WPA code (key handshake, PMKSA caching, pre-authentication), EAPOL
+state machine, and EAP state machine and methods. In addition, there
+are number of separate files for generic helper functions.
+
+Both WPA and EAPOL/EAP state machines can be used separately in other
+programs than wpa_supplicant. As an example, the included test
+programs eapol_test and preauth_test are using these modules.
+
+\ref driver_wrapper "Driver interface API" is defined in \ref driver.h and
+all hardware/driver dependent functionality is implemented in
+driver_*.c.
+
+
+\section _wpa_supplicant_core wpa_supplicant core functionality
+
+\ref wpa_supplicant.c
+ Program initialization, main control loop
+
+\ref wpa_supplicant/main.c
+ main() for UNIX-like operating systems and MinGW (Windows); this
+ uses command line arguments to configure wpa_supplicant
+
+\ref events.c
+ Driver event processing; \ref wpa_supplicant_event() and related functions
+
+\ref wpa_supplicant_i.h
+ Internal definitions for wpa_supplicant core; should not be
+ included into independent modules
+
+
+\section generic_helper_func Generic helper functions
+
+wpa_supplicant uses generic helper functions some of which are shared
+with with hostapd. The following C files are currently used:
+
+\ref eloop.c and \ref eloop.h
+ Event loop (select() loop with registerable timeouts, socket read
+ callbacks, and signal callbacks)
+
+\ref common.c and \ref common.h
+ Common helper functions
+
+\ref defs.h
+ Definitions shared by multiple files
+
+\ref l2_packet.h, \ref l2_packet_linux.c, and \ref l2_packet_pcap.c
+ Layer 2 (link) access wrapper (includes native Linux implementation
+ and wrappers for libdnet/libpcap). A new l2_packet implementation
+ may need to be added when porting to new operating systems that are
+ not supported by libdnet/libpcap. Makefile can be used to select which
+ l2_packet implementation is included. \ref l2_packet_linux.c uses Linux
+ packet sockets and \ref l2_packet_pcap.c has a more portable version using
+ libpcap and libdnet.
+
+\ref pcsc_funcs.c and \ref pcsc_funcs.h
+ Wrapper for PC/SC lite SIM and smart card readers
+
+\ref priv_netlink.h
+ Private version of netlink definitions from Linux kernel header files;
+ this could be replaced with C library header file once suitable
+ version becomes commonly available
+
+\ref version.h
+ Version number definitions
+
+
+\section crypto_func Cryptographic functions
+
+\ref md5.c and \ref md5.h
+ MD5 (replaced with a crypto library if TLS support is included)
+ HMAC-MD5 (keyed checksum for message authenticity validation)
+
+\ref rc4.c and \ref rc4.h
+ RC4 (broadcast/default key encryption)
+
+\ref sha1.c and \ref sha1.h
+ SHA-1 (replaced with a crypto library if TLS support is included)
+ HMAC-SHA-1 (keyed checksum for message authenticity validation)
+ PRF-SHA-1 (pseudorandom (key/nonce generation) function)
+ PBKDF2-SHA-1 (ASCII passphrase to shared secret)
+ T-PRF (for EAP-FAST)
+ TLS-PRF (RFC 2246)
+
+\ref sha256.c and \ref sha256.h
+ SHA-256 (replaced with a crypto library if TLS support is included)
+
+\ref aes-wrap.c, \ref aes_wrap.h, \ref aes.c
+ AES (replaced with a crypto library if TLS support is included),
+ AES Key Wrap Algorithm with 128-bit KEK, RFC3394 (broadcast/default
+ key encryption),
+ One-Key CBC MAC (OMAC1) hash with AES-128,
+ AES-128 CTR mode encryption,
+ AES-128 EAX mode encryption/decryption,
+ AES-128 CBC
+
+\ref crypto.h
+ Definition of crypto library wrapper
+
+\ref crypto_openssl.c
+ Wrapper functions for libcrypto (OpenSSL)
+
+\ref crypto_internal.c
+ Wrapper functions for internal crypto implementation
+
+\ref crypto_gnutls.c
+ Wrapper functions for libgcrypt (used by GnuTLS)
+
+\ref ms_funcs.c and \ref ms_funcs.h
+ Helper functions for MSCHAPV2 and LEAP
+
+\ref tls.h
+ Definition of TLS library wrapper
+
+\ref tls_none.c
+ Dummy implementation of TLS library wrapper for cases where TLS
+ functionality is not included.
+
+\ref tls_openssl.c
+ TLS library wrapper for openssl
+
+\ref tls_internal.c
+ TLS library for internal TLS implementation
+
+\ref tls_gnutls.c
+ TLS library wrapper for GnuTLS
+
+
+\section tls_func TLS library
+
+\ref asn1.c and \ref asn1.h
+ ASN.1 DER parsing
+
+\ref bignum.c and \ref bignum.h
+ Big number math
+
+\ref rsa.c and \ref rsa.h
+ RSA
+
+\ref x509v3.c and \ref x509v3.h
+ X.509v3 certificate parsing and processing
+
+\ref tlsv1_client.c, \ref tlsv1_client.h
+ TLSv1 client (RFC 2246)
+
+\ref tlsv1_client_i.h
+ Internal structures for TLSv1 client
+
+\ref tlsv1_client_read.c
+ TLSv1 client: read handshake messages
+
+\ref tlsv1_client_write.c
+ TLSv1 client: write handshake messages
+
+\ref tlsv1_common.c and \ref tlsv1_common.h
+ Common TLSv1 routines and definitions
+
+\ref tlsv1_cred.c and \ref tlsv1_cred.h
+ TLSv1 credentials
+
+\ref tlsv1_record.c and \ref tlsv1_record.h
+ TLSv1 record protocol
+
+
+\section configuration Configuration
+
+\ref config_ssid.h
+ Definition of per network configuration items
+
+\ref config.h
+ Definition of the wpa_supplicant configuration
+
+\ref config.c
+ Configuration parser and common functions
+
+\ref wpa_supplicant/config_file.c
+ Configuration backend for text files (e.g., wpa_supplicant.conf)
+
+\ref config_winreg.c
+ Configuration backend for Windows registry
+
+
+\section ctrl_iface Control interface
+
+wpa_supplicant has a \ref ctrl_iface_page "control interface"
+that can be used to get status
+information and manage operations from external programs. An example
+command line interface (wpa_cli) and GUI (wpa_gui) for this interface
+are included in the wpa_supplicant distribution.
+
+\ref wpa_supplicant/ctrl_iface.c and \ref wpa_supplicant/ctrl_iface.h
+ wpa_supplicant-side of the control interface
+
+\ref ctrl_iface_unix.c
+ UNIX domain sockets -based control interface backend
+
+\ref ctrl_iface_udp.c
+ UDP sockets -based control interface backend
+
+\ref ctrl_iface_named_pipe.c
+ Windows named pipes -based control interface backend
+
+\ref wpa_ctrl.c and \ref wpa_ctrl.h
+ Library functions for external programs to provide access to the
+ wpa_supplicant control interface
+
+\ref wpa_cli.c
+ Example program for using wpa_supplicant control interface
+
+
+\section wpa_code WPA supplicant
+
+\ref wpa.c and \ref wpa.h
+ WPA state machine and 4-Way/Group Key Handshake processing
+
+\ref preauth.c and \ref preauth.h
+ PMKSA caching and pre-authentication (RSN/WPA2)
+
+\ref wpa_i.h
+ Internal definitions for WPA code; not to be included to other modules.
+
+\section eap_peer EAP peer
+
+\ref eap_peer_module "EAP peer implementation" is a separate module that
+can be used by other programs than just wpa_supplicant.
+
+\ref eap.c and \ref eap.h
+ EAP state machine and method interface
+
+\ref eap_defs.h
+ Common EAP definitions
+
+\ref eap_i.h
+ Internal definitions for EAP state machine and EAP methods; not to be
+ included in other modules
+
+\ref eap_sim_common.c and \ref eap_sim_common.h
+ Common code for EAP-SIM and EAP-AKA
+
+\ref eap_tls_common.c and \ref eap_tls_common.h
+ Common code for EAP-PEAP, EAP-TTLS, and EAP-FAST
+
+\ref eap_ttls.c and \ref eap_ttls.h
+ EAP-TTLS
+
+\ref eap_pax.c, \ref eap_pax_common.h, \ref eap_pax_common.c
+ EAP-PAX
+
+\ref eap_psk.c, \ref eap_psk_common.h, \ref eap_psk_common.c
+ EAP-PSK (note: this is not needed for WPA-PSK)
+
+\ref eap_sake.c, \ref eap_sake_common.h, \ref eap_sake_common.c
+ EAP-SAKE
+
+\ref eap_gpsk.c, \ref eap_gpsk_common.h, \ref eap_gpsk_common.c
+ EAP-GPSK
+
+\ref eap_aka.c, \ref eap_fast.c, \ref eap_gtc.c, \ref eap_leap.c,
+\ref eap_md5.c, \ref eap_mschapv2.c, \ref eap_otp.c, \ref eap_peap.c,
+\ref eap_sim.c, \ref eap_tls.c
+ Other EAP method implementations
+
+
+\section eapol_supp EAPOL supplicant
+
+\ref eapol_supp_sm.c and \ref eapol_supp_sm.h
+ EAPOL supplicant state machine and IEEE 802.1X processing
+
+
+\section win_port Windows port
+
+\ref ndis_events.c
+ Code for receiving NdisMIndicateStatus() events and delivering them to
+ wpa_supplicant \ref driver_ndis.c in more easier to use form
+
+\ref win_if_list.c
+ External program for listing current network interface
+
+
+\section test_programs Test programs
+
+\ref radius_client.c and \ref radius_client.h
+ RADIUS authentication client implementation for eapol_test
+
+\ref radius.c and \ref radius.h
+ RADIUS message processing for eapol_test
+
+\ref eapol_test.c
+ Standalone EAP testing tool with integrated RADIUS authentication
+ client
+
+\ref preauth_test.c
+ Standalone RSN pre-authentication tool
+
+\ref wpa_passphrase.c
+ WPA ASCII passphrase to PSK conversion
+
+*/
diff --git a/doc/ctrl_iface.doxygen b/doc/ctrl_iface.doxygen
new file mode 100644
index 000000000000..7dccdc797ef3
--- /dev/null
+++ b/doc/ctrl_iface.doxygen
@@ -0,0 +1,1054 @@
+/**
+\page ctrl_iface_page wpa_supplicant control interface
+
+wpa_supplicant implements a control interface that can be used by
+external programs to control the operations of the wpa_supplicant
+daemon and to get status information and event notifications. There is
+a small C library, in a form of a single C file, \ref wpa_ctrl.c, that
+provides helper functions to facilitate the use of the control
+interface. External programs can link this file into them and then use
+the library functions documented in \ref wpa_ctrl.h to interact with
+wpa_supplicant. This library can also be used with C++. \ref wpa_cli.c and
+wpa_gui are example programs using this library.
+
+There are multiple mechanisms for inter-process communication. For
+example, Linux version of wpa_supplicant is using UNIX domain sockets
+for the control interface and Windows version UDP sockets. The use of
+the functions defined in \ref wpa_ctrl.h can be used to hide the details of
+the used IPC from external programs.
+
+
+\section using_ctrl_iface Using the control interface
+
+External programs, e.g., a GUI or a configuration utility, that need to
+communicate with wpa_supplicant should link in \ref wpa_ctrl.c. This
+allows them to use helper functions to open connection to the control
+interface with \ref wpa_ctrl_open() and to send commands with
+\ref wpa_ctrl_request().
+
+wpa_supplicant uses the control interface for two types of communication:
+commands and unsolicited event messages. Commands are a pair of
+messages, a request from the external program and a response from
+wpa_supplicant. These can be executed using \ref wpa_ctrl_request().
+Unsolicited event messages are sent by wpa_supplicant to the control
+interface connection without specific request from the external program
+for receiving each message. However, the external program needs to
+attach to the control interface with \ref wpa_ctrl_attach() to receive these
+unsolicited messages.
+
+If the control interface connection is used both for commands and
+unsolicited event messages, there is potential for receiving an
+unsolicited message between the command request and response.
+\ref wpa_ctrl_request() caller will need to supply a callback, msg_cb,
+for processing these messages. Often it is easier to open two
+control interface connections by calling \ref wpa_ctrl_open() twice and
+then use one of the connections for commands and the other one for
+unsolicited messages. This way command request/response pairs will
+not be broken by unsolicited messages. wpa_cli is an example of how
+to use only one connection for both purposes and wpa_gui demonstrates
+how to use two separate connections.
+
+Once the control interface connection is not needed anymore, it should
+be closed by calling \ref wpa_ctrl_close(). If the connection was used for
+unsolicited event messages, it should be first detached by calling
+\ref wpa_ctrl_detach().
+
+
+\section ctrl_iface_cmds Control interface commands
+
+Following commands can be used with \ref wpa_ctrl_request():
+
+\subsection ctrl_iface_PING PING
+
+This command can be used to test whether wpa_supplicant is replying
+to the control interface commands. The expected reply is \c PONG if the
+connection is open and wpa_supplicant is processing commands.
+
+
+\subsection ctrl_iface_MIB MIB
+
+Request a list of MIB variables (dot1x, dot11). The output is a text
+block with each line in \c variable=value format. For example:
+
+\verbatim
+dot11RSNAOptionImplemented=TRUE
+dot11RSNAPreauthenticationImplemented=TRUE
+dot11RSNAEnabled=FALSE
+dot11RSNAPreauthenticationEnabled=FALSE
+dot11RSNAConfigVersion=1
+dot11RSNAConfigPairwiseKeysSupported=5
+dot11RSNAConfigGroupCipherSize=128
+dot11RSNAConfigPMKLifetime=43200
+dot11RSNAConfigPMKReauthThreshold=70
+dot11RSNAConfigNumberOfPTKSAReplayCounters=1
+dot11RSNAConfigSATimeout=60
+dot11RSNAAuthenticationSuiteSelected=00-50-f2-2
+dot11RSNAPairwiseCipherSelected=00-50-f2-4
+dot11RSNAGroupCipherSelected=00-50-f2-4
+dot11RSNAPMKIDUsed=
+dot11RSNAAuthenticationSuiteRequested=00-50-f2-2
+dot11RSNAPairwiseCipherRequested=00-50-f2-4
+dot11RSNAGroupCipherRequested=00-50-f2-4
+dot11RSNAConfigNumberOfGTKSAReplayCounters=0
+dot11RSNA4WayHandshakeFailures=0
+dot1xSuppPaeState=5
+dot1xSuppHeldPeriod=60
+dot1xSuppAuthPeriod=30
+dot1xSuppStartPeriod=30
+dot1xSuppMaxStart=3
+dot1xSuppSuppControlledPortStatus=Authorized
+dot1xSuppBackendPaeState=2
+dot1xSuppEapolFramesRx=0
+dot1xSuppEapolFramesTx=440
+dot1xSuppEapolStartFramesTx=2
+dot1xSuppEapolLogoffFramesTx=0
+dot1xSuppEapolRespFramesTx=0
+dot1xSuppEapolReqIdFramesRx=0
+dot1xSuppEapolReqFramesRx=0
+dot1xSuppInvalidEapolFramesRx=0
+dot1xSuppEapLengthErrorFramesRx=0
+dot1xSuppLastEapolFrameVersion=0
+dot1xSuppLastEapolFrameSource=00:00:00:00:00:00
+\endverbatim
+
+
+\subsection ctrl_iface_STATUS STATUS
+
+Request current WPA/EAPOL/EAP status information. The output is a text
+block with each line in \c variable=value format. For example:
+
+\verbatim
+bssid=02:00:01:02:03:04
+ssid=test network
+pairwise_cipher=CCMP
+group_cipher=CCMP
+key_mgmt=WPA-PSK
+wpa_state=COMPLETED
+ip_address=192.168.1.21
+Supplicant PAE state=AUTHENTICATED
+suppPortStatus=Authorized
+EAP state=SUCCESS
+\endverbatim
+
+
+\subsection ctrl_iface_STATUS-VERBOSE STATUS-VERBOSE
+
+Same as STATUS, but with more verbosity (i.e., more \c variable=value pairs).
+
+\verbatim
+bssid=02:00:01:02:03:04
+ssid=test network
+id=0
+pairwise_cipher=CCMP
+group_cipher=CCMP
+key_mgmt=WPA-PSK
+wpa_state=COMPLETED
+ip_address=192.168.1.21
+Supplicant PAE state=AUTHENTICATED
+suppPortStatus=Authorized
+heldPeriod=60
+authPeriod=30
+startPeriod=30
+maxStart=3
+portControl=Auto
+Supplicant Backend state=IDLE
+EAP state=SUCCESS
+reqMethod=0
+methodState=NONE
+decision=COND_SUCC
+ClientTimeout=60
+\endverbatim
+
+
+\subsection ctrl_iface_PMKSA PMKSA
+
+Show PMKSA cache
+
+\verbatim
+Index / AA / PMKID / expiration (in seconds) / opportunistic
+1 / 02:00:01:02:03:04 / 000102030405060708090a0b0c0d0e0f / 41362 / 0
+2 / 02:00:01:33:55:77 / 928389281928383b34afb34ba4212345 / 362 / 1
+\endverbatim
+
+
+\subsection ctrl_iface_SET SET
+
+Set variables:
+- EAPOL::heldPeriod
+- EAPOL::authPeriod
+- EAPOL::startPeriod
+- EAPOL::maxStart
+- dot11RSNAConfigPMKLifetime
+- dot11RSNAConfigPMKReauthThreshold
+- dot11RSNAConfigSATimeout
+
+Example command:
+\verbatim
+SET EAPOL::heldPeriod 45
+\endverbatim
+
+
+\subsection ctrl_iface_LOGON LOGON
+
+IEEE 802.1X EAPOL state machine logon.
+
+
+\subsection ctrl_iface_LOGOFF LOGOFF
+
+IEEE 802.1X EAPOL state machine logoff.
+
+
+\subsection ctrl_iface_REASSOCIATE REASSOCIATE
+
+Force reassociation.
+
+
+\subsection ctrl_iface_RECONNECT RECONNECT
+
+Connect if disconnected (i.e., like \c REASSOCIATE, but only connect
+if in disconnected state).
+
+
+\subsection ctrl_iface_PREAUTH PREAUTH
+
+Start pre-authentication with the given BSSID.
+
+
+\subsection ctrl_iface_ATTACH ATTACH
+
+Attach the connection as a monitor for unsolicited events. This can
+be done with \ref wpa_ctrl_attach().
+
+
+\subsection ctrl_iface_DETACH DETACH
+
+Detach the connection as a monitor for unsolicited events. This can
+be done with \ref wpa_ctrl_detach().
+
+
+\subsection ctrl_iface_LEVEL LEVEL
+
+Change debug level.
+
+
+\subsection ctrl_iface_RECONFIGURE RECONFIGURE
+
+Force wpa_supplicant to re-read its configuration data.
+
+
+\subsection ctrl_iface_TERMINATE TERMINATE
+
+Terminate wpa_supplicant process.
+
+
+\subsection ctrl_iface_BSSID BSSID
+
+Set preferred BSSID for a network. Network id can be received from the
+\c LIST_NETWORKS command output.
+
+
+\subsection ctrl_iface_LIST_NETWORKS LIST_NETWORKS
+
+List configured networks.
+
+\verbatim
+network id / ssid / bssid / flags
+0 example network any [CURRENT]
+\endverbatim
+
+(note: fields are separated with tabs)
+
+
+\subsection ctrl_iface_DISCONNECT DISCONNECT
+
+Disconnect and wait for \c REASSOCIATE or \c RECONNECT command before
+connecting.
+
+
+\subsection ctrl_iface_SCAN SCAN
+
+Request a new BSS scan.
+
+
+\subsection ctrl_iface_SCAN_RESULTS SCAN_RESULTS
+
+Get the latest scan results.
+
+\verbatim
+bssid / frequency / signal level / flags / ssid
+00:09:5b:95:e0:4e 2412 208 [WPA-PSK-CCMP] jkm private
+02:55:24:33:77:a3 2462 187 [WPA-PSK-TKIP] testing
+00:09:5b:95:e0:4f 2412 209 jkm guest
+\endverbatim
+
+(note: fields are separated with tabs)
+
+
+\subsection ctrl_iface_BSS BSS
+
+Get detailed per-BSS scan results. \c BSS command can be used to
+iterate through scan results one BSS at a time and to fetch all
+information from the found BSSes. This provides access to the same
+data that is available through \c SCAN_RESULTS but in a way that
+avoids problems with large number of scan results not fitting in the
+ctrl_iface messages.
+
+There are two options for selecting the BSS with the \c BSS command:
+"BSS " requests information for the BSS identified by the index
+(0 .. size-1) in the scan results table and "BSS " requests
+information for the given BSS (based on BSSID in 00:01:02:03:04:05
+format).
+
+BSS information is presented in following format. Please note that new
+fields may be added to this field=value data, so the ctrl_iface user
+should be prepared to ignore values it does not understand.
+
+\verbatim
+bssid=00:09:5b:95:e0:4e
+freq=2412
+beacon_int=0
+capabilities=0x0011
+qual=51
+noise=161
+level=212
+tsf=0000000000000000
+ie=000b6a6b6d2070726976617465010180dd180050f20101000050f20401000050f20401000050f2020000
+ssid=jkm private
+\endverbatim
+
+
+
+\subsection ctrl_iface_SELECT_NETWORK SELECT_NETWORK
+
+Select a network (disable others). Network id can be received from the
+\c LIST_NETWORKS command output.
+
+
+\subsection ctrl_iface_ENABLE_NETWORK ENABLE_NETWORK
+
+Enable a network. Network id can be received from the
+\c LIST_NETWORKS command output. Special network id \c all can be
+used to enable all network.
+
+
+\subsection ctrl_iface_DISABLE_NETWORK DISABLE_NETWORK
+
+Disable a network. Network id can be received from the
+\c LIST_NETWORKS command output. Special network id \c all can be
+used to disable all network.
+
+
+\subsection ctrl_iface_ADD_NETWORK ADD_NETWORK
+
+Add a new network. This command creates a new network with empty
+configuration. The new network is disabled and once it has been
+configured it can be enabled with \c ENABLE_NETWORK command. \c ADD_NETWORK
+returns the network id of the new network or FAIL on failure.
+
+
+\subsection ctrl_iface_REMOVE_NETWORK REMOVE_NETWORK
+
+Remove a network. Network id can be received from the
+\c LIST_NETWORKS command output. Special network id \c all can be
+used to remove all network.
+
+
+\subsection ctrl_iface_SET_NETWORK SET_NETWORK
+
+Set network variables. Network id can be received from the
+\c LIST_NETWORKS command output.
+
+This command uses the same variables and data formats as the
+configuration file. See example wpa_supplicant.conf for more details.
+
+- ssid (network name, SSID)
+- psk (WPA passphrase or pre-shared key)
+- key_mgmt (key management protocol)
+- identity (EAP identity)
+- password (EAP password)
+- ...
+
+
+\subsection ctrl_iface_GET_NETWORK GET_NETWORK
+
+Get network variables. Network id can be received from the
+\c LIST_NETWORKS command output.
+
+
+\subsection ctrl_iface_SAVE_CONFIG SAVE_CONFIG
+
+Save the current configuration.
+
+
+\subsection ctrl_iface_P2P_FIND P2P_FIND
+
+Start P2P device discovery. Optional parameter can be used to specify
+the duration for the discovery in seconds (e.g., "P2P_FIND 5"). If the
+duration is not specified, discovery will be started for indefinite
+time, i.e., until it is terminated by P2P_STOP_FIND or P2P_CONNECT (to
+start group formation with a discovered peer).
+
+The default search type is to first run a full scan of all channels
+and then continue scanning only social channels (1, 6, 11). This
+behavior can be changed by specifying a different search type: social
+(e.g., "P2P_FIND 5 type=social") will skip the initial full scan and
+only search social channels; progressive (e.g., "P2P_FIND
+type=progressive") starts with a full scan and then searches
+progressively through all channels one channel at the time with the
+social channel scans. Progressive device discovery can be used to find
+new groups (and groups that were not found during the initial scan,
+e.g., due to the GO being asleep) over time without adding
+considerable extra delay for every Search state round.
+
+
+\subsection ctrl_iface_P2P_STOP_FIND P2P_STOP_FIND
+
+Stop ongoing P2P device discovery or other operation (connect, listen
+mode).
+
+
+\subsection ctrl_iface_P2P_CONNECT P2P_CONNECT
+
+Start P2P group formation with a discovered P2P peer. This includes
+group owner negotiation, group interface setup, provisioning, and
+establishing data connection.
+
+P2P_CONNECT
+[label|display|keypad] [persistent] [join|auth] [go_intent=<0..15>]
+
+Start P2P group formation with a discovered P2P peer. This includes
+optional group owner negotiation, group interface setup, provisioning,
+and establishing data connection.
+
+The parameter specifies the WPS provisioning
+method. "pbc" string starts pushbutton method, "pin" string start PIN
+method using an automatically generated PIN (which will be returned as
+the command return code), PIN# means that a pre-selected PIN can be
+used (e.g., 12345670). [label|display|keypad] is used with PIN method
+to specify which PIN is used (label=PIN from local label,
+display=dynamically generated random PIN from local display,
+keypad=PIN entered from peer device label or display). "persistent"
+parameter can be used to request a persistent group to be formed.
+
+"join" indicates that this is a command to join an existing group as a
+client. It skips the GO Negotiation part.
+
+"auth" indicates that the WPS parameters are authorized for the peer
+device without actually starting GO Negotiation (i.e., the peer is
+expected to initiate GO Negotiation). This is mainly for testing
+purposes.
+
+The optional "go_intent" parameter can be used to override the default
+GO Intent value.
+
+
+\subsection ctrl_iface_P2P_LISTEN P2P_LISTEN
+
+Start Listen-only state. Optional parameter can be used to specify the
+duration for the Listen operation in seconds. This command may not
+be of that much use during normal operations and is mainly designed
+for testing. It can also be used to keep the device discoverable
+without having to maintain a group.
+
+
+\subsection ctrl_iface_P2P_GROUP_REMOVE P2P_GROUP_REMOVE
+
+Terminate a P2P group. If a new virtual network interface was used for
+the group, it will also be removed. The network interface name of the
+group interface is used as a parameter for this command.
+
+
+\subsection ctrl_iface_P2P_GROUP_ADD P2P_GROUP_ADD
+
+Set up a P2P group owner manually (i.e., without group owner
+negotiation with a specific peer). This is also known as autonomous
+GO. Optional persistent= can be used to specify restart of
+a persistent group.
+
+
+\subsection ctrl_iface_P2P_PROV_DISC P2P_PROV_DISC
+
+Send P2P provision discovery request to the specified peer. The
+parameters for this command are the P2P device address of the peer and
+the desired configuration method. For example, "P2P_PROV_DISC
+02:01:02:03:04:05 display" would request the peer to display a PIN for
+us and "P2P_PROV_DISC 02:01:02:03:04:05 keypad" would request the peer
+to enter a PIN that we display.
+
+
+\subsection ctrl_iface_P2P_GET_PASSPHRASE P2P_GET_PASSPHRASE
+
+Get the passphrase for a group (only available when acting as a GO).
+
+
+\subsection ctrl_iface_P2P_SERV_DISC_REQ P2P_SERV_DISC_REQ
+
+Schedule a P2P service discovery request. The parameters for this
+command are the device address of the peer device (or 00:00:00:00:00:00
+for wildcard query that is sent to every discovered P2P peer that
+supports service discovery) and P2P Service Query TLV(s) as hexdump.
+For example, "P2P_SERV_DISC_REQ 00:00:00:00:00:00 02000001" schedules
+a request for listing all supported service discovery protocols and
+requests this to be sent to all discovered peers. The pending requests
+are sent during device discovery (see \ref ctrl_iface_P2P_FIND).
+
+This command returns an identifier for the pending query (e.g.,
+"1f77628") that can be used to cancel the request. Directed requests
+will be automatically removed when the specified peer has replied to
+it.
+
+
+\subsection ctrl_iface_P2P_SERV_DISC_CANCEL_REQ P2P_SERV_DISC_CANCEL_REQ
+
+Cancel a pending P2P service discovery request. This command takes a
+single parameter: identifier for the pending query (the value returned
+by \ref ctrl_iface_P2P_SERV_DISC_REQ), e.g.,
+"P2P_SERV_DISC_CANCEL_REQ 1f77628".
+
+
+\subsection ctrl_iface_P2P_SERV_DISC_RESP P2P_SERV_DISC_RESP
+
+Reply to a service discovery query. This command takes following
+parameters: frequency in MHz, destination address, dialog token,
+response TLV(s). The first three parameters are copied from the
+request event. For example,
+"P2P_SERV_DISC_RESP 2437 02:40:61:c2:f3:b7 1 0300000101".
+
+
+\subsection ctrl_iface_P2P_SERVICE_UPDATE P2P_SERVICE_UPDATE
+
+Indicate that local services have changed. This is used to increment
+the P2P service indicator value so that peers know when previously
+cached information may have changed.
+
+
+\subsection ctrl_iface_P2P_SERV_DISC_EXTERNAL P2P_SERV_DISC_EXTERNAL
+
+Configure external processing of P2P service requests: 0 (default) =
+no external processing of requests (i.e., internal code will reject
+each request), 1 = external processing of requests (external program
+is responsible for replying to service discovery requests with
+\ref ctrl_iface_P2P_SERV_DISC_RESP).
+
+
+\subsection ctrl_iface_P2P_REJECT P2P_REJECT
+
+Reject connection attempt from a peer (specified with a device
+address). This is a mechanism to reject a pending GO Negotiation with
+a peer and request to automatically block any further connection or
+discovery of the peer.
+
+
+\subsection ctrl_iface_P2P_INVITE P2P_INVITE
+
+Invite a peer to join a group or to (re)start a persistent group.
+
+
+\subsection ctrl_iface_P2P_PEER P2P_PEER
+
+Fetch information about a discovered peer. This command takes in an
+argument specifying which peer to select: P2P Device Address of the
+peer, "FIRST" to indicate the first peer in the list, or "NEXT-" to indicate the entry following the specified peer
+(to allow for iterating through the list).
+
+
+\subsection ctrl_iface_P2P_EXT_LISTEN P2P_EXT_LISTEN
+
+Enable/disable extended listen timing. Without parameters, this
+command disables extended listen timing. When enabling the feature,
+two parameters are used: availability period and availability interval
+(both in milliseconds and with range of 1-65535).
+
+
+\section ctrl_iface_interactive Interactive requests
+
+If wpa_supplicant needs additional information during authentication
+(e.g., password), it will use a specific prefix, \c CTRL-REQ-
+(\a WPA_CTRL_REQ macro) in an unsolicited event message. An external
+program, e.g., a GUI, can provide such information by using
+\c CTRL-RSP- (\a WPA_CTRL_RSP macro) prefix in a command with matching
+field name.
+
+The following fields can be requested in this way from the user:
+- IDENTITY (EAP identity/user name)
+- PASSWORD (EAP password)
+- NEW_PASSWORD (New password if the server is requesting password change)
+- PIN (PIN code for accessing a SIM or smartcard)
+- OTP (one-time password; like password, but the value is used only once)
+- PASSPHRASE (passphrase for a private key file)
+
+\verbatim
+CTRL-REQ---
+CTRL-RSP---
+\endverbatim
+
+For example, request from wpa_supplicant:
+\verbatim
+CTRL-REQ-PASSWORD-1-Password needed for SSID test-network
+\endverbatim
+
+And a matching reply from the GUI:
+\verbatim
+CTRL-RSP-PASSWORD-1-secret
+\endverbatim
+
+
+\subsection ctrl_iface_GET_CAPABILITY GET_CAPABILITY
+EOF
+
+# Build local keys and certs
+cd ca
+# Display help options.
+./setup.sh -h
+
+# Remove old keys, fill in appropriate values, and generate your keys.
+# For instance:
+./clean.sh
+rm -fr rootCA"
+old_hostname=myserver.local
+./setup.sh -C "Hotspot 2.0 Trust Root CA - CT" \
+ -o $old_hostname-osu-client \
+ -O $old_hostname-oscp -p lanforge -S $old_hostname \
+ -V $old_hostname-osu-revoked \
+ -m local -u http://$old_hostname:8888/
+
+# Configure subscription policies
+mkdir -p /home/user/hs20-server/spp/policy
+cat > /home/user/hs20-server/spp/policy/default.xml <
+
+ 30
+ ClientInitiated
+ Unrestricted
+ https://policy-server.osu.example.com/hs20/spp.php
+
+
+EOF
+
+
+# Install Hotspot 2.0 SPP and OMA DM XML schema/DTD files
+
+# XML schema for SPP
+# Copy the latest XML schema into /home/user/hs20-server/spp/spp.xsd
+
+# OMA DM Device Description Framework DTD
+# Copy into /home/user/hs20-server/spp/dm_ddf-v1_2.dtd
+# http://www.openmobilealliance.org/tech/DTD/dm_ddf-v1_2.dtd
+
+
+# Configure RADIUS authentication service
+# Note: Change the URL to match the setup
+# Note: Install AAA server key/certificate and root CA in Key directory
+
+cat > /home/user/hs20-server/AS/as-sql.conf < /home/user/hs20-server/AS/as.radius_clients <
+ Options Indexes MultiViews FollowSymLinks
+ AllowOverride None
+ Require all granted
+ SSLOptions +StdEnvVars
+
+
+Update SSL configuration to use the OSU server certificate/key.
+They keys and certs are called 'server.key' and 'server.pem' from
+ca/setup.sh.
+
+To support subscription remediation using client certificates, set
+"SSLVerifyClient optional" and configure the trust root CA(s) for the
+client certificates with SSLCACertificateFile.
+
+Enable default-ssl site and restart Apache2:
+ sudo a2ensite default-ssl
+ sudo a2enmod ssl
+ sudo service apache2 restart
+
+
+Management UI
+-------------
+
+The sample PHP scripts include a management UI for testing
+purposes. That is available at https:///hs20/users.php
+
+
+AP configuration
+----------------
+
+APs can now be configured to use the OSU server as the RADIUS
+authentication server. In addition, the OSU Provider List ANQP element
+should be configured to use the SPP (SOAP+XML) option and with the
+following Server URL:
+https:///hs20/spp.php/signup?realm=example.com
diff --git a/hs20/server/hs20_spp_server.c b/hs20/server/hs20_spp_server.c
new file mode 100644
index 000000000000..347c40a73d6a
--- /dev/null
+++ b/hs20/server/hs20_spp_server.c
@@ -0,0 +1,207 @@
+/*
+ * Hotspot 2.0 SPP server - standalone version
+ * Copyright (c) 2012-2013, Qualcomm Atheros, Inc.
+ *
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
+ */
+
+#include "includes.h"
+#include
+#include
+
+#include "common.h"
+#include "common/version.h"
+#include "xml-utils.h"
+#include "spp_server.h"
+
+
+static void write_timestamp(FILE *f)
+{
+ time_t t;
+ struct tm *tm;
+
+ time(&t);
+ tm = localtime(&t);
+
+ fprintf(f, "%04u-%02u-%02u %02u:%02u:%02u ",
+ tm->tm_year + 1900, tm->tm_mon + 1, tm->tm_mday,
+ tm->tm_hour, tm->tm_min, tm->tm_sec);
+}
+
+
+void debug_print(struct hs20_svc *ctx, int print, const char *fmt, ...)
+{
+ va_list ap;
+
+ if (ctx->debug_log == NULL)
+ return;
+
+ write_timestamp(ctx->debug_log);
+ va_start(ap, fmt);
+ vfprintf(ctx->debug_log, fmt, ap);
+ va_end(ap);
+
+ fprintf(ctx->debug_log, "\n");
+}
+
+
+void debug_dump_node(struct hs20_svc *ctx, const char *title, xml_node_t *node)
+{
+ char *str;
+
+ if (ctx->debug_log == NULL)
+ return;
+ str = xml_node_to_str(ctx->xml, node);
+ if (str == NULL)
+ return;
+
+ write_timestamp(ctx->debug_log);
+ fprintf(ctx->debug_log, "%s: '%s'\n", title, str);
+ os_free(str);
+}
+
+
+static int process(struct hs20_svc *ctx)
+{
+ int dmacc = 0;
+ xml_node_t *soap, *spp, *resp;
+ char *user, *realm, *post, *str;
+
+ ctx->addr = getenv("HS20ADDR");
+ if (ctx->addr)
+ debug_print(ctx, 1, "Connection from %s", ctx->addr);
+ ctx->test = getenv("HS20TEST");
+ if (ctx->test)
+ debug_print(ctx, 1, "Requested test functionality: %s",
+ ctx->test);
+
+ user = getenv("HS20USER");
+ if (user && strlen(user) == 0)
+ user = NULL;
+ realm = getenv("HS20REALM");
+ if (realm == NULL) {
+ debug_print(ctx, 1, "HS20REALM not set");
+ return -1;
+ }
+ post = getenv("HS20POST");
+ if (post == NULL) {
+ debug_print(ctx, 1, "HS20POST not set");
+ return -1;
+ }
+
+ ctx->imsi = getenv("HS20IMSI");
+ if (ctx->imsi)
+ debug_print(ctx, 1, "IMSI %s", ctx->imsi);
+
+ ctx->eap_method = getenv("HS20EAPMETHOD");
+ if (ctx->eap_method)
+ debug_print(ctx, 1, "EAP method %s", ctx->eap_method);
+
+ ctx->id_hash = getenv("HS20IDHASH");
+ if (ctx->id_hash)
+ debug_print(ctx, 1, "ID-HASH %s", ctx->id_hash);
+
+ soap = xml_node_from_buf(ctx->xml, post);
+ if (soap == NULL) {
+ debug_print(ctx, 1, "Could not parse SOAP data");
+ return -1;
+ }
+ debug_dump_node(ctx, "Received SOAP message", soap);
+ spp = soap_get_body(ctx->xml, soap);
+ if (spp == NULL) {
+ debug_print(ctx, 1, "Could not get SPP message");
+ xml_node_free(ctx->xml, soap);
+ return -1;
+ }
+ debug_dump_node(ctx, "Received SPP message", spp);
+
+ resp = hs20_spp_server_process(ctx, spp, user, realm, dmacc);
+ xml_node_free(ctx->xml, soap);
+ if (resp == NULL && user == NULL) {
+ debug_print(ctx, 1, "Request HTTP authentication");
+ return 2; /* Request authentication */
+ }
+ if (resp == NULL) {
+ debug_print(ctx, 1, "No response");
+ return -1;
+ }
+
+ soap = soap_build_envelope(ctx->xml, resp);
+ if (soap == NULL) {
+ debug_print(ctx, 1, "SOAP envelope building failed");
+ return -1;
+ }
+ str = xml_node_to_str(ctx->xml, soap);
+ xml_node_free(ctx->xml, soap);
+ if (str == NULL) {
+ debug_print(ctx, 1, "Could not get node string");
+ return -1;
+ }
+ printf("%s", str);
+ free(str);
+
+ return 0;
+}
+
+
+static void usage(void)
+{
+ printf("usage:\n"
+ "hs20_spp_server -r [-f]\n");
+}
+
+
+int main(int argc, char *argv[])
+{
+ struct hs20_svc ctx;
+ int ret;
+
+ os_memset(&ctx, 0, sizeof(ctx));
+ for (;;) {
+ int c = getopt(argc, argv, "f:r:v");
+ if (c < 0)
+ break;
+ switch (c) {
+ case 'f':
+ if (ctx.debug_log)
+ break;
+ ctx.debug_log = fopen(optarg, "a");
+ if (ctx.debug_log == NULL) {
+ printf("Could not write to %s\n", optarg);
+ return -1;
+ }
+ break;
+ case 'r':
+ ctx.root_dir = optarg;
+ break;
+ case 'v':
+ printf("hs20_spp_server v%s\n", VERSION_STR);
+ return 0;
+ default:
+ usage();
+ return -1;
+ }
+ }
+ if (ctx.root_dir == NULL) {
+ usage();
+ return -1;
+ }
+ ctx.xml = xml_node_init_ctx(&ctx, NULL);
+ if (ctx.xml == NULL)
+ return -1;
+ if (hs20_spp_server_init(&ctx) < 0) {
+ xml_node_deinit_ctx(ctx.xml);
+ return -1;
+ }
+
+ ret = process(&ctx);
+ debug_print(&ctx, 1, "process() --> %d", ret);
+
+ xml_node_deinit_ctx(ctx.xml);
+ hs20_spp_server_deinit(&ctx);
+ if (ctx.debug_log)
+ fclose(ctx.debug_log);
+
+ return ret;
+}
diff --git a/hs20/server/spp_server.c b/hs20/server/spp_server.c
new file mode 100644
index 000000000000..a50e9074f7b4
--- /dev/null
+++ b/hs20/server/spp_server.c
@@ -0,0 +1,2933 @@
+/*
+ * Hotspot 2.0 SPP server
+ * Copyright (c) 2012-2013, Qualcomm Atheros, Inc.
+ *
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
+ */
+
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+
+#include "common.h"
+#include "base64.h"
+#include "md5_i.h"
+#include "xml-utils.h"
+#include "spp_server.h"
+
+
+#define SPP_NS_URI "http://www.wi-fi.org/specifications/hotspot2dot0/v1.0/spp"
+
+#define URN_OMA_DM_DEVINFO "urn:oma:mo:oma-dm-devinfo:1.0"
+#define URN_OMA_DM_DEVDETAIL "urn:oma:mo:oma-dm-devdetail:1.0"
+#define URN_OMA_DM_DMACC "urn:oma:mo:oma-dm-dmacc:1.0"
+#define URN_HS20_PPS "urn:wfa:mo:hotspot2dot0-perprovidersubscription:1.0"
+
+
+/* TODO: timeout to expire sessions */
+
+enum hs20_session_operation {
+ NO_OPERATION,
+ UPDATE_PASSWORD,
+ CONTINUE_SUBSCRIPTION_REMEDIATION,
+ CONTINUE_POLICY_UPDATE,
+ USER_REMEDIATION,
+ SUBSCRIPTION_REGISTRATION,
+ POLICY_REMEDIATION,
+ POLICY_UPDATE,
+ FREE_REMEDIATION,
+ CLEAR_REMEDIATION,
+ CERT_REENROLL,
+};
+
+
+static char * db_get_session_val(struct hs20_svc *ctx, const char *user,
+ const char *realm, const char *session_id,
+ const char *field);
+static char * db_get_osu_config_val(struct hs20_svc *ctx, const char *realm,
+ const char *field);
+static xml_node_t * build_policy(struct hs20_svc *ctx, const char *user,
+ const char *realm, int use_dmacc);
+static xml_node_t * spp_exec_get_certificate(struct hs20_svc *ctx,
+ const char *session_id,
+ const char *user,
+ const char *realm,
+ int add_est_user);
+
+
+static int db_add_session(struct hs20_svc *ctx,
+ const char *user, const char *realm,
+ const char *sessionid, const char *pw,
+ const char *redirect_uri,
+ enum hs20_session_operation operation,
+ const u8 *mac_addr)
+{
+ char *sql;
+ int ret = 0;
+ char addr[20];
+
+ if (mac_addr)
+ snprintf(addr, sizeof(addr), MACSTR, MAC2STR(mac_addr));
+ else
+ addr[0] = '\0';
+ sql = sqlite3_mprintf("INSERT INTO sessions(timestamp,id,user,realm,"
+ "operation,password,redirect_uri,mac_addr,test) "
+ "VALUES "
+ "(strftime('%%Y-%%m-%%d %%H:%%M:%%f','now'),"
+ "%Q,%Q,%Q,%d,%Q,%Q,%Q,%Q)",
+ sessionid, user ? user : "", realm ? realm : "",
+ operation, pw ? pw : "",
+ redirect_uri ? redirect_uri : "",
+ addr, ctx->test);
+ if (sql == NULL)
+ return -1;
+ debug_print(ctx, 1, "DB: %s", sql);
+ if (sqlite3_exec(ctx->db, sql, NULL, NULL, NULL) != SQLITE_OK) {
+ debug_print(ctx, 1, "Failed to add session entry into sqlite "
+ "database: %s", sqlite3_errmsg(ctx->db));
+ ret = -1;
+ }
+ sqlite3_free(sql);
+ return ret;
+}
+
+
+static void db_update_session_password(struct hs20_svc *ctx, const char *user,
+ const char *realm, const char *sessionid,
+ const char *pw)
+{
+ char *sql;
+
+ sql = sqlite3_mprintf("UPDATE sessions SET password=%Q WHERE id=%Q AND "
+ "user=%Q AND realm=%Q",
+ pw, sessionid, user, realm);
+ if (sql == NULL)
+ return;
+ debug_print(ctx, 1, "DB: %s", sql);
+ if (sqlite3_exec(ctx->db, sql, NULL, NULL, NULL) != SQLITE_OK) {
+ debug_print(ctx, 1, "Failed to update session password: %s",
+ sqlite3_errmsg(ctx->db));
+ }
+ sqlite3_free(sql);
+}
+
+
+static void db_update_session_machine_managed(struct hs20_svc *ctx,
+ const char *user,
+ const char *realm,
+ const char *sessionid,
+ const int pw_mm)
+{
+ char *sql;
+
+ sql = sqlite3_mprintf("UPDATE sessions SET machine_managed=%Q WHERE id=%Q AND user=%Q AND realm=%Q",
+ pw_mm ? "1" : "0", sessionid, user, realm);
+ if (sql == NULL)
+ return;
+ debug_print(ctx, 1, "DB: %s", sql);
+ if (sqlite3_exec(ctx->db, sql, NULL, NULL, NULL) != SQLITE_OK) {
+ debug_print(ctx, 1,
+ "Failed to update session machine_managed: %s",
+ sqlite3_errmsg(ctx->db));
+ }
+ sqlite3_free(sql);
+}
+
+
+static void db_add_session_pps(struct hs20_svc *ctx, const char *user,
+ const char *realm, const char *sessionid,
+ xml_node_t *node)
+{
+ char *str;
+ char *sql;
+
+ str = xml_node_to_str(ctx->xml, node);
+ if (str == NULL)
+ return;
+ sql = sqlite3_mprintf("UPDATE sessions SET pps=%Q WHERE id=%Q AND "
+ "user=%Q AND realm=%Q",
+ str, sessionid, user, realm);
+ free(str);
+ if (sql == NULL)
+ return;
+ debug_print(ctx, 1, "DB: %s", sql);
+ if (sqlite3_exec(ctx->db, sql, NULL, NULL, NULL) != SQLITE_OK) {
+ debug_print(ctx, 1, "Failed to add session pps: %s",
+ sqlite3_errmsg(ctx->db));
+ }
+ sqlite3_free(sql);
+}
+
+
+static void db_add_session_devinfo(struct hs20_svc *ctx, const char *sessionid,
+ xml_node_t *node)
+{
+ char *str;
+ char *sql;
+
+ str = xml_node_to_str(ctx->xml, node);
+ if (str == NULL)
+ return;
+ sql = sqlite3_mprintf("UPDATE sessions SET devinfo=%Q WHERE id=%Q",
+ str, sessionid);
+ free(str);
+ if (sql == NULL)
+ return;
+ debug_print(ctx, 1, "DB: %s", sql);
+ if (sqlite3_exec(ctx->db, sql, NULL, NULL, NULL) != SQLITE_OK) {
+ debug_print(ctx, 1, "Failed to add session devinfo: %s",
+ sqlite3_errmsg(ctx->db));
+ }
+ sqlite3_free(sql);
+}
+
+
+static void db_add_session_devdetail(struct hs20_svc *ctx,
+ const char *sessionid,
+ xml_node_t *node)
+{
+ char *str;
+ char *sql;
+
+ str = xml_node_to_str(ctx->xml, node);
+ if (str == NULL)
+ return;
+ sql = sqlite3_mprintf("UPDATE sessions SET devdetail=%Q WHERE id=%Q",
+ str, sessionid);
+ free(str);
+ if (sql == NULL)
+ return;
+ debug_print(ctx, 1, "DB: %s", sql);
+ if (sqlite3_exec(ctx->db, sql, NULL, NULL, NULL) != SQLITE_OK) {
+ debug_print(ctx, 1, "Failed to add session devdetail: %s",
+ sqlite3_errmsg(ctx->db));
+ }
+ sqlite3_free(sql);
+}
+
+
+static void db_add_session_dmacc(struct hs20_svc *ctx, const char *sessionid,
+ const char *username, const char *password)
+{
+ char *sql;
+
+ sql = sqlite3_mprintf("UPDATE sessions SET osu_user=%Q, osu_password=%Q WHERE id=%Q",
+ username, password, sessionid);
+ if (!sql)
+ return;
+ debug_print(ctx, 1, "DB: %s", sql);
+ if (sqlite3_exec(ctx->db, sql, NULL, NULL, NULL) != SQLITE_OK) {
+ debug_print(ctx, 1, "Failed to add session DMAcc: %s",
+ sqlite3_errmsg(ctx->db));
+ }
+ sqlite3_free(sql);
+}
+
+
+static void db_add_session_eap_method(struct hs20_svc *ctx,
+ const char *sessionid,
+ const char *method)
+{
+ char *sql;
+
+ sql = sqlite3_mprintf("UPDATE sessions SET eap_method=%Q WHERE id=%Q",
+ method, sessionid);
+ if (!sql)
+ return;
+ debug_print(ctx, 1, "DB: %s", sql);
+ if (sqlite3_exec(ctx->db, sql, NULL, NULL, NULL) != SQLITE_OK) {
+ debug_print(ctx, 1, "Failed to add session EAP method: %s",
+ sqlite3_errmsg(ctx->db));
+ }
+ sqlite3_free(sql);
+}
+
+
+static void db_add_session_id_hash(struct hs20_svc *ctx, const char *sessionid,
+ const char *id_hash)
+{
+ char *sql;
+
+ sql = sqlite3_mprintf("UPDATE sessions SET mobile_identifier_hash=%Q WHERE id=%Q",
+ id_hash, sessionid);
+ if (!sql)
+ return;
+ debug_print(ctx, 1, "DB: %s", sql);
+ if (sqlite3_exec(ctx->db, sql, NULL, NULL, NULL) != SQLITE_OK) {
+ debug_print(ctx, 1, "Failed to add session ID hash: %s",
+ sqlite3_errmsg(ctx->db));
+ }
+ sqlite3_free(sql);
+}
+
+
+static void db_remove_session(struct hs20_svc *ctx,
+ const char *user, const char *realm,
+ const char *sessionid)
+{
+ char *sql;
+
+ if (user == NULL || realm == NULL) {
+ sql = sqlite3_mprintf("DELETE FROM sessions WHERE "
+ "id=%Q", sessionid);
+ } else {
+ sql = sqlite3_mprintf("DELETE FROM sessions WHERE "
+ "user=%Q AND realm=%Q AND id=%Q",
+ user, realm, sessionid);
+ }
+ if (sql == NULL)
+ return;
+ debug_print(ctx, 1, "DB: %s", sql);
+ if (sqlite3_exec(ctx->db, sql, NULL, NULL, NULL) != SQLITE_OK) {
+ debug_print(ctx, 1, "Failed to delete session entry from "
+ "sqlite database: %s", sqlite3_errmsg(ctx->db));
+ }
+ sqlite3_free(sql);
+}
+
+
+static void hs20_eventlog(struct hs20_svc *ctx,
+ const char *user, const char *realm,
+ const char *sessionid, const char *notes,
+ const char *dump)
+{
+ char *sql;
+ char *user_buf = NULL, *realm_buf = NULL;
+
+ debug_print(ctx, 1, "eventlog: %s", notes);
+
+ if (user == NULL) {
+ user_buf = db_get_session_val(ctx, NULL, NULL, sessionid,
+ "user");
+ user = user_buf;
+ realm_buf = db_get_session_val(ctx, NULL, NULL, sessionid,
+ "realm");
+ realm = realm_buf;
+ }
+
+ sql = sqlite3_mprintf("INSERT INTO eventlog"
+ "(user,realm,sessionid,timestamp,notes,dump,addr)"
+ " VALUES (%Q,%Q,%Q,"
+ "strftime('%%Y-%%m-%%d %%H:%%M:%%f','now'),"
+ "%Q,%Q,%Q)",
+ user, realm, sessionid, notes,
+ dump ? dump : "", ctx->addr ? ctx->addr : "");
+ free(user_buf);
+ free(realm_buf);
+ if (sql == NULL)
+ return;
+ if (sqlite3_exec(ctx->db, sql, NULL, NULL, NULL) != SQLITE_OK) {
+ debug_print(ctx, 1, "Failed to add eventlog entry into sqlite "
+ "database: %s", sqlite3_errmsg(ctx->db));
+ }
+ sqlite3_free(sql);
+}
+
+
+static void hs20_eventlog_node(struct hs20_svc *ctx,
+ const char *user, const char *realm,
+ const char *sessionid, const char *notes,
+ xml_node_t *node)
+{
+ char *str;
+
+ if (node)
+ str = xml_node_to_str(ctx->xml, node);
+ else
+ str = NULL;
+ hs20_eventlog(ctx, user, realm, sessionid, notes, str);
+ free(str);
+}
+
+
+static void db_update_mo_str(struct hs20_svc *ctx, const char *user,
+ const char *realm, const char *name,
+ const char *str)
+{
+ char *sql;
+ if (user == NULL || realm == NULL || name == NULL)
+ return;
+ sql = sqlite3_mprintf("UPDATE users SET %s=%Q WHERE identity=%Q AND realm=%Q AND (phase2=1 OR methods='TLS')",
+ name, str, user, realm);
+ if (sql == NULL)
+ return;
+ debug_print(ctx, 1, "DB: %s", sql);
+ if (sqlite3_exec(ctx->db, sql, NULL, NULL, NULL) != SQLITE_OK) {
+ debug_print(ctx, 1, "Failed to update user MO entry in sqlite "
+ "database: %s", sqlite3_errmsg(ctx->db));
+ }
+ sqlite3_free(sql);
+}
+
+
+static void db_update_mo(struct hs20_svc *ctx, const char *user,
+ const char *realm, const char *name, xml_node_t *mo)
+{
+ char *str;
+
+ str = xml_node_to_str(ctx->xml, mo);
+ if (str == NULL)
+ return;
+
+ db_update_mo_str(ctx, user, realm, name, str);
+ free(str);
+}
+
+
+static void add_text_node(struct hs20_svc *ctx, xml_node_t *parent,
+ const char *name, const char *value)
+{
+ xml_node_create_text(ctx->xml, parent, NULL, name, value ? value : "");
+}
+
+
+static void add_text_node_conf(struct hs20_svc *ctx, const char *realm,
+ xml_node_t *parent, const char *name,
+ const char *field)
+{
+ char *val;
+ val = db_get_osu_config_val(ctx, realm, field);
+ xml_node_create_text(ctx->xml, parent, NULL, name, val ? val : "");
+ os_free(val);
+}
+
+
+static void add_text_node_conf_corrupt(struct hs20_svc *ctx, const char *realm,
+ xml_node_t *parent, const char *name,
+ const char *field)
+{
+ char *val;
+
+ val = db_get_osu_config_val(ctx, realm, field);
+ if (val) {
+ size_t len;
+
+ len = os_strlen(val);
+ if (len > 0) {
+ if (val[len - 1] == '0')
+ val[len - 1] = '1';
+ else
+ val[len - 1] = '0';
+ }
+ }
+ xml_node_create_text(ctx->xml, parent, NULL, name, val ? val : "");
+ os_free(val);
+}
+
+
+static int new_password(char *buf, int buflen)
+{
+ int i;
+
+ if (buflen < 1)
+ return -1;
+ buf[buflen - 1] = '\0';
+ if (os_get_random((unsigned char *) buf, buflen - 1) < 0)
+ return -1;
+
+ for (i = 0; i < buflen - 1; i++) {
+ unsigned char val = buf[i];
+ val %= 2 * 26 + 10;
+ if (val < 26)
+ buf[i] = 'a' + val;
+ else if (val < 2 * 26)
+ buf[i] = 'A' + val - 26;
+ else
+ buf[i] = '0' + val - 2 * 26;
+ }
+
+ return 0;
+}
+
+
+struct get_db_field_data {
+ const char *field;
+ char *value;
+};
+
+
+static int get_db_field(void *ctx, int argc, char *argv[], char *col[])
+{
+ struct get_db_field_data *data = ctx;
+ int i;
+
+ for (i = 0; i < argc; i++) {
+ if (os_strcmp(col[i], data->field) == 0 && argv[i]) {
+ os_free(data->value);
+ data->value = os_strdup(argv[i]);
+ break;
+ }
+ }
+
+ return 0;
+}
+
+
+static char * db_get_val(struct hs20_svc *ctx, const char *user,
+ const char *realm, const char *field, int dmacc)
+{
+ char *cmd;
+ struct get_db_field_data data;
+
+ cmd = sqlite3_mprintf("SELECT %s FROM users WHERE %s=%Q AND realm=%Q AND (phase2=1 OR methods='TLS')",
+ field, dmacc ? "osu_user" : "identity",
+ user, realm);
+ if (cmd == NULL)
+ return NULL;
+ memset(&data, 0, sizeof(data));
+ data.field = field;
+ if (sqlite3_exec(ctx->db, cmd, get_db_field, &data, NULL) != SQLITE_OK)
+ {
+ debug_print(ctx, 1, "Could not find user '%s'", user);
+ sqlite3_free(cmd);
+ return NULL;
+ }
+ sqlite3_free(cmd);
+
+ debug_print(ctx, 1, "DB: user='%s' realm='%s' field='%s' dmacc=%d --> "
+ "value='%s'", user, realm, field, dmacc, data.value);
+
+ return data.value;
+}
+
+
+static int db_update_val(struct hs20_svc *ctx, const char *user,
+ const char *realm, const char *field,
+ const char *val, int dmacc)
+{
+ char *cmd;
+ int ret;
+
+ cmd = sqlite3_mprintf("UPDATE users SET %s=%Q WHERE %s=%Q AND realm=%Q AND (phase2=1 OR methods='TLS')",
+ field, val, dmacc ? "osu_user" : "identity", user,
+ realm);
+ if (cmd == NULL)
+ return -1;
+ debug_print(ctx, 1, "DB: %s", cmd);
+ if (sqlite3_exec(ctx->db, cmd, NULL, NULL, NULL) != SQLITE_OK) {
+ debug_print(ctx, 1,
+ "Failed to update user in sqlite database: %s",
+ sqlite3_errmsg(ctx->db));
+ ret = -1;
+ } else {
+ debug_print(ctx, 1,
+ "DB: user='%s' realm='%s' field='%s' set to '%s'",
+ user, realm, field, val);
+ ret = 0;
+ }
+ sqlite3_free(cmd);
+
+ return ret;
+}
+
+
+static char * db_get_session_val(struct hs20_svc *ctx, const char *user,
+ const char *realm, const char *session_id,
+ const char *field)
+{
+ char *cmd;
+ struct get_db_field_data data;
+
+ if (user == NULL || realm == NULL) {
+ cmd = sqlite3_mprintf("SELECT %s FROM sessions WHERE "
+ "id=%Q", field, session_id);
+ } else {
+ cmd = sqlite3_mprintf("SELECT %s FROM sessions WHERE "
+ "user=%Q AND realm=%Q AND id=%Q",
+ field, user, realm, session_id);
+ }
+ if (cmd == NULL)
+ return NULL;
+ debug_print(ctx, 1, "DB: %s", cmd);
+ memset(&data, 0, sizeof(data));
+ data.field = field;
+ if (sqlite3_exec(ctx->db, cmd, get_db_field, &data, NULL) != SQLITE_OK)
+ {
+ debug_print(ctx, 1, "DB: Could not find session %s: %s",
+ session_id, sqlite3_errmsg(ctx->db));
+ sqlite3_free(cmd);
+ return NULL;
+ }
+ sqlite3_free(cmd);
+
+ debug_print(ctx, 1, "DB: return '%s'", data.value);
+ return data.value;
+}
+
+
+static int update_password(struct hs20_svc *ctx, const char *user,
+ const char *realm, const char *pw, int dmacc)
+{
+ char *cmd;
+
+ cmd = sqlite3_mprintf("UPDATE users SET password=%Q, "
+ "remediation='' "
+ "WHERE %s=%Q AND phase2=1",
+ pw, dmacc ? "osu_user" : "identity",
+ user);
+ if (cmd == NULL)
+ return -1;
+ debug_print(ctx, 1, "DB: %s", cmd);
+ if (sqlite3_exec(ctx->db, cmd, NULL, NULL, NULL) != SQLITE_OK) {
+ debug_print(ctx, 1, "Failed to update database for user '%s'",
+ user);
+ }
+ sqlite3_free(cmd);
+
+ return 0;
+}
+
+
+static int clear_remediation(struct hs20_svc *ctx, const char *user,
+ const char *realm, int dmacc)
+{
+ char *cmd;
+
+ cmd = sqlite3_mprintf("UPDATE users SET remediation='' WHERE %s=%Q",
+ dmacc ? "osu_user" : "identity",
+ user);
+ if (cmd == NULL)
+ return -1;
+ debug_print(ctx, 1, "DB: %s", cmd);
+ if (sqlite3_exec(ctx->db, cmd, NULL, NULL, NULL) != SQLITE_OK) {
+ debug_print(ctx, 1, "Failed to update database for user '%s'",
+ user);
+ }
+ sqlite3_free(cmd);
+
+ return 0;
+}
+
+
+static int add_eap_ttls(struct hs20_svc *ctx, xml_node_t *parent)
+{
+ xml_node_t *node;
+
+ node = xml_node_create(ctx->xml, parent, NULL, "EAPMethod");
+ if (node == NULL)
+ return -1;
+
+ add_text_node(ctx, node, "EAPType", "21");
+ add_text_node(ctx, node, "InnerMethod", "MS-CHAP-V2");
+
+ return 0;
+}
+
+
+static xml_node_t * build_username_password(struct hs20_svc *ctx,
+ xml_node_t *parent,
+ const char *user, const char *pw)
+{
+ xml_node_t *node;
+ char *b64;
+ size_t len;
+
+ node = xml_node_create(ctx->xml, parent, NULL, "UsernamePassword");
+ if (node == NULL)
+ return NULL;
+
+ add_text_node(ctx, node, "Username", user);
+
+ b64 = base64_encode(pw, strlen(pw), NULL);
+ if (b64 == NULL)
+ return NULL;
+ len = os_strlen(b64);
+ if (len > 0 && b64[len - 1] == '\n')
+ b64[len - 1] = '\0';
+ add_text_node(ctx, node, "Password", b64);
+ free(b64);
+
+ return node;
+}
+
+
+static int add_username_password(struct hs20_svc *ctx, xml_node_t *cred,
+ const char *user, const char *pw,
+ int machine_managed)
+{
+ xml_node_t *node;
+
+ node = build_username_password(ctx, cred, user, pw);
+ if (node == NULL)
+ return -1;
+
+ add_text_node(ctx, node, "MachineManaged",
+ machine_managed ? "TRUE" : "FALSE");
+ add_text_node(ctx, node, "SoftTokenApp", "");
+ add_eap_ttls(ctx, node);
+
+ return 0;
+}
+
+
+static void add_creation_date(struct hs20_svc *ctx, xml_node_t *cred)
+{
+ char str[30];
+ time_t now;
+ struct tm tm;
+
+ time(&now);
+ gmtime_r(&now, &tm);
+ snprintf(str, sizeof(str), "%04u-%02u-%02uT%02u:%02u:%02uZ",
+ tm.tm_year + 1900, tm.tm_mon + 1, tm.tm_mday,
+ tm.tm_hour, tm.tm_min, tm.tm_sec);
+ xml_node_create_text(ctx->xml, cred, NULL, "CreationDate", str);
+}
+
+
+static xml_node_t * build_credential_pw(struct hs20_svc *ctx,
+ const char *user, const char *realm,
+ const char *pw, int machine_managed)
+{
+ xml_node_t *cred;
+
+ cred = xml_node_create_root(ctx->xml, NULL, NULL, NULL, "Credential");
+ if (cred == NULL) {
+ debug_print(ctx, 1, "Failed to create Credential node");
+ return NULL;
+ }
+ add_creation_date(ctx, cred);
+ if (add_username_password(ctx, cred, user, pw, machine_managed) < 0) {
+ xml_node_free(ctx->xml, cred);
+ return NULL;
+ }
+ add_text_node(ctx, cred, "Realm", realm);
+
+ return cred;
+}
+
+
+static xml_node_t * build_credential(struct hs20_svc *ctx,
+ const char *user, const char *realm,
+ char *new_pw, size_t new_pw_len)
+{
+ if (new_password(new_pw, new_pw_len) < 0)
+ return NULL;
+ debug_print(ctx, 1, "Update password to '%s'", new_pw);
+ return build_credential_pw(ctx, user, realm, new_pw, 1);
+}
+
+
+static xml_node_t * build_credential_cert(struct hs20_svc *ctx,
+ const char *user, const char *realm,
+ const char *cert_fingerprint)
+{
+ xml_node_t *cred, *cert;
+
+ cred = xml_node_create_root(ctx->xml, NULL, NULL, NULL, "Credential");
+ if (cred == NULL) {
+ debug_print(ctx, 1, "Failed to create Credential node");
+ return NULL;
+ }
+ add_creation_date(ctx, cred);
+ cert = xml_node_create(ctx->xml, cred, NULL, "DigitalCertificate");
+ add_text_node(ctx, cert, "CertificateType", "x509v3");
+ add_text_node(ctx, cert, "CertSHA256Fingerprint", cert_fingerprint);
+ add_text_node(ctx, cred, "Realm", realm);
+
+ return cred;
+}
+
+
+static xml_node_t * build_post_dev_data_response(struct hs20_svc *ctx,
+ xml_namespace_t **ret_ns,
+ const char *session_id,
+ const char *status,
+ const char *error_code)
+{
+ xml_node_t *spp_node = NULL;
+ xml_namespace_t *ns;
+
+ spp_node = xml_node_create_root(ctx->xml, SPP_NS_URI, "spp", &ns,
+ "sppPostDevDataResponse");
+ if (spp_node == NULL)
+ return NULL;
+ if (ret_ns)
+ *ret_ns = ns;
+
+ xml_node_add_attr(ctx->xml, spp_node, ns, "sppVersion", "1.0");
+ xml_node_add_attr(ctx->xml, spp_node, ns, "sessionID", session_id);
+ xml_node_add_attr(ctx->xml, spp_node, ns, "sppStatus", status);
+
+ if (error_code) {
+ xml_node_t *node;
+ node = xml_node_create(ctx->xml, spp_node, ns, "sppError");
+ if (node)
+ xml_node_add_attr(ctx->xml, node, NULL, "errorCode",
+ error_code);
+ }
+
+ return spp_node;
+}
+
+
+static int add_update_node(struct hs20_svc *ctx, xml_node_t *spp_node,
+ xml_namespace_t *ns, const char *uri,
+ xml_node_t *upd_node)
+{
+ xml_node_t *node, *tnds;
+ char *str;
+
+ tnds = mo_to_tnds(ctx->xml, upd_node, 0, NULL, NULL);
+ if (!tnds)
+ return -1;
+
+ str = xml_node_to_str(ctx->xml, tnds);
+ xml_node_free(ctx->xml, tnds);
+ if (str == NULL)
+ return -1;
+ node = xml_node_create_text(ctx->xml, spp_node, ns, "updateNode", str);
+ free(str);
+
+ xml_node_add_attr(ctx->xml, node, ns, "managementTreeURI", uri);
+
+ return 0;
+}
+
+
+static xml_node_t * read_subrem_file(struct hs20_svc *ctx,
+ const char *subrem_id,
+ char *uri, size_t uri_size)
+{
+ char fname[200];
+ char *buf, *buf2, *pos;
+ size_t len;
+ xml_node_t *node;
+
+ os_snprintf(fname, sizeof(fname), "%s/spp/subrem/%s",
+ ctx->root_dir, subrem_id);
+ debug_print(ctx, 1, "Use subrem file %s", fname);
+
+ buf = os_readfile(fname, &len);
+ if (!buf)
+ return NULL;
+ buf2 = os_realloc(buf, len + 1);
+ if (!buf2) {
+ os_free(buf);
+ return NULL;
+ }
+ buf = buf2;
+ buf[len] = '\0';
+
+ pos = os_strchr(buf, '\n');
+ if (!pos) {
+ os_free(buf);
+ return NULL;
+ }
+ *pos++ = '\0';
+ os_strlcpy(uri, buf, uri_size);
+
+ node = xml_node_from_buf(ctx->xml, pos);
+ os_free(buf);
+
+ return node;
+}
+
+
+static xml_node_t * build_sub_rem_resp(struct hs20_svc *ctx,
+ const char *user, const char *realm,
+ const char *session_id,
+ int machine_rem, int dmacc)
+{
+ xml_namespace_t *ns;
+ xml_node_t *spp_node, *cred;
+ char buf[400];
+ char new_pw[33];
+ char *status;
+ char *cert;
+
+ cert = db_get_val(ctx, user, realm, "cert", dmacc);
+ if (cert && cert[0] == '\0') {
+ os_free(cert);
+ cert = NULL;
+ }
+ if (cert) {
+ char *subrem;
+
+ /* No change needed in PPS MO unless specifically asked to */
+ cred = NULL;
+ buf[0] = '\0';
+
+ subrem = db_get_val(ctx, user, realm, "subrem", dmacc);
+ if (subrem && subrem[0]) {
+ cred = read_subrem_file(ctx, subrem, buf, sizeof(buf));
+ if (!cred) {
+ debug_print(ctx, 1,
+ "Could not create updateNode from subrem file");
+ os_free(subrem);
+ os_free(cert);
+ return NULL;
+ }
+ }
+ os_free(subrem);
+ } else {
+ char *real_user = NULL;
+ char *pw;
+
+ if (dmacc) {
+ real_user = db_get_val(ctx, user, realm, "identity",
+ dmacc);
+ if (!real_user) {
+ debug_print(ctx, 1,
+ "Could not find user identity for dmacc user '%s'",
+ user);
+ return NULL;
+ }
+ }
+
+ pw = db_get_session_val(ctx, user, realm, session_id,
+ "password");
+ if (pw && pw[0]) {
+ debug_print(ctx, 1, "New password from the user: '%s'",
+ pw);
+ snprintf(new_pw, sizeof(new_pw), "%s", pw);
+ free(pw);
+ cred = build_credential_pw(ctx,
+ real_user ? real_user : user,
+ realm, new_pw, 0);
+ } else {
+ cred = build_credential(ctx,
+ real_user ? real_user : user,
+ realm, new_pw, sizeof(new_pw));
+ }
+
+ free(real_user);
+ if (!cred) {
+ debug_print(ctx, 1, "Could not build credential");
+ os_free(cert);
+ return NULL;
+ }
+
+ snprintf(buf, sizeof(buf),
+ "./Wi-Fi/%s/PerProviderSubscription/Cred01/Credential",
+ realm);
+ }
+
+ status = "Remediation complete, request sppUpdateResponse";
+ spp_node = build_post_dev_data_response(ctx, &ns, session_id, status,
+ NULL);
+ if (spp_node == NULL) {
+ debug_print(ctx, 1, "Could not build sppPostDevDataResponse");
+ os_free(cert);
+ return NULL;
+ }
+
+ if ((cred && add_update_node(ctx, spp_node, ns, buf, cred) < 0) ||
+ (!cred && !xml_node_create(ctx->xml, spp_node, ns, "noMOUpdate"))) {
+ debug_print(ctx, 1, "Could not add update node");
+ xml_node_free(ctx->xml, spp_node);
+ os_free(cert);
+ return NULL;
+ }
+
+ hs20_eventlog_node(ctx, user, realm, session_id,
+ machine_rem ? "machine remediation" :
+ "user remediation", cred);
+ xml_node_free(ctx->xml, cred);
+
+ if (cert) {
+ debug_print(ctx, 1, "Request DB remediation clearing on success notification (certificate credential)");
+ db_add_session(ctx, user, realm, session_id, NULL, NULL,
+ CLEAR_REMEDIATION, NULL);
+ } else {
+ debug_print(ctx, 1, "Request DB password update on success "
+ "notification");
+ db_add_session(ctx, user, realm, session_id, new_pw, NULL,
+ UPDATE_PASSWORD, NULL);
+ }
+ os_free(cert);
+
+ return spp_node;
+}
+
+
+static xml_node_t * machine_remediation(struct hs20_svc *ctx,
+ const char *user,
+ const char *realm,
+ const char *session_id, int dmacc)
+{
+ return build_sub_rem_resp(ctx, user, realm, session_id, 1, dmacc);
+}
+
+
+static xml_node_t * cert_reenroll(struct hs20_svc *ctx,
+ const char *user,
+ const char *realm,
+ const char *session_id)
+{
+ db_add_session(ctx, user, realm, session_id, NULL, NULL,
+ CERT_REENROLL, NULL);
+ return spp_exec_get_certificate(ctx, session_id, user, realm, 0);
+}
+
+
+static xml_node_t * policy_remediation(struct hs20_svc *ctx,
+ const char *user, const char *realm,
+ const char *session_id, int dmacc)
+{
+ xml_namespace_t *ns;
+ xml_node_t *spp_node, *policy;
+ char buf[400];
+ const char *status;
+
+ hs20_eventlog(ctx, user, realm, session_id,
+ "requires policy remediation", NULL);
+
+ db_add_session(ctx, user, realm, session_id, NULL, NULL,
+ POLICY_REMEDIATION, NULL);
+
+ policy = build_policy(ctx, user, realm, dmacc);
+ if (!policy) {
+ return build_post_dev_data_response(
+ ctx, NULL, session_id,
+ "No update available at this time", NULL);
+ }
+
+ status = "Remediation complete, request sppUpdateResponse";
+ spp_node = build_post_dev_data_response(ctx, &ns, session_id, status,
+ NULL);
+ if (spp_node == NULL)
+ return NULL;
+
+ snprintf(buf, sizeof(buf),
+ "./Wi-Fi/%s/PerProviderSubscription/Cred01/Policy",
+ realm);
+
+ if (add_update_node(ctx, spp_node, ns, buf, policy) < 0) {
+ xml_node_free(ctx->xml, spp_node);
+ xml_node_free(ctx->xml, policy);
+ return NULL;
+ }
+
+ hs20_eventlog_node(ctx, user, realm, session_id,
+ "policy update (sub rem)", policy);
+ xml_node_free(ctx->xml, policy);
+
+ return spp_node;
+}
+
+
+static xml_node_t * browser_remediation(struct hs20_svc *ctx,
+ const char *session_id,
+ const char *redirect_uri,
+ const char *uri)
+{
+ xml_namespace_t *ns;
+ xml_node_t *spp_node, *exec_node;
+
+ if (redirect_uri == NULL) {
+ debug_print(ctx, 1, "Missing redirectURI attribute for user "
+ "remediation");
+ return NULL;
+ }
+ debug_print(ctx, 1, "redirectURI %s", redirect_uri);
+
+ spp_node = build_post_dev_data_response(ctx, &ns, session_id, "OK",
+ NULL);
+ if (spp_node == NULL)
+ return NULL;
+
+ exec_node = xml_node_create(ctx->xml, spp_node, ns, "exec");
+ xml_node_create_text(ctx->xml, exec_node, ns, "launchBrowserToURI",
+ uri);
+ return spp_node;
+}
+
+
+static xml_node_t * user_remediation(struct hs20_svc *ctx, const char *user,
+ const char *realm, const char *session_id,
+ const char *redirect_uri)
+{
+ char uri[300], *val;
+
+ hs20_eventlog(ctx, user, realm, session_id,
+ "requires user remediation", NULL);
+ val = db_get_osu_config_val(ctx, realm, "remediation_url");
+ if (val == NULL)
+ return NULL;
+
+ db_add_session(ctx, user, realm, session_id, NULL, redirect_uri,
+ USER_REMEDIATION, NULL);
+
+ snprintf(uri, sizeof(uri), "%s%s", val, session_id);
+ os_free(val);
+ return browser_remediation(ctx, session_id, redirect_uri, uri);
+}
+
+
+static xml_node_t * free_remediation(struct hs20_svc *ctx,
+ const char *user, const char *realm,
+ const char *session_id,
+ const char *redirect_uri)
+{
+ char uri[300], *val;
+
+ hs20_eventlog(ctx, user, realm, session_id,
+ "requires free/public account remediation", NULL);
+ val = db_get_osu_config_val(ctx, realm, "free_remediation_url");
+ if (val == NULL)
+ return NULL;
+
+ db_add_session(ctx, user, realm, session_id, NULL, redirect_uri,
+ FREE_REMEDIATION, NULL);
+
+ snprintf(uri, sizeof(uri), "%s%s", val, session_id);
+ os_free(val);
+ return browser_remediation(ctx, session_id, redirect_uri, uri);
+}
+
+
+static xml_node_t * no_sub_rem(struct hs20_svc *ctx,
+ const char *user, const char *realm,
+ const char *session_id)
+{
+ const char *status;
+
+ hs20_eventlog(ctx, user, realm, session_id,
+ "no subscription mediation available", NULL);
+
+ status = "No update available at this time";
+ return build_post_dev_data_response(ctx, NULL, session_id, status,
+ NULL);
+}
+
+
+static xml_node_t * hs20_subscription_remediation(struct hs20_svc *ctx,
+ const char *user,
+ const char *realm,
+ const char *session_id,
+ int dmacc,
+ const char *redirect_uri)
+{
+ char *type, *identity;
+ xml_node_t *ret;
+ char *free_account;
+
+ identity = db_get_val(ctx, user, realm, "identity", dmacc);
+ if (identity == NULL || strlen(identity) == 0) {
+ hs20_eventlog(ctx, user, realm, session_id,
+ "user not found in database for remediation",
+ NULL);
+ os_free(identity);
+ return build_post_dev_data_response(ctx, NULL, session_id,
+ "Error occurred",
+ "Not found");
+ }
+ os_free(identity);
+
+ free_account = db_get_osu_config_val(ctx, realm, "free_account");
+ if (free_account && strcmp(free_account, user) == 0) {
+ free(free_account);
+ return no_sub_rem(ctx, user, realm, session_id);
+ }
+ free(free_account);
+
+ type = db_get_val(ctx, user, realm, "remediation", dmacc);
+ if (type && strcmp(type, "free") != 0) {
+ char *val;
+ int shared = 0;
+ val = db_get_val(ctx, user, realm, "shared", dmacc);
+ if (val)
+ shared = atoi(val);
+ free(val);
+ if (shared) {
+ free(type);
+ return no_sub_rem(ctx, user, realm, session_id);
+ }
+ }
+ if (type && strcmp(type, "user") == 0)
+ ret = user_remediation(ctx, user, realm, session_id,
+ redirect_uri);
+ else if (type && strcmp(type, "free") == 0)
+ ret = free_remediation(ctx, user, realm, session_id,
+ redirect_uri);
+ else if (type && strcmp(type, "policy") == 0)
+ ret = policy_remediation(ctx, user, realm, session_id, dmacc);
+ else if (type && strcmp(type, "machine") == 0)
+ ret = machine_remediation(ctx, user, realm, session_id, dmacc);
+ else if (type && strcmp(type, "reenroll") == 0)
+ ret = cert_reenroll(ctx, user, realm, session_id);
+ else
+ ret = no_sub_rem(ctx, user, realm, session_id);
+ free(type);
+
+ return ret;
+}
+
+
+static xml_node_t * read_policy_file(struct hs20_svc *ctx,
+ const char *policy_id)
+{
+ char fname[200];
+
+ snprintf(fname, sizeof(fname), "%s/spp/policy/%s.xml",
+ ctx->root_dir, policy_id);
+ debug_print(ctx, 1, "Use policy file %s", fname);
+
+ return node_from_file(ctx->xml, fname);
+}
+
+
+static void update_policy_update_uri(struct hs20_svc *ctx, const char *realm,
+ xml_node_t *policy)
+{
+ xml_node_t *node;
+ char *url;
+
+ node = get_node_uri(ctx->xml, policy, "Policy/PolicyUpdate/URI");
+ if (!node)
+ return;
+
+ url = db_get_osu_config_val(ctx, realm, "policy_url");
+ if (!url)
+ return;
+ xml_node_set_text(ctx->xml, node, url);
+ free(url);
+}
+
+
+static xml_node_t * build_policy(struct hs20_svc *ctx, const char *user,
+ const char *realm, int use_dmacc)
+{
+ char *policy_id;
+ xml_node_t *policy, *node;
+
+ policy_id = db_get_val(ctx, user, realm, "policy", use_dmacc);
+ if (policy_id == NULL || strlen(policy_id) == 0) {
+ free(policy_id);
+ policy_id = strdup("default");
+ if (policy_id == NULL)
+ return NULL;
+ }
+ policy = read_policy_file(ctx, policy_id);
+ free(policy_id);
+ if (policy == NULL)
+ return NULL;
+
+ update_policy_update_uri(ctx, realm, policy);
+
+ node = get_node_uri(ctx->xml, policy, "Policy/PolicyUpdate");
+ if (node && use_dmacc) {
+ char *pw;
+ pw = db_get_val(ctx, user, realm, "osu_password", use_dmacc);
+ if (pw == NULL ||
+ build_username_password(ctx, node, user, pw) == NULL) {
+ debug_print(ctx, 1, "Failed to add Policy/PolicyUpdate/"
+ "UsernamePassword");
+ free(pw);
+ xml_node_free(ctx->xml, policy);
+ return NULL;
+ }
+ free(pw);
+ }
+
+ return policy;
+}
+
+
+static xml_node_t * hs20_policy_update(struct hs20_svc *ctx,
+ const char *user, const char *realm,
+ const char *session_id, int dmacc)
+{
+ xml_namespace_t *ns;
+ xml_node_t *spp_node;
+ xml_node_t *policy;
+ char buf[400];
+ const char *status;
+ char *identity;
+
+ identity = db_get_val(ctx, user, realm, "identity", dmacc);
+ if (identity == NULL || strlen(identity) == 0) {
+ hs20_eventlog(ctx, user, realm, session_id,
+ "user not found in database for policy update",
+ NULL);
+ os_free(identity);
+ return build_post_dev_data_response(ctx, NULL, session_id,
+ "Error occurred",
+ "Not found");
+ }
+ os_free(identity);
+
+ policy = build_policy(ctx, user, realm, dmacc);
+ if (!policy) {
+ return build_post_dev_data_response(
+ ctx, NULL, session_id,
+ "No update available at this time", NULL);
+ }
+
+ db_add_session(ctx, user, realm, session_id, NULL, NULL, POLICY_UPDATE,
+ NULL);
+
+ status = "Update complete, request sppUpdateResponse";
+ spp_node = build_post_dev_data_response(ctx, &ns, session_id, status,
+ NULL);
+ if (spp_node == NULL)
+ return NULL;
+
+ snprintf(buf, sizeof(buf),
+ "./Wi-Fi/%s/PerProviderSubscription/Cred01/Policy",
+ realm);
+
+ if (add_update_node(ctx, spp_node, ns, buf, policy) < 0) {
+ xml_node_free(ctx->xml, spp_node);
+ xml_node_free(ctx->xml, policy);
+ return NULL;
+ }
+
+ hs20_eventlog_node(ctx, user, realm, session_id, "policy update",
+ policy);
+ xml_node_free(ctx->xml, policy);
+
+ return spp_node;
+}
+
+
+static xml_node_t * spp_get_mo(struct hs20_svc *ctx, xml_node_t *node,
+ const char *urn, int *valid, char **ret_err)
+{
+ xml_node_t *child, *tnds, *mo;
+ const char *name;
+ char *mo_urn;
+ char *str;
+ char fname[200];
+
+ *valid = -1;
+ if (ret_err)
+ *ret_err = NULL;
+
+ xml_node_for_each_child(ctx->xml, child, node) {
+ xml_node_for_each_check(ctx->xml, child);
+ name = xml_node_get_localname(ctx->xml, child);
+ if (strcmp(name, "moContainer") != 0)
+ continue;
+ mo_urn = xml_node_get_attr_value_ns(ctx->xml, child, SPP_NS_URI,
+ "moURN");
+ if (strcasecmp(urn, mo_urn) == 0) {
+ xml_node_get_attr_value_free(ctx->xml, mo_urn);
+ break;
+ }
+ xml_node_get_attr_value_free(ctx->xml, mo_urn);
+ }
+
+ if (child == NULL)
+ return NULL;
+
+ debug_print(ctx, 1, "moContainer text for %s", urn);
+ debug_dump_node(ctx, "moContainer", child);
+
+ str = xml_node_get_text(ctx->xml, child);
+ debug_print(ctx, 1, "moContainer payload: '%s'", str);
+ tnds = xml_node_from_buf(ctx->xml, str);
+ xml_node_get_text_free(ctx->xml, str);
+ if (tnds == NULL) {
+ debug_print(ctx, 1, "could not parse moContainer text");
+ return NULL;
+ }
+
+ snprintf(fname, sizeof(fname), "%s/spp/dm_ddf-v1_2.dtd", ctx->root_dir);
+ if (xml_validate_dtd(ctx->xml, tnds, fname, ret_err) == 0)
+ *valid = 1;
+ else if (ret_err && *ret_err &&
+ os_strcmp(*ret_err, "No declaration for attribute xmlns of element MgmtTree\n") == 0) {
+ free(*ret_err);
+ debug_print(ctx, 1, "Ignore OMA-DM DDF DTD validation error for MgmtTree namespace declaration with xmlns attribute");
+ *ret_err = NULL;
+ *valid = 1;
+ } else
+ *valid = 0;
+
+ mo = tnds_to_mo(ctx->xml, tnds);
+ xml_node_free(ctx->xml, tnds);
+ if (mo == NULL) {
+ debug_print(ctx, 1, "invalid moContainer for %s", urn);
+ }
+
+ return mo;
+}
+
+
+static xml_node_t * spp_exec_upload_mo(struct hs20_svc *ctx,
+ const char *session_id, const char *urn)
+{
+ xml_namespace_t *ns;
+ xml_node_t *spp_node, *node, *exec_node;
+
+ spp_node = build_post_dev_data_response(ctx, &ns, session_id, "OK",
+ NULL);
+ if (spp_node == NULL)
+ return NULL;
+
+ exec_node = xml_node_create(ctx->xml, spp_node, ns, "exec");
+
+ node = xml_node_create(ctx->xml, exec_node, ns, "uploadMO");
+ xml_node_add_attr(ctx->xml, node, ns, "moURN", urn);
+
+ return spp_node;
+}
+
+
+static xml_node_t * hs20_subscription_registration(struct hs20_svc *ctx,
+ const char *realm,
+ const char *session_id,
+ const char *redirect_uri,
+ const u8 *mac_addr)
+{
+ xml_namespace_t *ns;
+ xml_node_t *spp_node, *exec_node;
+ char uri[300], *val;
+
+ if (db_add_session(ctx, NULL, realm, session_id, NULL, redirect_uri,
+ SUBSCRIPTION_REGISTRATION, mac_addr) < 0)
+ return NULL;
+ val = db_get_osu_config_val(ctx, realm, "signup_url");
+ if (val == NULL)
+ return NULL;
+
+ spp_node = build_post_dev_data_response(ctx, &ns, session_id, "OK",
+ NULL);
+ if (spp_node == NULL)
+ return NULL;
+
+ exec_node = xml_node_create(ctx->xml, spp_node, ns, "exec");
+
+ snprintf(uri, sizeof(uri), "%s%s", val, session_id);
+ os_free(val);
+ xml_node_create_text(ctx->xml, exec_node, ns, "launchBrowserToURI",
+ uri);
+ return spp_node;
+}
+
+
+static xml_node_t * hs20_user_input_remediation(struct hs20_svc *ctx,
+ const char *user,
+ const char *realm, int dmacc,
+ const char *session_id)
+{
+ return build_sub_rem_resp(ctx, user, realm, session_id, 0, dmacc);
+}
+
+
+static char * db_get_osu_config_val(struct hs20_svc *ctx, const char *realm,
+ const char *field)
+{
+ char *cmd;
+ struct get_db_field_data data;
+
+ cmd = sqlite3_mprintf("SELECT value FROM osu_config WHERE realm=%Q AND "
+ "field=%Q", realm, field);
+ if (cmd == NULL)
+ return NULL;
+ debug_print(ctx, 1, "DB: %s", cmd);
+ memset(&data, 0, sizeof(data));
+ data.field = "value";
+ if (sqlite3_exec(ctx->db, cmd, get_db_field, &data, NULL) != SQLITE_OK)
+ {
+ debug_print(ctx, 1, "DB: Could not find osu_config %s: %s",
+ realm, sqlite3_errmsg(ctx->db));
+ sqlite3_free(cmd);
+ return NULL;
+ }
+ sqlite3_free(cmd);
+
+ debug_print(ctx, 1, "DB: return '%s'", data.value);
+ return data.value;
+}
+
+
+static xml_node_t * build_pps(struct hs20_svc *ctx,
+ const char *user, const char *realm,
+ const char *pw, const char *cert,
+ int machine_managed, const char *test,
+ const char *imsi, const char *dmacc_username,
+ const char *dmacc_password,
+ xml_node_t *policy_node)
+{
+ xml_node_t *pps, *c, *trust, *aaa, *aaa1, *upd, *homesp, *p;
+ xml_node_t *cred, *eap, *userpw;
+
+ pps = xml_node_create_root(ctx->xml, NULL, NULL, NULL,
+ "PerProviderSubscription");
+ if (!pps) {
+ xml_node_free(ctx->xml, policy_node);
+ return NULL;
+ }
+
+ add_text_node(ctx, pps, "UpdateIdentifier", "1");
+
+ c = xml_node_create(ctx->xml, pps, NULL, "Cred01");
+
+ add_text_node(ctx, c, "CredentialPriority", "1");
+
+ if (imsi)
+ goto skip_aaa_trust_root;
+ aaa = xml_node_create(ctx->xml, c, NULL, "AAAServerTrustRoot");
+ aaa1 = xml_node_create(ctx->xml, aaa, NULL, "AAA1");
+ add_text_node_conf(ctx, realm, aaa1, "CertURL",
+ "aaa_trust_root_cert_url");
+ if (test && os_strcmp(test, "corrupt_aaa_hash") == 0) {
+ debug_print(ctx, 1,
+ "TEST: Corrupt PPS/Cred*/AAAServerTrustRoot/Root*/CertSHA256FingerPrint");
+ add_text_node_conf_corrupt(ctx, realm, aaa1,
+ "CertSHA256Fingerprint",
+ "aaa_trust_root_cert_fingerprint");
+ } else {
+ add_text_node_conf(ctx, realm, aaa1, "CertSHA256Fingerprint",
+ "aaa_trust_root_cert_fingerprint");
+ }
+
+ if (test && os_strcmp(test, "corrupt_polupd_hash") == 0) {
+ debug_print(ctx, 1,
+ "TEST: Corrupt PPS/Cred*/Policy/PolicyUpdate/Trustroot/CertSHA256FingerPrint");
+ p = xml_node_create(ctx->xml, c, NULL, "Policy");
+ upd = xml_node_create(ctx->xml, p, NULL, "PolicyUpdate");
+ add_text_node(ctx, upd, "UpdateInterval", "30");
+ add_text_node(ctx, upd, "UpdateMethod", "SPP-ClientInitiated");
+ add_text_node(ctx, upd, "Restriction", "Unrestricted");
+ add_text_node_conf(ctx, realm, upd, "URI", "policy_url");
+ trust = xml_node_create(ctx->xml, upd, NULL, "TrustRoot");
+ add_text_node_conf(ctx, realm, trust, "CertURL",
+ "policy_trust_root_cert_url");
+ add_text_node_conf_corrupt(ctx, realm, trust,
+ "CertSHA256Fingerprint",
+ "policy_trust_root_cert_fingerprint");
+ }
+skip_aaa_trust_root:
+
+ upd = xml_node_create(ctx->xml, c, NULL, "SubscriptionUpdate");
+ add_text_node(ctx, upd, "UpdateInterval", "4294967295");
+ add_text_node(ctx, upd, "UpdateMethod", "SPP-ClientInitiated");
+ add_text_node(ctx, upd, "Restriction", "HomeSP");
+ add_text_node_conf(ctx, realm, upd, "URI", "spp_http_auth_url");
+ trust = xml_node_create(ctx->xml, upd, NULL, "TrustRoot");
+ add_text_node_conf(ctx, realm, trust, "CertURL", "trust_root_cert_url");
+ if (test && os_strcmp(test, "corrupt_subrem_hash") == 0) {
+ debug_print(ctx, 1,
+ "TEST: Corrupt PPS/Cred*/SubscriptionUpdate/Trustroot/CertSHA256FingerPrint");
+ add_text_node_conf_corrupt(ctx, realm, trust,
+ "CertSHA256Fingerprint",
+ "trust_root_cert_fingerprint");
+ } else {
+ add_text_node_conf(ctx, realm, trust, "CertSHA256Fingerprint",
+ "trust_root_cert_fingerprint");
+ }
+
+ if (dmacc_username &&
+ !build_username_password(ctx, upd, dmacc_username,
+ dmacc_password)) {
+ xml_node_free(ctx->xml, pps);
+ xml_node_free(ctx->xml, policy_node);
+ return NULL;
+ }
+
+ if (policy_node)
+ xml_node_add_child(ctx->xml, c, policy_node);
+
+ homesp = xml_node_create(ctx->xml, c, NULL, "HomeSP");
+ add_text_node_conf(ctx, realm, homesp, "FriendlyName", "friendly_name");
+ add_text_node_conf(ctx, realm, homesp, "FQDN", "fqdn");
+
+ xml_node_create(ctx->xml, c, NULL, "SubscriptionParameters");
+
+ cred = xml_node_create(ctx->xml, c, NULL, "Credential");
+ add_creation_date(ctx, cred);
+ if (imsi) {
+ xml_node_t *sim;
+ const char *type = "18"; /* default to EAP-SIM */
+
+ sim = xml_node_create(ctx->xml, cred, NULL, "SIM");
+ add_text_node(ctx, sim, "IMSI", imsi);
+ if (ctx->eap_method && os_strcmp(ctx->eap_method, "AKA") == 0)
+ type = "23";
+ else if (ctx->eap_method &&
+ os_strcmp(ctx->eap_method, "AKA'") == 0)
+ type = "50";
+ add_text_node(ctx, sim, "EAPType", type);
+ } else if (cert) {
+ xml_node_t *dc;
+ dc = xml_node_create(ctx->xml, cred, NULL,
+ "DigitalCertificate");
+ add_text_node(ctx, dc, "CertificateType", "x509v3");
+ add_text_node(ctx, dc, "CertSHA256Fingerprint", cert);
+ } else {
+ userpw = build_username_password(ctx, cred, user, pw);
+ add_text_node(ctx, userpw, "MachineManaged",
+ machine_managed ? "TRUE" : "FALSE");
+ eap = xml_node_create(ctx->xml, userpw, NULL, "EAPMethod");
+ add_text_node(ctx, eap, "EAPType", "21");
+ add_text_node(ctx, eap, "InnerMethod", "MS-CHAP-V2");
+ }
+ add_text_node(ctx, cred, "Realm", realm);
+
+ return pps;
+}
+
+
+static xml_node_t * spp_exec_get_certificate(struct hs20_svc *ctx,
+ const char *session_id,
+ const char *user,
+ const char *realm,
+ int add_est_user)
+{
+ xml_namespace_t *ns;
+ xml_node_t *spp_node, *enroll, *exec_node;
+ char *val;
+ char password[11];
+ char *b64;
+
+ if (add_est_user && new_password(password, sizeof(password)) < 0)
+ return NULL;
+
+ spp_node = build_post_dev_data_response(ctx, &ns, session_id, "OK",
+ NULL);
+ if (spp_node == NULL)
+ return NULL;
+
+ exec_node = xml_node_create(ctx->xml, spp_node, ns, "exec");
+
+ enroll = xml_node_create(ctx->xml, exec_node, ns, "getCertificate");
+ xml_node_add_attr(ctx->xml, enroll, NULL, "enrollmentProtocol", "EST");
+
+ val = db_get_osu_config_val(ctx, realm, "est_url");
+ xml_node_create_text(ctx->xml, enroll, ns, "enrollmentServerURI",
+ val ? val : "");
+ os_free(val);
+
+ if (!add_est_user)
+ return spp_node;
+
+ xml_node_create_text(ctx->xml, enroll, ns, "estUserID", user);
+
+ b64 = base64_encode(password, strlen(password), NULL);
+ if (b64 == NULL) {
+ xml_node_free(ctx->xml, spp_node);
+ return NULL;
+ }
+ xml_node_create_text(ctx->xml, enroll, ns, "estPassword", b64);
+ free(b64);
+
+ db_update_session_password(ctx, user, realm, session_id, password);
+
+ return spp_node;
+}
+
+
+static xml_node_t * hs20_user_input_registration(struct hs20_svc *ctx,
+ const char *session_id,
+ int enrollment_done)
+{
+ xml_namespace_t *ns;
+ xml_node_t *spp_node, *node = NULL;
+ xml_node_t *pps, *tnds;
+ char buf[400];
+ char *str;
+ char *user, *realm, *pw, *type, *mm, *test;
+ const char *status;
+ int cert = 0;
+ int machine_managed = 0;
+ char *fingerprint;
+
+ user = db_get_session_val(ctx, NULL, NULL, session_id, "user");
+ realm = db_get_session_val(ctx, NULL, NULL, session_id, "realm");
+ pw = db_get_session_val(ctx, NULL, NULL, session_id, "password");
+
+ if (!user || !realm || !pw) {
+ debug_print(ctx, 1, "Could not find session info from DB for "
+ "the new subscription");
+ free(user);
+ free(realm);
+ free(pw);
+ return NULL;
+ }
+
+ mm = db_get_session_val(ctx, NULL, NULL, session_id, "machine_managed");
+ if (mm && atoi(mm))
+ machine_managed = 1;
+ free(mm);
+
+ type = db_get_session_val(ctx, NULL, NULL, session_id, "type");
+ if (type && strcmp(type, "cert") == 0)
+ cert = 1;
+ free(type);
+
+ if (cert && !enrollment_done) {
+ xml_node_t *ret;
+ hs20_eventlog(ctx, user, realm, session_id,
+ "request client certificate enrollment", NULL);
+ ret = spp_exec_get_certificate(ctx, session_id, user, realm, 1);
+ free(user);
+ free(realm);
+ free(pw);
+ return ret;
+ }
+
+ if (!cert && strlen(pw) == 0) {
+ machine_managed = 1;
+ free(pw);
+ pw = malloc(11);
+ if (pw == NULL || new_password(pw, 11) < 0) {
+ free(user);
+ free(realm);
+ free(pw);
+ return NULL;
+ }
+ }
+
+ status = "Provisioning complete, request sppUpdateResponse";
+ spp_node = build_post_dev_data_response(ctx, &ns, session_id, status,
+ NULL);
+ if (spp_node == NULL)
+ return NULL;
+
+ fingerprint = db_get_session_val(ctx, NULL, NULL, session_id, "cert");
+ test = db_get_session_val(ctx, NULL, NULL, session_id, "test");
+ if (test)
+ debug_print(ctx, 1, "TEST: Requested special behavior: %s",
+ test);
+ pps = build_pps(ctx, user, realm, pw,
+ fingerprint ? fingerprint : NULL, machine_managed,
+ test, NULL, NULL, NULL, NULL);
+ free(fingerprint);
+ free(test);
+ if (!pps) {
+ xml_node_free(ctx->xml, spp_node);
+ free(user);
+ free(realm);
+ free(pw);
+ return NULL;
+ }
+
+ debug_print(ctx, 1, "Request DB subscription registration on success "
+ "notification");
+ if (machine_managed) {
+ db_update_session_password(ctx, user, realm, session_id, pw);
+ db_update_session_machine_managed(ctx, user, realm, session_id,
+ machine_managed);
+ }
+ db_add_session_pps(ctx, user, realm, session_id, pps);
+
+ hs20_eventlog_node(ctx, user, realm, session_id,
+ "new subscription", pps);
+ free(user);
+ free(pw);
+
+ tnds = mo_to_tnds(ctx->xml, pps, 0, URN_HS20_PPS, NULL);
+ xml_node_free(ctx->xml, pps);
+ if (!tnds) {
+ xml_node_free(ctx->xml, spp_node);
+ free(realm);
+ return NULL;
+ }
+
+ str = xml_node_to_str(ctx->xml, tnds);
+ xml_node_free(ctx->xml, tnds);
+ if (str == NULL) {
+ xml_node_free(ctx->xml, spp_node);
+ free(realm);
+ return NULL;
+ }
+
+ node = xml_node_create_text(ctx->xml, spp_node, ns, "addMO", str);
+ free(str);
+ snprintf(buf, sizeof(buf), "./Wi-Fi/%s/PerProviderSubscription", realm);
+ free(realm);
+ xml_node_add_attr(ctx->xml, node, ns, "managementTreeURI", buf);
+ xml_node_add_attr(ctx->xml, node, ns, "moURN", URN_HS20_PPS);
+
+ return spp_node;
+}
+
+
+static xml_node_t * hs20_user_input_free_remediation(struct hs20_svc *ctx,
+ const char *user,
+ const char *realm,
+ const char *session_id)
+{
+ xml_namespace_t *ns;
+ xml_node_t *spp_node;
+ xml_node_t *cred;
+ char buf[400];
+ char *status;
+ char *free_account, *pw;
+
+ free_account = db_get_osu_config_val(ctx, realm, "free_account");
+ if (free_account == NULL)
+ return NULL;
+ pw = db_get_val(ctx, free_account, realm, "password", 0);
+ if (pw == NULL) {
+ free(free_account);
+ return NULL;
+ }
+
+ cred = build_credential_pw(ctx, free_account, realm, pw, 1);
+ free(free_account);
+ free(pw);
+ if (!cred) {
+ xml_node_free(ctx->xml, cred);
+ return NULL;
+ }
+
+ status = "Remediation complete, request sppUpdateResponse";
+ spp_node = build_post_dev_data_response(ctx, &ns, session_id, status,
+ NULL);
+ if (spp_node == NULL)
+ return NULL;
+
+ snprintf(buf, sizeof(buf),
+ "./Wi-Fi/%s/PerProviderSubscription/Cred01/Credential",
+ realm);
+
+ if (add_update_node(ctx, spp_node, ns, buf, cred) < 0) {
+ xml_node_free(ctx->xml, spp_node);
+ return NULL;
+ }
+
+ hs20_eventlog_node(ctx, user, realm, session_id,
+ "free/public remediation", cred);
+ xml_node_free(ctx->xml, cred);
+
+ return spp_node;
+}
+
+
+static xml_node_t * hs20_user_input_complete(struct hs20_svc *ctx,
+ const char *user,
+ const char *realm, int dmacc,
+ const char *session_id)
+{
+ char *val;
+ enum hs20_session_operation oper;
+
+ val = db_get_session_val(ctx, user, realm, session_id, "operation");
+ if (val == NULL) {
+ debug_print(ctx, 1, "No session %s found to continue",
+ session_id);
+ return NULL;
+ }
+ oper = atoi(val);
+ free(val);
+
+ if (oper == USER_REMEDIATION) {
+ return hs20_user_input_remediation(ctx, user, realm, dmacc,
+ session_id);
+ }
+
+ if (oper == FREE_REMEDIATION) {
+ return hs20_user_input_free_remediation(ctx, user, realm,
+ session_id);
+ }
+
+ if (oper == SUBSCRIPTION_REGISTRATION) {
+ return hs20_user_input_registration(ctx, session_id, 0);
+ }
+
+ debug_print(ctx, 1, "User session %s not in state for user input "
+ "completion", session_id);
+ return NULL;
+}
+
+
+static xml_node_t * hs20_cert_reenroll_complete(struct hs20_svc *ctx,
+ const char *session_id)
+{
+ char *user, *realm, *cert;
+ char *status;
+ xml_namespace_t *ns;
+ xml_node_t *spp_node, *cred;
+ char buf[400];
+
+ user = db_get_session_val(ctx, NULL, NULL, session_id, "user");
+ realm = db_get_session_val(ctx, NULL, NULL, session_id, "realm");
+ cert = db_get_session_val(ctx, NULL, NULL, session_id, "cert");
+ if (!user || !realm || !cert) {
+ debug_print(ctx, 1,
+ "Could not find session info from DB for certificate reenrollment");
+ free(user);
+ free(realm);
+ free(cert);
+ return NULL;
+ }
+
+ cred = build_credential_cert(ctx, user, realm, cert);
+ if (!cred) {
+ debug_print(ctx, 1, "Could not build credential");
+ free(user);
+ free(realm);
+ free(cert);
+ return NULL;
+ }
+
+ status = "Remediation complete, request sppUpdateResponse";
+ spp_node = build_post_dev_data_response(ctx, &ns, session_id, status,
+ NULL);
+ if (spp_node == NULL) {
+ debug_print(ctx, 1, "Could not build sppPostDevDataResponse");
+ free(user);
+ free(realm);
+ free(cert);
+ xml_node_free(ctx->xml, cred);
+ return NULL;
+ }
+
+ snprintf(buf, sizeof(buf),
+ "./Wi-Fi/%s/PerProviderSubscription/Cred01/Credential",
+ realm);
+
+ if (add_update_node(ctx, spp_node, ns, buf, cred) < 0) {
+ debug_print(ctx, 1, "Could not add update node");
+ xml_node_free(ctx->xml, spp_node);
+ free(user);
+ free(realm);
+ free(cert);
+ return NULL;
+ }
+
+ hs20_eventlog_node(ctx, user, realm, session_id,
+ "certificate reenrollment", cred);
+ xml_node_free(ctx->xml, cred);
+
+ free(user);
+ free(realm);
+ free(cert);
+ return spp_node;
+}
+
+
+static xml_node_t * hs20_cert_enroll_completed(struct hs20_svc *ctx,
+ const char *user,
+ const char *realm, int dmacc,
+ const char *session_id)
+{
+ char *val;
+ enum hs20_session_operation oper;
+
+ val = db_get_session_val(ctx, NULL, NULL, session_id, "operation");
+ if (val == NULL) {
+ debug_print(ctx, 1, "No session %s found to continue",
+ session_id);
+ return NULL;
+ }
+ oper = atoi(val);
+ free(val);
+
+ if (oper == SUBSCRIPTION_REGISTRATION)
+ return hs20_user_input_registration(ctx, session_id, 1);
+ if (oper == CERT_REENROLL)
+ return hs20_cert_reenroll_complete(ctx, session_id);
+
+ debug_print(ctx, 1, "User session %s not in state for certificate "
+ "enrollment completion", session_id);
+ return NULL;
+}
+
+
+static xml_node_t * hs20_cert_enroll_failed(struct hs20_svc *ctx,
+ const char *user,
+ const char *realm, int dmacc,
+ const char *session_id)
+{
+ char *val;
+ enum hs20_session_operation oper;
+ xml_node_t *spp_node, *node;
+ char *status;
+ xml_namespace_t *ns;
+
+ val = db_get_session_val(ctx, user, realm, session_id, "operation");
+ if (val == NULL) {
+ debug_print(ctx, 1, "No session %s found to continue",
+ session_id);
+ return NULL;
+ }
+ oper = atoi(val);
+ free(val);
+
+ if (oper != SUBSCRIPTION_REGISTRATION) {
+ debug_print(ctx, 1, "User session %s not in state for "
+ "enrollment failure", session_id);
+ return NULL;
+ }
+
+ status = "Error occurred";
+ spp_node = build_post_dev_data_response(ctx, &ns, session_id, status,
+ NULL);
+ if (spp_node == NULL)
+ return NULL;
+ node = xml_node_create(ctx->xml, spp_node, ns, "sppError");
+ xml_node_add_attr(ctx->xml, node, NULL, "errorCode",
+ "Credentials cannot be provisioned at this time");
+ db_remove_session(ctx, user, realm, session_id);
+
+ return spp_node;
+}
+
+
+static xml_node_t * hs20_sim_provisioning(struct hs20_svc *ctx,
+ const char *user,
+ const char *realm, int dmacc,
+ const char *session_id)
+{
+ xml_namespace_t *ns;
+ xml_node_t *spp_node, *node = NULL;
+ xml_node_t *pps, *tnds;
+ char buf[400];
+ char *str;
+ const char *status;
+ char dmacc_username[32];
+ char dmacc_password[32];
+ char *policy;
+ xml_node_t *policy_node = NULL;
+
+ if (!ctx->imsi) {
+ debug_print(ctx, 1, "IMSI not available for SIM provisioning");
+ return NULL;
+ }
+
+ if (new_password(dmacc_username, sizeof(dmacc_username)) < 0 ||
+ new_password(dmacc_password, sizeof(dmacc_password)) < 0) {
+ debug_print(ctx, 1,
+ "Failed to generate DMAcc username/password");
+ return NULL;
+ }
+
+ status = "Provisioning complete, request sppUpdateResponse";
+ spp_node = build_post_dev_data_response(ctx, &ns, session_id, status,
+ NULL);
+ if (!spp_node)
+ return NULL;
+
+ policy = db_get_osu_config_val(ctx, realm, "sim_policy");
+ if (policy) {
+ policy_node = read_policy_file(ctx, policy);
+ os_free(policy);
+ if (!policy_node) {
+ xml_node_free(ctx->xml, spp_node);
+ return NULL;
+ }
+ update_policy_update_uri(ctx, realm, policy_node);
+ node = get_node_uri(ctx->xml, policy_node,
+ "Policy/PolicyUpdate");
+ if (node)
+ build_username_password(ctx, node, dmacc_username,
+ dmacc_password);
+ }
+
+ pps = build_pps(ctx, NULL, realm, NULL, NULL, 0, NULL, ctx->imsi,
+ dmacc_username, dmacc_password, policy_node);
+ if (!pps) {
+ xml_node_free(ctx->xml, spp_node);
+ return NULL;
+ }
+
+ debug_print(ctx, 1,
+ "Request DB subscription registration on success notification");
+ if (!user || !user[0])
+ user = ctx->imsi;
+ db_add_session(ctx, user, realm, session_id, NULL, NULL,
+ SUBSCRIPTION_REGISTRATION, NULL);
+ db_add_session_dmacc(ctx, session_id, dmacc_username, dmacc_password);
+ if (ctx->eap_method)
+ db_add_session_eap_method(ctx, session_id, ctx->eap_method);
+ if (ctx->id_hash)
+ db_add_session_id_hash(ctx, session_id, ctx->id_hash);
+ db_add_session_pps(ctx, user, realm, session_id, pps);
+
+ hs20_eventlog_node(ctx, user, realm, session_id,
+ "new subscription", pps);
+
+ tnds = mo_to_tnds(ctx->xml, pps, 0, URN_HS20_PPS, NULL);
+ xml_node_free(ctx->xml, pps);
+ if (!tnds) {
+ xml_node_free(ctx->xml, spp_node);
+ return NULL;
+ }
+
+ str = xml_node_to_str(ctx->xml, tnds);
+ xml_node_free(ctx->xml, tnds);
+ if (!str) {
+ xml_node_free(ctx->xml, spp_node);
+ return NULL;
+ }
+
+ node = xml_node_create_text(ctx->xml, spp_node, ns, "addMO", str);
+ free(str);
+ snprintf(buf, sizeof(buf), "./Wi-Fi/%s/PerProviderSubscription", realm);
+ xml_node_add_attr(ctx->xml, node, ns, "managementTreeURI", buf);
+ xml_node_add_attr(ctx->xml, node, ns, "moURN", URN_HS20_PPS);
+
+ return spp_node;
+}
+
+
+static xml_node_t * hs20_spp_post_dev_data(struct hs20_svc *ctx,
+ xml_node_t *node,
+ const char *user,
+ const char *realm,
+ const char *session_id,
+ int dmacc)
+{
+ const char *req_reason;
+ char *redirect_uri = NULL;
+ char *req_reason_buf = NULL;
+ char str[200];
+ xml_node_t *ret = NULL, *devinfo = NULL, *devdetail = NULL;
+ xml_node_t *mo, *macaddr;
+ char *version;
+ int valid;
+ char *supp, *pos;
+ char *err;
+ u8 wifi_mac_addr[ETH_ALEN];
+
+ version = xml_node_get_attr_value_ns(ctx->xml, node, SPP_NS_URI,
+ "sppVersion");
+ if (version == NULL || strstr(version, "1.0") == NULL) {
+ ret = build_post_dev_data_response(
+ ctx, NULL, session_id, "Error occurred",
+ "SPP version not supported");
+ hs20_eventlog_node(ctx, user, realm, session_id,
+ "Unsupported sppVersion", ret);
+ xml_node_get_attr_value_free(ctx->xml, version);
+ return ret;
+ }
+ xml_node_get_attr_value_free(ctx->xml, version);
+
+ mo = get_node(ctx->xml, node, "supportedMOList");
+ if (mo == NULL) {
+ ret = build_post_dev_data_response(
+ ctx, NULL, session_id, "Error occurred",
+ "Other");
+ hs20_eventlog_node(ctx, user, realm, session_id,
+ "No supportedMOList element", ret);
+ return ret;
+ }
+ supp = xml_node_get_text(ctx->xml, mo);
+ for (pos = supp; pos && *pos; pos++)
+ *pos = tolower(*pos);
+ if (supp == NULL ||
+ strstr(supp, URN_OMA_DM_DEVINFO) == NULL ||
+ strstr(supp, URN_OMA_DM_DEVDETAIL) == NULL ||
+ strstr(supp, URN_HS20_PPS) == NULL) {
+ xml_node_get_text_free(ctx->xml, supp);
+ ret = build_post_dev_data_response(
+ ctx, NULL, session_id, "Error occurred",
+ "One or more mandatory MOs not supported");
+ hs20_eventlog_node(ctx, user, realm, session_id,
+ "Unsupported MOs", ret);
+ return ret;
+ }
+ xml_node_get_text_free(ctx->xml, supp);
+
+ req_reason_buf = xml_node_get_attr_value(ctx->xml, node,
+ "requestReason");
+ if (req_reason_buf == NULL) {
+ debug_print(ctx, 1, "No requestReason attribute");
+ return NULL;
+ }
+ req_reason = req_reason_buf;
+
+ redirect_uri = xml_node_get_attr_value(ctx->xml, node, "redirectURI");
+
+ debug_print(ctx, 1, "requestReason: %s sessionID: %s redirectURI: %s",
+ req_reason, session_id, redirect_uri);
+ snprintf(str, sizeof(str), "sppPostDevData: requestReason=%s",
+ req_reason);
+ hs20_eventlog(ctx, user, realm, session_id, str, NULL);
+
+ devinfo = spp_get_mo(ctx, node, URN_OMA_DM_DEVINFO, &valid, &err);
+ if (devinfo == NULL) {
+ ret = build_post_dev_data_response(ctx, NULL, session_id,
+ "Error occurred", "Other");
+ hs20_eventlog_node(ctx, user, realm, session_id,
+ "No DevInfo moContainer in sppPostDevData",
+ ret);
+ os_free(err);
+ goto out;
+ }
+
+ hs20_eventlog_node(ctx, user, realm, session_id,
+ "Received DevInfo MO", devinfo);
+ if (valid == 0) {
+ hs20_eventlog(ctx, user, realm, session_id,
+ "OMA-DM DDF DTD validation errors in DevInfo MO",
+ err);
+ ret = build_post_dev_data_response(ctx, NULL, session_id,
+ "Error occurred", "Other");
+ os_free(err);
+ goto out;
+ }
+ os_free(err);
+ if (user)
+ db_update_mo(ctx, user, realm, "devinfo", devinfo);
+
+ devdetail = spp_get_mo(ctx, node, URN_OMA_DM_DEVDETAIL, &valid, &err);
+ if (devdetail == NULL) {
+ ret = build_post_dev_data_response(ctx, NULL, session_id,
+ "Error occurred", "Other");
+ hs20_eventlog_node(ctx, user, realm, session_id,
+ "No DevDetail moContainer in sppPostDevData",
+ ret);
+ os_free(err);
+ goto out;
+ }
+
+ hs20_eventlog_node(ctx, user, realm, session_id,
+ "Received DevDetail MO", devdetail);
+ if (valid == 0) {
+ hs20_eventlog(ctx, user, realm, session_id,
+ "OMA-DM DDF DTD validation errors "
+ "in DevDetail MO", err);
+ ret = build_post_dev_data_response(ctx, NULL, session_id,
+ "Error occurred", "Other");
+ os_free(err);
+ goto out;
+ }
+ os_free(err);
+
+ os_memset(wifi_mac_addr, 0, ETH_ALEN);
+ macaddr = get_node(ctx->xml, devdetail,
+ "Ext/org.wi-fi/Wi-Fi/Wi-FiMACAddress");
+ if (macaddr) {
+ char *addr, buf[50];
+
+ addr = xml_node_get_text(ctx->xml, macaddr);
+ if (addr && hwaddr_compact_aton(addr, wifi_mac_addr) == 0) {
+ snprintf(buf, sizeof(buf), "DevDetail MAC address: "
+ MACSTR, MAC2STR(wifi_mac_addr));
+ hs20_eventlog(ctx, user, realm, session_id, buf, NULL);
+ xml_node_get_text_free(ctx->xml, addr);
+ } else {
+ hs20_eventlog(ctx, user, realm, session_id,
+ "Could not extract MAC address from DevDetail",
+ NULL);
+ }
+ } else {
+ hs20_eventlog(ctx, user, realm, session_id,
+ "No MAC address in DevDetail", NULL);
+ }
+
+ if (user)
+ db_update_mo(ctx, user, realm, "devdetail", devdetail);
+
+ if (user)
+ mo = spp_get_mo(ctx, node, URN_HS20_PPS, &valid, &err);
+ else {
+ mo = NULL;
+ err = NULL;
+ }
+ if (user && mo) {
+ hs20_eventlog_node(ctx, user, realm, session_id,
+ "Received PPS MO", mo);
+ if (valid == 0) {
+ hs20_eventlog(ctx, user, realm, session_id,
+ "OMA-DM DDF DTD validation errors "
+ "in PPS MO", err);
+ xml_node_get_attr_value_free(ctx->xml, redirect_uri);
+ os_free(err);
+ return build_post_dev_data_response(
+ ctx, NULL, session_id,
+ "Error occurred", "Other");
+ }
+ db_update_mo(ctx, user, realm, "pps", mo);
+ db_update_val(ctx, user, realm, "fetch_pps", "0", dmacc);
+ xml_node_free(ctx->xml, mo);
+ }
+ os_free(err);
+
+ if (user && !mo) {
+ char *fetch;
+ int fetch_pps;
+
+ fetch = db_get_val(ctx, user, realm, "fetch_pps", dmacc);
+ fetch_pps = fetch ? atoi(fetch) : 0;
+ free(fetch);
+
+ if (fetch_pps) {
+ enum hs20_session_operation oper;
+ if (strcasecmp(req_reason, "Subscription remediation")
+ == 0)
+ oper = CONTINUE_SUBSCRIPTION_REMEDIATION;
+ else if (strcasecmp(req_reason, "Policy update") == 0)
+ oper = CONTINUE_POLICY_UPDATE;
+ else
+ oper = NO_OPERATION;
+ if (db_add_session(ctx, user, realm, session_id, NULL,
+ NULL, oper, NULL) < 0)
+ goto out;
+
+ ret = spp_exec_upload_mo(ctx, session_id,
+ URN_HS20_PPS);
+ hs20_eventlog_node(ctx, user, realm, session_id,
+ "request PPS MO upload",
+ ret);
+ goto out;
+ }
+ }
+
+ if (user && strcasecmp(req_reason, "MO upload") == 0) {
+ char *val = db_get_session_val(ctx, user, realm, session_id,
+ "operation");
+ enum hs20_session_operation oper;
+ if (!val) {
+ debug_print(ctx, 1, "No session %s found to continue",
+ session_id);
+ goto out;
+ }
+ oper = atoi(val);
+ free(val);
+ if (oper == CONTINUE_SUBSCRIPTION_REMEDIATION)
+ req_reason = "Subscription remediation";
+ else if (oper == CONTINUE_POLICY_UPDATE)
+ req_reason = "Policy update";
+ else {
+ debug_print(ctx, 1,
+ "No pending operation in session %s",
+ session_id);
+ goto out;
+ }
+ }
+
+ if (strcasecmp(req_reason, "Subscription registration") == 0) {
+ ret = hs20_subscription_registration(ctx, realm, session_id,
+ redirect_uri,
+ wifi_mac_addr);
+ hs20_eventlog_node(ctx, user, realm, session_id,
+ "subscription registration response",
+ ret);
+ goto out;
+ }
+ if (user && strcasecmp(req_reason, "Subscription remediation") == 0) {
+ ret = hs20_subscription_remediation(ctx, user, realm,
+ session_id, dmacc,
+ redirect_uri);
+ hs20_eventlog_node(ctx, user, realm, session_id,
+ "subscription remediation response",
+ ret);
+ goto out;
+ }
+ if (user && strcasecmp(req_reason, "Policy update") == 0) {
+ ret = hs20_policy_update(ctx, user, realm, session_id, dmacc);
+ hs20_eventlog_node(ctx, user, realm, session_id,
+ "policy update response",
+ ret);
+ goto out;
+ }
+
+ if (strcasecmp(req_reason, "User input completed") == 0) {
+ db_add_session_devinfo(ctx, session_id, devinfo);
+ db_add_session_devdetail(ctx, session_id, devdetail);
+ ret = hs20_user_input_complete(ctx, user, realm, dmacc,
+ session_id);
+ hs20_eventlog_node(ctx, user, realm, session_id,
+ "user input completed response", ret);
+ goto out;
+ }
+
+ if (strcasecmp(req_reason, "Certificate enrollment completed") == 0) {
+ ret = hs20_cert_enroll_completed(ctx, user, realm, dmacc,
+ session_id);
+ hs20_eventlog_node(ctx, user, realm, session_id,
+ "certificate enrollment response", ret);
+ goto out;
+ }
+
+ if (strcasecmp(req_reason, "Certificate enrollment failed") == 0) {
+ ret = hs20_cert_enroll_failed(ctx, user, realm, dmacc,
+ session_id);
+ hs20_eventlog_node(ctx, user, realm, session_id,
+ "certificate enrollment failed response",
+ ret);
+ goto out;
+ }
+
+ if (strcasecmp(req_reason, "Subscription provisioning") == 0) {
+ ret = hs20_sim_provisioning(ctx, user, realm, dmacc,
+ session_id);
+ hs20_eventlog_node(ctx, user, realm, session_id,
+ "subscription provisioning response",
+ ret);
+ goto out;
+ }
+
+ debug_print(ctx, 1, "Unsupported requestReason '%s' user '%s'",
+ req_reason, user);
+out:
+ xml_node_get_attr_value_free(ctx->xml, req_reason_buf);
+ xml_node_get_attr_value_free(ctx->xml, redirect_uri);
+ if (devinfo)
+ xml_node_free(ctx->xml, devinfo);
+ if (devdetail)
+ xml_node_free(ctx->xml, devdetail);
+ return ret;
+}
+
+
+static xml_node_t * build_spp_exchange_complete(struct hs20_svc *ctx,
+ const char *session_id,
+ const char *status,
+ const char *error_code)
+{
+ xml_namespace_t *ns;
+ xml_node_t *spp_node, *node;
+
+ spp_node = xml_node_create_root(ctx->xml, SPP_NS_URI, "spp", &ns,
+ "sppExchangeComplete");
+
+
+ xml_node_add_attr(ctx->xml, spp_node, ns, "sppVersion", "1.0");
+ xml_node_add_attr(ctx->xml, spp_node, ns, "sessionID", session_id);
+ xml_node_add_attr(ctx->xml, spp_node, ns, "sppStatus", status);
+
+ if (error_code) {
+ node = xml_node_create(ctx->xml, spp_node, ns, "sppError");
+ xml_node_add_attr(ctx->xml, node, NULL, "errorCode",
+ error_code);
+ }
+
+ return spp_node;
+}
+
+
+static int add_subscription(struct hs20_svc *ctx, const char *session_id)
+{
+ char *user, *realm, *pw, *pw_mm, *pps, *str;
+ char *osu_user, *osu_password, *eap_method;
+ char *policy = NULL;
+ char *sql;
+ int ret = -1;
+ char *free_account;
+ int free_acc;
+ char *type;
+ int cert = 0;
+ char *cert_pem, *fingerprint;
+ const char *method;
+
+ user = db_get_session_val(ctx, NULL, NULL, session_id, "user");
+ realm = db_get_session_val(ctx, NULL, NULL, session_id, "realm");
+ pw = db_get_session_val(ctx, NULL, NULL, session_id, "password");
+ pw_mm = db_get_session_val(ctx, NULL, NULL, session_id,
+ "machine_managed");
+ pps = db_get_session_val(ctx, NULL, NULL, session_id, "pps");
+ cert_pem = db_get_session_val(ctx, NULL, NULL, session_id, "cert_pem");
+ fingerprint = db_get_session_val(ctx, NULL, NULL, session_id, "cert");
+ type = db_get_session_val(ctx, NULL, NULL, session_id, "type");
+ if (type && strcmp(type, "cert") == 0)
+ cert = 1;
+ free(type);
+ osu_user = db_get_session_val(ctx, NULL, NULL, session_id, "osu_user");
+ osu_password = db_get_session_val(ctx, NULL, NULL, session_id,
+ "osu_password");
+ eap_method = db_get_session_val(ctx, NULL, NULL, session_id,
+ "eap_method");
+
+ if (!user || !realm || !pw) {
+ debug_print(ctx, 1, "Could not find session info from DB for "
+ "the new subscription");
+ goto out;
+ }
+
+ free_account = db_get_osu_config_val(ctx, realm, "free_account");
+ free_acc = free_account && strcmp(free_account, user) == 0;
+ free(free_account);
+
+ policy = db_get_osu_config_val(ctx, realm, "sim_policy");
+
+ debug_print(ctx, 1,
+ "New subscription: user='%s' realm='%s' free_acc=%d",
+ user, realm, free_acc);
+ debug_print(ctx, 1, "New subscription: pps='%s'", pps);
+
+ sql = sqlite3_mprintf("UPDATE eventlog SET user=%Q, realm=%Q WHERE "
+ "sessionid=%Q AND (user='' OR user IS NULL)",
+ user, realm, session_id);
+ if (sql) {
+ debug_print(ctx, 1, "DB: %s", sql);
+ if (sqlite3_exec(ctx->db, sql, NULL, NULL, NULL) != SQLITE_OK) {
+ debug_print(ctx, 1, "Failed to update eventlog in "
+ "sqlite database: %s",
+ sqlite3_errmsg(ctx->db));
+ }
+ sqlite3_free(sql);
+ }
+
+ if (free_acc) {
+ hs20_eventlog(ctx, user, realm, session_id,
+ "completed shared free account registration",
+ NULL);
+ ret = 0;
+ goto out;
+ }
+
+ str = db_get_session_val(ctx, NULL, NULL, session_id, "mac_addr");
+
+ if (eap_method && eap_method[0])
+ method = eap_method;
+ else
+ method = cert ? "TLS" : "TTLS-MSCHAPV2";
+ sql = sqlite3_mprintf("INSERT INTO users(identity,realm,phase2,methods,cert,cert_pem,machine_managed,mac_addr,osu_user,osu_password,policy) VALUES (%Q,%Q,%d,%Q,%Q,%Q,%d,%Q,%Q,%Q,%Q)",
+ user, realm, cert ? 0 : 1,
+ method,
+ fingerprint ? fingerprint : "",
+ cert_pem ? cert_pem : "",
+ pw_mm && atoi(pw_mm) ? 1 : 0,
+ str ? str : "",
+ osu_user ? osu_user : "",
+ osu_password ? osu_password : "",
+ policy ? policy : "");
+ free(str);
+ if (sql == NULL)
+ goto out;
+ debug_print(ctx, 1, "DB: %s", sql);
+ if (sqlite3_exec(ctx->db, sql, NULL, NULL, NULL) != SQLITE_OK) {
+ debug_print(ctx, 1, "Failed to add user in sqlite database: %s",
+ sqlite3_errmsg(ctx->db));
+ sqlite3_free(sql);
+ goto out;
+ }
+ sqlite3_free(sql);
+
+ if (cert)
+ ret = 0;
+ else
+ ret = update_password(ctx, user, realm, pw, 0);
+ if (ret < 0) {
+ sql = sqlite3_mprintf("DELETE FROM users WHERE identity=%Q AND realm=%Q AND (phase2=1 OR methods='TLS')",
+ user, realm);
+ if (sql) {
+ debug_print(ctx, 1, "DB: %s", sql);
+ sqlite3_exec(ctx->db, sql, NULL, NULL, NULL);
+ sqlite3_free(sql);
+ }
+ }
+
+ if (pps)
+ db_update_mo_str(ctx, user, realm, "pps", pps);
+
+ str = db_get_session_val(ctx, NULL, NULL, session_id, "devinfo");
+ if (str) {
+ db_update_mo_str(ctx, user, realm, "devinfo", str);
+ free(str);
+ }
+
+ str = db_get_session_val(ctx, NULL, NULL, session_id, "devdetail");
+ if (str) {
+ db_update_mo_str(ctx, user, realm, "devdetail", str);
+ free(str);
+ }
+
+ if (cert && user) {
+ const char *serialnum;
+
+ str = db_get_session_val(ctx, NULL, NULL, session_id,
+ "mac_addr");
+
+ if (os_strncmp(user, "cert-", 5) == 0)
+ serialnum = user + 5;
+ else
+ serialnum = "";
+ sql = sqlite3_mprintf("INSERT OR REPLACE INTO cert_enroll (mac_addr,user,realm,serialnum) VALUES(%Q,%Q,%Q,%Q)",
+ str ? str : "", user, realm ? realm : "",
+ serialnum);
+ free(str);
+ if (sql) {
+ debug_print(ctx, 1, "DB: %s", sql);
+ if (sqlite3_exec(ctx->db, sql, NULL, NULL, NULL) !=
+ SQLITE_OK) {
+ debug_print(ctx, 1,
+ "Failed to add cert_enroll entry into sqlite database: %s",
+ sqlite3_errmsg(ctx->db));
+ }
+ sqlite3_free(sql);
+ }
+ }
+
+ str = db_get_session_val(ctx, NULL, NULL, session_id,
+ "mobile_identifier_hash");
+ if (str) {
+ sql = sqlite3_mprintf("DELETE FROM sim_provisioning WHERE mobile_identifier_hash=%Q",
+ str);
+ if (sql) {
+ debug_print(ctx, 1, "DB: %s", sql);
+ if (sqlite3_exec(ctx->db, sql, NULL, NULL, NULL) !=
+ SQLITE_OK) {
+ debug_print(ctx, 1,
+ "Failed to delete pending sim_provisioning entry: %s",
+ sqlite3_errmsg(ctx->db));
+ }
+ sqlite3_free(sql);
+ }
+ os_free(str);
+ }
+
+ if (ret == 0) {
+ hs20_eventlog(ctx, user, realm, session_id,
+ "completed subscription registration", NULL);
+ }
+
+out:
+ free(user);
+ free(realm);
+ free(pw);
+ free(pw_mm);
+ free(pps);
+ free(cert_pem);
+ free(fingerprint);
+ free(osu_user);
+ free(osu_password);
+ free(eap_method);
+ os_free(policy);
+ return ret;
+}
+
+
+static xml_node_t * hs20_spp_update_response(struct hs20_svc *ctx,
+ xml_node_t *node,
+ const char *user,
+ const char *realm,
+ const char *session_id,
+ int dmacc)
+{
+ char *status;
+ xml_node_t *ret;
+ char *val;
+ enum hs20_session_operation oper;
+
+ status = xml_node_get_attr_value_ns(ctx->xml, node, SPP_NS_URI,
+ "sppStatus");
+ if (status == NULL) {
+ debug_print(ctx, 1, "No sppStatus attribute");
+ return NULL;
+ }
+
+ debug_print(ctx, 1, "sppUpdateResponse: sppStatus: %s sessionID: %s",
+ status, session_id);
+
+ val = db_get_session_val(ctx, NULL, NULL, session_id, "operation");
+ if (!val) {
+ debug_print(ctx, 1,
+ "No session active for sessionID: %s",
+ session_id);
+ oper = NO_OPERATION;
+ } else
+ oper = atoi(val);
+
+ if (strcasecmp(status, "OK") == 0) {
+ char *new_pw = NULL;
+
+ xml_node_get_attr_value_free(ctx->xml, status);
+
+ if (oper == USER_REMEDIATION) {
+ new_pw = db_get_session_val(ctx, user, realm,
+ session_id, "password");
+ if (new_pw == NULL || strlen(new_pw) == 0) {
+ free(new_pw);
+ ret = build_spp_exchange_complete(
+ ctx, session_id, "Error occurred",
+ "Other");
+ hs20_eventlog_node(ctx, user, realm,
+ session_id, "No password "
+ "had been assigned for "
+ "session", ret);
+ db_remove_session(ctx, user, realm, session_id);
+ return ret;
+ }
+ oper = UPDATE_PASSWORD;
+ }
+ if (oper == UPDATE_PASSWORD) {
+ if (!new_pw) {
+ new_pw = db_get_session_val(ctx, user, realm,
+ session_id,
+ "password");
+ if (!new_pw) {
+ db_remove_session(ctx, user, realm,
+ session_id);
+ return NULL;
+ }
+ }
+ debug_print(ctx, 1, "Update user '%s' password in DB",
+ user);
+ if (update_password(ctx, user, realm, new_pw, dmacc) <
+ 0) {
+ debug_print(ctx, 1, "Failed to update user "
+ "'%s' password in DB", user);
+ ret = build_spp_exchange_complete(
+ ctx, session_id, "Error occurred",
+ "Other");
+ hs20_eventlog_node(ctx, user, realm,
+ session_id, "Failed to "
+ "update database", ret);
+ db_remove_session(ctx, user, realm, session_id);
+ return ret;
+ }
+ hs20_eventlog(ctx, user, realm,
+ session_id, "Updated user password "
+ "in database", NULL);
+ }
+ if (oper == CLEAR_REMEDIATION) {
+ debug_print(ctx, 1,
+ "Clear remediation requirement for user '%s' in DB",
+ user);
+ if (clear_remediation(ctx, user, realm, dmacc) < 0) {
+ debug_print(ctx, 1,
+ "Failed to clear remediation requirement for user '%s' in DB",
+ user);
+ ret = build_spp_exchange_complete(
+ ctx, session_id, "Error occurred",
+ "Other");
+ hs20_eventlog_node(ctx, user, realm,
+ session_id,
+ "Failed to update database",
+ ret);
+ db_remove_session(ctx, user, realm, session_id);
+ return ret;
+ }
+ hs20_eventlog(ctx, user, realm,
+ session_id,
+ "Cleared remediation requirement in database",
+ NULL);
+ }
+ if (oper == SUBSCRIPTION_REGISTRATION) {
+ if (add_subscription(ctx, session_id) < 0) {
+ debug_print(ctx, 1, "Failed to add "
+ "subscription into DB");
+ ret = build_spp_exchange_complete(
+ ctx, session_id, "Error occurred",
+ "Other");
+ hs20_eventlog_node(ctx, user, realm,
+ session_id, "Failed to "
+ "update database", ret);
+ db_remove_session(ctx, user, realm, session_id);
+ return ret;
+ }
+ }
+ if (oper == POLICY_REMEDIATION || oper == POLICY_UPDATE) {
+ char *val;
+ val = db_get_val(ctx, user, realm, "remediation",
+ dmacc);
+ if (val && strcmp(val, "policy") == 0)
+ db_update_val(ctx, user, realm, "remediation",
+ "", dmacc);
+ free(val);
+ }
+ if (oper == POLICY_UPDATE)
+ db_update_val(ctx, user, realm, "polupd_done", "1",
+ dmacc);
+ if (oper == CERT_REENROLL) {
+ char *new_user;
+ char event[200];
+
+ new_user = db_get_session_val(ctx, NULL, NULL,
+ session_id, "user");
+ if (!new_user) {
+ debug_print(ctx, 1,
+ "Failed to find new user name (cert-serialnum)");
+ ret = build_spp_exchange_complete(
+ ctx, session_id, "Error occurred",
+ "Other");
+ hs20_eventlog_node(ctx, user, realm,
+ session_id,
+ "Failed to find new user name (cert reenroll)",
+ ret);
+ db_remove_session(ctx, NULL, NULL, session_id);
+ return ret;
+ }
+
+ debug_print(ctx, 1,
+ "Update certificate user entry to use the new serial number (old=%s new=%s)",
+ user, new_user);
+ os_snprintf(event, sizeof(event), "renamed user to: %s",
+ new_user);
+ hs20_eventlog(ctx, user, realm, session_id, event,
+ NULL);
+
+ if (db_update_val(ctx, user, realm, "identity",
+ new_user, 0) < 0 ||
+ db_update_val(ctx, new_user, realm, "remediation",
+ "", 0) < 0) {
+ debug_print(ctx, 1,
+ "Failed to update user name (cert-serialnum)");
+ ret = build_spp_exchange_complete(
+ ctx, session_id, "Error occurred",
+ "Other");
+ hs20_eventlog_node(ctx, user, realm,
+ session_id,
+ "Failed to update user name (cert reenroll)",
+ ret);
+ db_remove_session(ctx, NULL, NULL, session_id);
+ os_free(new_user);
+ return ret;
+ }
+
+ os_free(new_user);
+ }
+ ret = build_spp_exchange_complete(
+ ctx, session_id,
+ "Exchange complete, release TLS connection", NULL);
+ hs20_eventlog_node(ctx, user, realm, session_id,
+ "Exchange completed", ret);
+ db_remove_session(ctx, NULL, NULL, session_id);
+ return ret;
+ }
+
+ ret = build_spp_exchange_complete(ctx, session_id, "Error occurred",
+ "Other");
+ hs20_eventlog_node(ctx, user, realm, session_id, "Error occurred", ret);
+ db_remove_session(ctx, user, realm, session_id);
+ xml_node_get_attr_value_free(ctx->xml, status);
+ return ret;
+}
+
+
+#define SPP_SESSION_ID_LEN 16
+
+static char * gen_spp_session_id(void)
+{
+ FILE *f;
+ int i;
+ char *session;
+
+ session = os_malloc(SPP_SESSION_ID_LEN * 2 + 1);
+ if (session == NULL)
+ return NULL;
+
+ f = fopen("/dev/urandom", "r");
+ if (f == NULL) {
+ os_free(session);
+ return NULL;
+ }
+ for (i = 0; i < SPP_SESSION_ID_LEN; i++)
+ os_snprintf(session + i * 2, 3, "%02x", fgetc(f));
+
+ fclose(f);
+ return session;
+}
+
+xml_node_t * hs20_spp_server_process(struct hs20_svc *ctx, xml_node_t *node,
+ const char *auth_user,
+ const char *auth_realm, int dmacc)
+{
+ xml_node_t *ret = NULL;
+ char *session_id;
+ const char *op_name;
+ char *xml_err;
+ char fname[200];
+
+ debug_dump_node(ctx, "received request", node);
+
+ if (!dmacc && auth_user && auth_realm) {
+ char *real;
+ real = db_get_val(ctx, auth_user, auth_realm, "identity", 0);
+ if (!real) {
+ real = db_get_val(ctx, auth_user, auth_realm,
+ "identity", 1);
+ if (real)
+ dmacc = 1;
+ }
+ os_free(real);
+ }
+
+ snprintf(fname, sizeof(fname), "%s/spp/spp.xsd", ctx->root_dir);
+ if (xml_validate(ctx->xml, node, fname, &xml_err) < 0) {
+ /*
+ * We may not be able to extract the sessionID from invalid
+ * input, but well, we can try.
+ */
+ session_id = xml_node_get_attr_value_ns(ctx->xml, node,
+ SPP_NS_URI,
+ "sessionID");
+ debug_print(ctx, 1,
+ "SPP message failed validation, xsd file: %s xml-error: %s",
+ fname, xml_err);
+ hs20_eventlog_node(ctx, auth_user, auth_realm, session_id,
+ "SPP message failed validation", node);
+ hs20_eventlog(ctx, auth_user, auth_realm, session_id,
+ "Validation errors", xml_err);
+ os_free(xml_err);
+ xml_node_get_attr_value_free(ctx->xml, session_id);
+ /* TODO: what to return here? */
+ ret = xml_node_create_root(ctx->xml, NULL, NULL, NULL,
+ "SppValidationError");
+ return ret;
+ }
+
+ session_id = xml_node_get_attr_value_ns(ctx->xml, node, SPP_NS_URI,
+ "sessionID");
+ if (session_id) {
+ char *tmp;
+ debug_print(ctx, 1, "Received sessionID %s", session_id);
+ tmp = os_strdup(session_id);
+ xml_node_get_attr_value_free(ctx->xml, session_id);
+ if (tmp == NULL)
+ return NULL;
+ session_id = tmp;
+ } else {
+ session_id = gen_spp_session_id();
+ if (session_id == NULL) {
+ debug_print(ctx, 1, "Failed to generate sessionID");
+ return NULL;
+ }
+ debug_print(ctx, 1, "Generated sessionID %s", session_id);
+ }
+
+ op_name = xml_node_get_localname(ctx->xml, node);
+ if (op_name == NULL) {
+ debug_print(ctx, 1, "Could not get op_name");
+ return NULL;
+ }
+
+ if (strcmp(op_name, "sppPostDevData") == 0) {
+ hs20_eventlog_node(ctx, auth_user, auth_realm, session_id,
+ "sppPostDevData received and validated",
+ node);
+ ret = hs20_spp_post_dev_data(ctx, node, auth_user, auth_realm,
+ session_id, dmacc);
+ } else if (strcmp(op_name, "sppUpdateResponse") == 0) {
+ hs20_eventlog_node(ctx, auth_user, auth_realm, session_id,
+ "sppUpdateResponse received and validated",
+ node);
+ ret = hs20_spp_update_response(ctx, node, auth_user,
+ auth_realm, session_id, dmacc);
+ } else {
+ hs20_eventlog_node(ctx, auth_user, auth_realm, session_id,
+ "Unsupported SPP message received and "
+ "validated", node);
+ debug_print(ctx, 1, "Unsupported operation '%s'", op_name);
+ /* TODO: what to return here? */
+ ret = xml_node_create_root(ctx->xml, NULL, NULL, NULL,
+ "SppUnknownCommandError");
+ }
+ os_free(session_id);
+
+ if (ret == NULL) {
+ /* TODO: what to return here? */
+ ret = xml_node_create_root(ctx->xml, NULL, NULL, NULL,
+ "SppInternalError");
+ }
+
+ return ret;
+}
+
+
+int hs20_spp_server_init(struct hs20_svc *ctx)
+{
+ char fname[200];
+ ctx->db = NULL;
+ snprintf(fname, sizeof(fname), "%s/AS/DB/eap_user.db", ctx->root_dir);
+ if (sqlite3_open(fname, &ctx->db)) {
+ printf("Failed to open sqlite database: %s\n",
+ sqlite3_errmsg(ctx->db));
+ sqlite3_close(ctx->db);
+ return -1;
+ }
+
+ return 0;
+}
+
+
+void hs20_spp_server_deinit(struct hs20_svc *ctx)
+{
+ sqlite3_close(ctx->db);
+ ctx->db = NULL;
+}
diff --git a/hs20/server/spp_server.h b/hs20/server/spp_server.h
new file mode 100644
index 000000000000..421974c607b8
--- /dev/null
+++ b/hs20/server/spp_server.h
@@ -0,0 +1,36 @@
+/*
+ * Hotspot 2.0 SPP server
+ * Copyright (c) 2012-2013, Qualcomm Atheros, Inc.
+ *
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
+ */
+
+#ifndef SPP_SERVER_H
+#define SPP_SERVER_H
+
+struct hs20_svc {
+ const void *ctx;
+ struct xml_node_ctx *xml;
+ char *root_dir;
+ FILE *debug_log;
+ sqlite3 *db;
+ const char *addr;
+ const char *test;
+ const char *imsi;
+ const char *eap_method;
+ const char *id_hash;
+};
+
+
+void debug_print(struct hs20_svc *ctx, int print, const char *fmt, ...)
+ __attribute__ ((format (printf, 3, 4)));
+void debug_dump_node(struct hs20_svc *ctx, const char *title, xml_node_t *node);
+
+xml_node_t * hs20_spp_server_process(struct hs20_svc *ctx, xml_node_t *node,
+ const char *auth_user,
+ const char *auth_realm, int dmacc);
+int hs20_spp_server_init(struct hs20_svc *ctx);
+void hs20_spp_server_deinit(struct hs20_svc *ctx);
+
+#endif /* SPP_SERVER_H */
diff --git a/hs20/server/sql-example.txt b/hs20/server/sql-example.txt
new file mode 100644
index 000000000000..20dcf2f5c688
--- /dev/null
+++ b/hs20/server/sql-example.txt
@@ -0,0 +1,17 @@
+INSERT INTO osu_config(realm,field,value) VALUES('example.com','fqdn','example.com');
+INSERT INTO osu_config(realm,field,value) VALUES('example.com','friendly_name','Example Operator');
+INSERT INTO osu_config(realm,field,value) VALUES('example.com','spp_http_auth_url','https://subscription-server.osu.example.com/hs20/spp.php?realm=example.com');
+INSERT INTO osu_config(realm,field,value) VALUES('example.com','trust_root_cert_url','https://osu-server.osu.example.com/hs20/files/spp-root-ca.der');
+INSERT INTO osu_config(realm,field,value) VALUES('example.com','trust_root_cert_fingerprint','5b393a9246865569485c2605c3304e48212b449367858299beba9384c4cf4647');
+INSERT INTO osu_config(realm,field,value) VALUES('example.com','aaa_trust_root_cert_url','https://osu-server.osu.example.com/hs20/files/aaa-root-ca.der');
+INSERT INTO osu_config(realm,field,value) VALUES('example.com','aaa_trust_root_cert_fingerprint','5b393a9246865569485c2605c3304e48212b449367858299beba9384c4cf4647');
+INSERT INTO osu_config(realm,field,value) VALUES('example.com','free_account','free');
+INSERT INTO osu_config(realm,field,value) VALUES('example.com','policy_url','https://subscription-server.osu.example.com/hs20/spp.php?realm=example.com');
+INSERT INTO osu_config(realm,field,value) VALUES('example.com','remediation_url','https://subscription-server.osu.example.com/hs20/remediation.php?session_id=');
+INSERT INTO osu_config(realm,field,value) VALUES('example.com','free_remediation_url','https://subscription-server.osu.example.com/hs20/free-remediation.php?session_id=');
+INSERT INTO osu_config(realm,field,value) VALUES('example.com','signup_url','https://subscription-server.osu.example.com/hs20/signup.php?session_id=');
+
+
+INSERT INTO users(identity,realm,methods,password,phase2,shared) VALUES('free','example.com','TTLS-MSCHAPV2','free',1,1);
+
+INSERT INTO wildcards(identity,methods) VALUES('','TTLS,TLS');
diff --git a/hs20/server/sql.txt b/hs20/server/sql.txt
new file mode 100644
index 000000000000..2cc6edea4063
--- /dev/null
+++ b/hs20/server/sql.txt
@@ -0,0 +1,108 @@
+CREATE TABLE eventlog(
+ user TEXT,
+ realm TEXT,
+ sessionid TEXT COLLATE NOCASE,
+ timestamp TEXT,
+ notes TEXT,
+ dump TEXT,
+ addr TEXT
+);
+
+CREATE TABLE sessions(
+ timestamp TEXT,
+ id TEXT COLLATE NOCASE,
+ user TEXT,
+ realm TEXT,
+ password TEXT,
+ machine_managed BOOLEAN,
+ operation INTEGER,
+ type TEXT,
+ pps TEXT,
+ redirect_uri TEXT,
+ devinfo TEXT,
+ devdetail TEXT,
+ cert TEXT,
+ cert_pem TEXT,
+ mac_addr TEXT,
+ osu_user TEXT,
+ osu_password TEXT,
+ eap_method TEXT,
+ mobile_identifier_hash TEXT,
+ test TEXT
+);
+
+CREATE index sessions_id_index ON sessions(id);
+
+CREATE TABLE osu_config(
+ realm TEXT,
+ field TEXT,
+ value TEXT
+);
+
+CREATE TABLE users(
+ identity TEXT PRIMARY KEY,
+ methods TEXT,
+ password TEXT,
+ machine_managed BOOLEAN,
+ remediation TEXT,
+ phase2 INTEGER,
+ realm TEXT,
+ policy TEXT,
+ devinfo TEXT,
+ devdetail TEXT,
+ pps TEXT,
+ fetch_pps INTEGER,
+ osu_user TEXT,
+ osu_password TEXT,
+ shared INTEGER,
+ cert TEXT,
+ cert_pem TEXT,
+ t_c_timestamp INTEGER,
+ mac_addr TEXT,
+ last_msk TEXT,
+ polupd_done TEXT,
+ subrem TEXT
+);
+
+CREATE TABLE wildcards(
+ identity TEXT PRIMARY KEY,
+ methods TEXT
+);
+
+CREATE TABLE authlog(
+ timestamp TEXT,
+ session TEXT,
+ nas_ip TEXT,
+ username TEXT,
+ note TEXT
+);
+
+CREATE TABLE pending_tc(
+ mac_addr TEXT PRIMARY KEY,
+ identity TEXT
+);
+
+CREATE TABLE current_sessions(
+ mac_addr TEXT PRIMARY KEY,
+ identity TEXT,
+ start_time TEXT,
+ nas TEXT,
+ hs20_t_c_filtering BOOLEAN,
+ waiting_coa_ack BOOLEAN,
+ coa_ack_received BOOLEAN
+);
+
+CREATE TABLE cert_enroll(
+ mac_addr TEXT PRIMARY KEY,
+ user TEXT,
+ realm TEXT,
+ serialnum TEXT
+);
+
+CREATE TABLE sim_provisioning(
+ mobile_identifier_hash TEXT PRIMARY KEY,
+ imsi TEXT,
+ mac_addr TEXT,
+ eap_method TEXT,
+ timestamp TEXT
+);
diff --git a/hs20/server/www/add-free.php b/hs20/server/www/add-free.php
new file mode 100644
index 000000000000..1efc65563274
--- /dev/null
+++ b/hs20/server/www/add-free.php
@@ -0,0 +1,50 @@
+query("SELECT rowid,* FROM sessions WHERE id='$id'")->fetch();
+if ($row == false) {
+ die("Session not found");
+}
+
+$uri = $row['redirect_uri'];
+$rowid = $row['rowid'];
+$realm = $row['realm'];
+
+$row = $db->query("SELECT value FROM osu_config WHERE realm='$realm' AND field='free_account'")->fetch();
+if (!$row || strlen($row['value']) == 0) {
+ die("Free account disabled");
+}
+
+$user = $row['value'];
+
+$row = $db->query("SELECT password FROM users WHERE identity='$user' AND realm='$realm'")->fetch();
+if (!$row)
+ die("Free account not found");
+
+$pw = $row['password'];
+
+if (!$db->exec("UPDATE sessions SET user='$user', password='$pw', realm='$realm', machine_managed='1' WHERE rowid=$rowid")) {
+ die("Failed to update session database");
+}
+
+$db->exec("INSERT INTO eventlog(user,realm,sessionid,timestamp,notes) " .
+ "VALUES ('$user', '$realm', '$id', " .
+ "strftime('%Y-%m-%d %H:%M:%f','now'), " .
+ "'completed user input response for a new PPS MO')");
+
+header("Location: $uri", true, 302);
+
+?>
diff --git a/hs20/server/www/add-mo.php b/hs20/server/www/add-mo.php
new file mode 100644
index 000000000000..a3b4513531f8
--- /dev/null
+++ b/hs20/server/www/add-mo.php
@@ -0,0 +1,56 @@
+Invalid username
\n";
+ echo "Try again\n";
+ echo "