[meta-xilinx] [PATCH] minized-zynq7: Add support * Add the device tree for MiniZed * Add machine config for MiniZed * Add u-boot patch to support MiniZed * Add kernel config to suport MiniZed and wireless module * Add driver for Murata wireless module
Manjukumar Harthikote Matha
MANJUKUM at xilinx.com
Fri May 25 13:10:01 PDT 2018
Hi Clement,
> -----Original Message-----
> From: meta-xilinx-bounces at yoctoproject.org [mailto:meta-xilinx-
> bounces at yoctoproject.org] On Behalf Of Clement Laigle
> Sent: Thursday, May 03, 2018 10:35 PM
> To: meta-xilinx at lists.yoctoproject.org
> Subject: [meta-xilinx] [PATCH] minized-zynq7: Add support * Add the device tree
> for MiniZed * Add machine config for MiniZed * Add u-boot patch to support
> MiniZed * Add kernel config to suport MiniZed and wireless module * Add driver
> for Murata wireless module
>
> From: Clément Laigle <clement.laigle8 at gmail.com>
>
> Signed-off-by: Clément Laigle <clement.laigle8 at gmail.com>
> ---
> .../conf/machine/minized-zynq7.conf | 30 +
> .../recipes-bsp/device-tree/device-tree.bbappend | 6 +
> .../device-tree/files/minized-zynq7.dts | 241 ++
> .../minized-wireless/minized-wireless_2017.4.bb | 49 +
> .../u-boot-xlnx/v2017.3/u-boot-minized.patch | 203 +
> .../recipes-bsp/u-boot/u-boot-xlnx_2017.3.bbappend | 8 +
> .../hostapd/hostapd/0001-murata-hostapd-conf.patch | 11 +
> .../hostapd/hostapd_%.bbappend | 5 +
> ...urata-wpa_supplication-Add-server-in-hs20.patch | 4575
> ++++++++++++++++++++
> .../wpa-supplicant/wpa-supplicant_%.bbappend | 4 +
> .../cypress-orga-backport_4.12.bb | 73 +
> .../linux/linux-xlnx/v2017.3/wifi-bluetooth.cfg | 33 +
> .../linux/linux-xlnx_2017.3.bbappend | 1 +
> 13 files changed, 5239 insertions(+)
> create mode 100644 meta-xilinx-contrib/conf/machine/minized-zynq7.conf
> create mode 100644 meta-xilinx-contrib/recipes-bsp/device-tree/device-
> tree.bbappend
> create mode 100644 meta-xilinx-contrib/recipes-bsp/device-tree/files/minized-
> zynq7.dts
> create mode 100644 meta-xilinx-contrib/recipes-bsp/minized-wireless/minized-
> wireless_2017.4.bb
> create mode 100644 meta-xilinx-contrib/recipes-bsp/u-boot/u-boot-
> xlnx/v2017.3/u-boot-minized.patch
> create mode 100644 meta-xilinx-contrib/recipes-bsp/u-boot/u-boot-
> xlnx_2017.3.bbappend
> create mode 100644 meta-xilinx-contrib/recipes-
> connectivity/hostapd/hostapd/0001-murata-hostapd-conf.patch
> create mode 100644 meta-xilinx-contrib/recipes-
> connectivity/hostapd/hostapd_%.bbappend
> create mode 100644 meta-xilinx-contrib/recipes-connectivity/wpa-
> supplicant/wpa-supplicant/0001-murata-wpa_supplication-Add-server-in-
> hs20.patch
> create mode 100644 meta-xilinx-contrib/recipes-connectivity/wpa-
> supplicant/wpa-supplicant_%.bbappend
> create mode 100644 meta-xilinx-contrib/recipes-kernel/cypress-orga-
> backport/cypress-orga-backport_4.12.bb
> create mode 100644 meta-xilinx-contrib/recipes-kernel/linux/linux-
> xlnx/v2017.3/wifi-bluetooth.cfg
>
> diff --git a/meta-xilinx-contrib/conf/machine/minized-zynq7.conf b/meta-xilinx-
> contrib/conf/machine/minized-zynq7.conf
> new file mode 100644
> index 0000000..92d3876
> --- /dev/null
> +++ b/meta-xilinx-contrib/conf/machine/minized-zynq7.conf
> @@ -0,0 +1,30 @@
> +#@TYPE: Machine
> +#@NAME: minized-zynq7
> +#@DESCRIPTION: Machine support for MiniZed. (http://www.minized.org/)
> +
> +require conf/machine/include/tune-zynq.inc
> +require conf/machine/include/machine-xilinx-default.inc
> +require conf/machine/include/machine-xilinx-board.inc
> +
> +MACHINE_FEATURES = "ext2 vfat usbhost wifi bluetooth"
> +
> +MACHINE_ESSENTIAL_EXTRA_RRECOMMENDS += "cypress-orga-backport
> minized-wireless"
> +
> +# u-boot configuration
> +UBOOT_MACHINE = "zynq_minized_config"
> +SPL_BINARY = "spl/boot.bin"
> +
> +EXTRA_IMAGEDEPENDS += " \
> + u-boot-zynq-uenv \
> + virtual/boot-bin \
> + "
> +
> +SERIAL_CONSOLE = "115200 ttyPS0"
> +
> +MACHINE_ESSENTIAL_EXTRA_RDEPENDS += "device-tree"
> +
> +IMAGE_BOOT_FILES += " \
> + boot.bin \
> + ${MACHINE}.dtb \
> + uEnv.txt \
> + "
> diff --git a/meta-xilinx-contrib/recipes-bsp/device-tree/device-tree.bbappend
> b/meta-xilinx-contrib/recipes-bsp/device-tree/device-tree.bbappend
> new file mode 100644
> index 0000000..79f63fe
> --- /dev/null
> +++ b/meta-xilinx-contrib/recipes-bsp/device-tree/device-tree.bbappend
> @@ -0,0 +1,6 @@
> +FILESEXTRAPATHS_prepend := "${THISDIR}/files:"
> +
> +# device tree sources for MiniZed
> +COMPATIBLE_MACHINE_minized-zynq7 = ".*"
> +SRC_URI_append_minized-zynq7 = " file://minized-zynq7.dts"
> +
> diff --git a/meta-xilinx-contrib/recipes-bsp/device-tree/files/minized-zynq7.dts
> b/meta-xilinx-contrib/recipes-bsp/device-tree/files/minized-zynq7.dts
> new file mode 100644
> index 0000000..36ac168
> --- /dev/null
> +++ b/meta-xilinx-contrib/recipes-bsp/device-tree/files/minized-zynq7.dts
> @@ -0,0 +1,241 @@
> +/dts-v1/;
> +/include/ "zynq-7000.dtsi"
> +
> +
> +/ {
> + model = "Zynq Minized Board";
> + compatible = "xlnx,zynq-Minized", "xlnx,zynq-7000";
> +
> + chosen {
> + stdout-path = "serial0:115200n8";
> + };
> +
> + cpus {
> + cpu at 0 {
> + operating-points = <666666 1000000 333333 1000000>;
> + };
> + };
> +
> + aliases {
> + serial0 = &uart1;
> + serial1 = &bluetooth_uart;
> + spi0 = &qspi;
> + mmc0 = &sdhci1;
> + };
> +
> + memory {
> + device_type = "memory";
> + reg = <0 0x20000000>;
> + };
> +
> + usb_phy0: phy0 {
> + compatible = "ulpi-phy";
> + #phy-cells = <0x0>;
> + reg = <0xe0002000 0x1000>;
> + view-port = <0x170>;
> + drv-vbus;
> + linux,phandle = <0x7>;
> + phandle = <0x7>;
> + };
> +
> + leds {
> + compatible = "gpio-leds";
> + led-psg {
> + label = "led-psg";
> + gpios = <&gpio0 53 0>;
> + default-state = "on";
> + linux,default-trigger = "heartbeat";
> + };
> + led-psr {
> + label = "led-psr";
> + gpios = <&gpio0 52 0>;
> + default-state = "on";
> + linux,default-trigger = "heartbeat";
> + };
> + };
> +
> + gpio-keys {
> + compatible = "gpio-keys";
> + #address-cells = <1>;
> + #size-cells = <0>;
> + autorepeat;
> + sw3 {
> + label = "ps-bp";
> + gpios = <&gpio0 0 0>;
> + linux,code = <108>; /* down */
> + gpio-key,wakeup;
> + autorepeat;
> + };
> + };
> +
> + amba_pl: amba_pl {
> + #address-cells = <1>;
> + #size-cells = <1>;
> + compatible = "simple-bus";
> + ranges ;
> +
> + axi_gpio_0: gpio at 41200000 {
> + #gpio-cells = <2>;
> + compatible = "xlnx,xps-gpio-1.00.a";
> + gpio-controller ;
> + reg = <0x41200000 0x10000>;
> + xlnx,all-inputs = <0x0>;
> + xlnx,all-inputs-2 = <0x0>;
> + xlnx,all-outputs = <0x1>;
> + xlnx,all-outputs-2 = <0x1>;
> + xlnx,dout-default = <0x00000000>;
> + xlnx,dout-default-2 = <0x00000000>;
> + xlnx,gpio-width = <0x1>;
> + xlnx,gpio2-width = <0x1>;
> + xlnx,interrupt-present = <0x0>;
> + xlnx,is-dual = <0x1>;
> + xlnx,tri-default = <0xFFFFFFFF>;
> + xlnx,tri-default-2 = <0xFFFFFFFF>;
> + };
> + axi_gpio_1: gpio at 41210000 {
> + #gpio-cells = <2>;
> + compatible = "xlnx,xps-gpio-1.00.a";
> + gpio-controller ;
> + reg = <0x41210000 0x10000>;
> + xlnx,all-inputs = <0x1>;
> + xlnx,all-inputs-2 = <0x0>;
> + xlnx,all-outputs = <0x0>;
> + xlnx,all-outputs-2 = <0x0>;
> + xlnx,dout-default = <0x00000000>;
> + xlnx,dout-default-2 = <0x00000000>;
> + xlnx,gpio-width = <0x1>;
> + xlnx,gpio2-width = <0x20>;
> + xlnx,interrupt-present = <0x0>;
> + xlnx,is-dual = <0x0>;
> + xlnx,tri-default = <0xFFFFFFFF>;
> + xlnx,tri-default-2 = <0xFFFFFFFF>;
> + };
> + axi_iic_0: i2c at 41600000 {
> + #address-cells = <1>;
> + #size-cells = <0>;
> + clock-names = "ref_clk";
> + clocks = <&clkc 15>;
> + compatible = "xlnx,xps-iic-2.00.a";
> + interrupt-parent = <&intc>;
> + interrupts = <0 30 4>;
> + reg = <0x41600000 0x10000>;
> + };
> + bluetooth_uart: serial at 43c00000 {
> + clock-frequency = <0x2dc6c00>;
> + clock-names = "ref_clk";
> + clocks = <&clkc 0>;
> + compatible = "xlnx,xps-uart16550-2.00.a", "ns16550a";
> + current-speed = <115200>;
> + device_type = "serial";
> + interrupt-parent = <&intc>;
> + interrupts = <0 29 4>;
> + port-number = <1>;
> + reg = <0x43c00000 0x10000>;
> + reg-offset = <0x1000>;
> + reg-shift = <2>;
> + xlnx,external-xin-clk-hz = <0x2dc6c00>;
> + xlnx,external-xin-clk-hz-d = <0x30>;
> + xlnx,has-external-rclk = <0x0>;
> + xlnx,has-external-xin = <0x1>;
> + xlnx,is-a-16550 = <0x1>;
> + xlnx,s-axi-aclk-freq-hz-d = "100.0";
> + xlnx,use-modem-ports = <0x1>;
> + xlnx,use-user-ports = <0x1>;
> + };
> + };
> +
> + wlreg_on: wlreg-on {
> + compatible = "regulator-fixed";
> + regulator-name = "wlreg_on";
> + enable-active-high;
> + gpio = <&gpio0 56 0>;
> + regulator-min-microvolt = <3300000>;
> + regulator-max-microvolt = <3300000>;
> + startup-delay-us = <100>;
> + };
> +};
> +
> +&gpio0 {
> + emio-gpio-width = <4>;
> + gpio-mask-high = <0x0>;
> + gpio-mask-low = <0x5600>;
> +};
> +
> +&intc {
> + num_cpus = <1>;
> + num_interrupts = <96>;
> +};
> +
> +&uart1 {
> + status = "okay";
> +};
> +
> +&sdhci0 {
> + status = "okay";
> + bus-width= <4>;
> + xlnx,has-cd = <0x0>;
> + xlnx,has-power = <0x0>;
> + xlnx,has-wp = <0x0>;
> + non-removeable;
> + broken-cd;
> + vmmc-supply = <&wlreg_on>;
> +
> + brcmf: brcmf at 1 {
> + status = "okay";
> + reg = <1>;
> + compatible = "brcm,bcm43430-fmac";
> + };
> +};
> +
> +&sdhci1 {
> + status = "okay";
> + broken-adma2;
> + xlnx,has-cd = <0x1>;
> + xlnx,has-power = <0x0>;
> + xlnx,has-wp = <0x1>;
> +};
> +
> +&usb0 {
> + status = "okay";
> + dr_mode = "host";
> + phy_type = "ulpi";
> + usb-reset = <&gpio0 7 0>;
> + usb-phy = <&usb_phy0>;
> +};
> +
> +&qspi {
> + status = "okay";
> + #address-cells = <1>;
> + #size-cells = <0>;
> + interrupt-parent = <0x3>;
> + is-dual = <0x0>;
> + num-cs = <0x1>;
> +
> +
> + flash0: flash at 0 {
> + compatible = "micron,m25p80";
> + reg = <0x0>;
> + #address-cells = <1>;
> + #size-cells = <1>;
> + spi-max-frequency = <50000000>;
> +
> + partition at 0x00000000 {
> + label = "boot";
> + reg = <0x00000000 0x00500000>;
> + };
> + partition at 0x00500000 {
> + label = "bootenv";
> + reg = <0x00500000 0x00020000>;
> + };
> + partition at 0x00520000 {
> + label = "kernel";
> + reg = <0x00520000 0x00a80000>;
> + };
> + partition at 0x00fa0000 {
> + label = "spare";
> + reg = <0x00fa0000 0x00000000>;
> + };
> +
> + };
> +};
> +
> diff --git a/meta-xilinx-contrib/recipes-bsp/minized-wireless/minized-
> wireless_2017.4.bb b/meta-xilinx-contrib/recipes-bsp/minized-wireless/minized-
> wireless_2017.4.bb
> new file mode 100644
> index 0000000..a2e9c10
> --- /dev/null
> +++ b/meta-xilinx-contrib/recipes-bsp/minized-wireless/minized-
> wireless_2017.4.bb
> @@ -0,0 +1,49 @@
> +SUMMARY = "minized-wireless: Wi-Fi/BT drivers and firmware for the Murata
> 1DX module"
> +#SECTION = "PETALINUX/modules"
> +LICENSE = "MIT"
> +LIC_FILES_CHKSUM =
> "file://${COMMON_LICENSE_DIR}/MIT;md5=0835ade698e0bcf8506ecda2f7b4f30
> 2"
The license is not MIT, it should be specific to the below
https://github.com/murata-wireless/cyw-fmac-fw/blob/master/LICENCE.cypress
> +
> +SRC_URI = " \
> + git://github.com/murata-wireless/cyw-fmac-
> fw;protocol=http;branch=orga;destsuffix=cyw-fmac-fw \
> + git://github.com/murata-wireless/cyw-fmac-
> nvram;protocol=http;branch=orga;destsuffix=cyw-fmac-nvram \
> + git://github.com/murata-wireless/cyw-bt-
> patch;protocol=http;branch=morty-orga;destsuffix=cyw-bt-patch \
> + git://github.com/murata-wireless/cyw-fmac-utils-
> imx32;protocol=http;branch=orga;destsuffix=cyw-fmac-utils-imx32 \
> +"
> +
> +SRCREV_cyw-fmac-fw = "2242fd3f67a913fbfff8678cc8f7761629dca8ca"
> +SRCREV_cyw-fmac-nvram = "d12c2ac1b93941eaa03063bb7cb3c1ee1aa1b7d0"
> +SRCREV_cyw-bt-patch = "9216e0d9f778009b5667d032886dfd49174c4b3a"
> +SRCREV_cyw-fmac-utils-imx32 =
> "060688dfe76df98751207c8146268ce7fd80b6ab"
> +
> +SRCREV_default = "${AUTOREV}"
We should not pin the recipe to AUTOREV, use a commit id
> +
> +DEPENDS = "libnl virtual/kernel"
> +
> +S = "${WORKDIR}"
> +
> +KERNEL_VERSION = "${@base_read_file('${STAGING_KERNEL_BUILDDIR}/kernel-
> abiversion')}"
> +
> +
> +do_install() {
> + install -d ${D}/lib/firmware/brcm
> + install -d ${D}/etc/firmware
> + install -d ${D}/usr/bin
/usr/bin should not be used, use ${bindir}
> +
> + install -m 644 ${S}/cyw-fmac-fw/brcmfmac43430-sdio.bin
> ${D}/lib/firmware/brcm/brcmfmac43430-sdio.bin
> + install -m 644 ${S}/cyw-fmac-nvram/brcmfmac43430-sdio.txt
> ${D}/lib/firmware/brcm/brcmfmac43430-sdio.txt
> + install -m 644 ${S}/cyw-bt-patch/CYW43430A1.1DX.hcd
> ${D}/etc/firmware/BCM43430A1.1DX.hcd
> + install -m 755 ${S}/cyw-fmac-utils-imx32/wl ${D}/usr/bin/wl
> +}
> +
> +PACKAGES =+ "${PN}-mfgtest"
> +
> +FILES_${PN} = " \
> + /lib/firmware/brcm/brcmfmac43430-sdio.bin \
> + /lib/firmware/brcm/brcmfmac43430-sdio.txt \
> + /etc/firmware/BCM43430A1.1DX.hcd \
> +"
> +
> +FILES_${PN}-mfgtest = " \
> + /usr/bin/wl \
> +"
> +
> diff --git a/meta-xilinx-contrib/recipes-bsp/u-boot/u-boot-xlnx/v2017.3/u-boot-
> minized.patch b/meta-xilinx-contrib/recipes-bsp/u-boot/u-boot-xlnx/v2017.3/u-
> boot-minized.patch
> new file mode 100644
> index 0000000..793656a
> --- /dev/null
> +++ b/meta-xilinx-contrib/recipes-bsp/u-boot/u-boot-xlnx/v2017.3/u-boot-
> minized.patch
> @@ -0,0 +1,203 @@
> +From 4401d707451ea115d944e7ba34c6fd5777236e2d Mon Sep 17 00:00:00
> 2001
> +From: Clément Laigle <clement.laigle8 at gmail.com>
> +Date: Wed, 2 May 2018 20:29:22 +0200
> +Subject: [PATCH] Add MiniZed support
> +MIME-Version: 1.0
> +Content-Type: text/plain; charset=UTF-8
> +Content-Transfer-Encoding: 8bit
> +
> +Signed-off-by: Clément Laigle <clement.laigle8 at gmail.com>
> +---
> + arch/arm/dts/Makefile | 3 +-
> + arch/arm/dts/zynq-minized.dts | 101
> +++++++++++++++++++++++++++++++++++++++++
> + configs/zynq_minized_defconfig | 56 +++++++++++++++++++++++
> + 3 files changed, 159 insertions(+), 1 deletion(-)
> + create mode 100644 arch/arm/dts/zynq-minized.dts
> + create mode 100644 configs/zynq_minized_defconfig
> +
> +diff --git a/arch/arm/dts/Makefile b/arch/arm/dts/Makefile
> +index 27330e6..dde2c8e 100644
> +--- a/arch/arm/dts/Makefile
> ++++ b/arch/arm/dts/Makefile
> +@@ -115,7 +115,8 @@ dtb-$(CONFIG_ARCH_ZYNQ) += zynq-zc702.dtb \
> + zynq-zc770-xm010.dtb \
> + zynq-zc770-xm011.dtb \
> + zynq-zc770-xm012.dtb \
> +- zynq-zc770-xm013.dtb
> ++ zynq-zc770-xm013.dtb \
> ++ zynq-minized.dtb
> + dtb-$(CONFIG_ARCH_ZYNQMP) += \
> + zynqmp-ep108.dtb \
> + zynqmp-zcu100-revC.dtb \
> +diff --git a/arch/arm/dts/zynq-minized.dts b/arch/arm/dts/zynq-minized.dts
> +new file mode 100644
> +index 0000000..383d184
> +--- /dev/null
> ++++ b/arch/arm/dts/zynq-minized.dts
> +@@ -0,0 +1,101 @@
> ++/*
> ++ * Avnet Minized board DTS
> ++ *
> ++ * Copyright (C) 2015 Xilinx, Inc.
> ++ *
> ++ * SPDX-License-Identifier: GPL-2.0+
> ++ */
> ++/dts-v1/;
> ++#include "zynq-7000.dtsi"
> ++
> ++/ {
> ++ model = "Zynq Minized Board";
> ++ compatible = "xlnx,zynq-Minized", "xlnx,zynq-7000";
> ++
> ++ chosen {
> ++ stdout-path = "serial0:115200n8";
> ++ };
> ++
> ++ cpus {
> ++ cpu at 0 {
> ++ operating-points = <666666 1000000 333333 1000000>;
> ++ };
> ++ };
> ++
> ++ aliases {
> ++ serial0 = &uart1;
> ++ spi0 = &qspi;
> ++ mmc0 = &sdhci1;
> ++ };
> ++
> ++ memory at 0 {
> ++ device_type = "memory";
> ++ reg = <0 0x20000000>;
> ++ };
> ++
> ++};
> ++
> ++&gpio0 {
> ++ emio-gpio-width = <4>;
> ++ gpio-mask-high = <0x0>;
> ++ gpio-mask-low = <0x5600>;
> ++};
> ++
> ++&intc {
> ++ num_cpus = <2>;
> ++ num_interrupts = <96>;
> ++};
> ++
> ++&uart1 {
> ++ u-boot,dm-pre-reloc;
> ++ status = "okay";
> ++};
> ++
> ++&sdhci0 {
> ++ status = "disabled";
> ++};
> ++
> ++&sdhci1 {
> ++ status = "okay";
> ++ broken-adma2;
> ++ xlnx,has-cd = <0x1>;
> ++ xlnx,has-power = <0x0>;
> ++ xlnx,has-wp = <0x1>;
> ++};
> ++
> ++&usb0 {
> ++ dr_mode = "host";
> ++ phy_type = "ulpi";
> ++ status = "okay";
> ++ usb-reset = <&gpio0 7 0>; /* USB_RST_N-MIO7 */
> ++};
> ++
> ++&qspi {
> ++ u-boot,dm-pre-reloc;
> ++ status = "okay";
> ++ #address-cells = <1>;
> ++ #size-cells = <0>;
> ++ flash0: flash at 0 {
> ++ compatible = "micron,n25q128";
> ++ reg = <0x0>;
> ++ #address-cells = <1>;
> ++ #size-cells = <1>;
> ++ spi-max-frequency = <50000000>;
> ++ partition at 0x00000000 {
> ++ label = "boot";
> ++ reg = <0x00000000 0x00620000>;
> ++ };
> ++ partition at 0x00620000 {
> ++ label = "bootenv";
> ++ reg = <0x00620000 0x00020000>;
> ++ };
> ++ partition at 0x00640000 {
> ++ label = "kernel";
> ++ reg = <0x00640000 0x00960000>;
> ++ };
> ++ partition at 0x00fa0000 {
> ++ label = "spare";
> ++ reg = <0x00fa0000 0x00060000>;
> ++ };
> ++ };
> ++};
> +diff --git a/configs/zynq_minized_defconfig b/configs/zynq_minized_defconfig
> +new file mode 100644
> +index 0000000..5da9640
> +--- /dev/null
> ++++ b/configs/zynq_minized_defconfig
> +@@ -0,0 +1,56 @@
> ++CONFIG_ARM=y
> ++CONFIG_ARCH_ZYNQ=y
> ++CONFIG_SYS_TEXT_BASE=0x4000000
> ++CONFIG_DEFAULT_DEVICE_TREE="zynq-minized"
> ++CONFIG_SYS_NO_FLASH=y
> ++# CONFIG_DISPLAY_CPUINFO is not set
> ++CONFIG_SPL=y
> ++CONFIG_SPL_MTD_SUPPORT=y
> ++CONFIG_SPL_OS_BOOT=y
> ++CONFIG_HUSH_PARSER=y
> ++CONFIG_SYS_PROMPT="Zynq> "
> ++CONFIG_CMD_BOOTZ=y
> ++# CONFIG_CMD_IMLS is not set
> ++# CONFIG_CMD_FLASH is not set
> ++CONFIG_CMD_MMC=y
> ++CONFIG_CMD_SF=y
> ++CONFIG_CMD_SPI=y
> ++CONFIG_CMD_USB=y
> ++CONFIG_CMD_DFU=y
> ++CONFIG_CMD_GPIO=y
> ++# CONFIG_CMD_SETEXPR is not set
> ++# CONFIG_CMD_NET is not set
> ++# CONFIG_CMD_NFS is not set
> ++CONFIG_CMD_CACHE=y
> ++CONFIG_CMD_EXT2=y
> ++CONFIG_CMD_EXT4=y
> ++CONFIG_CMD_EXT4_WRITE=y
> ++CONFIG_CMD_FAT=y
> ++CONFIG_CMD_FS_GENERIC=y
> ++CONFIG_OF_EMBED=y
> ++CONFIG_SPL_DM_SEQ_ALIAS=y
> ++CONFIG_DFU_MMC=y
> ++CONFIG_DFU_RAM=y
> ++CONFIG_DM_GPIO=y
> ++CONFIG_DM_MMC=y
> ++CONFIG_ZYNQ_SDHCI=y
> ++CONFIG_MMC_SDHCI=y
> ++CONFIG_MTD=y
> ++CONFIG_CFI_FLASH=y
> ++CONFIG_SPI_FLASH=y
> ++CONFIG_SPI_FLASH_BAR=y
> ++CONFIG_SPI_FLASH_STMICRO=y
> ++CONFIG_ZYNQ_QSPI=y
> ++CONFIG_USB=y
> ++CONFIG_USB_EHCI_HCD=y
> ++CONFIG_USB_ULPI_VIEWPORT=y
> ++CONFIG_USB_ULPI=y
> ++CONFIG_USB_STORAGE=y
> ++CONFIG_USB_GADGET=y
> ++CONFIG_CI_UDC=y
> ++CONFIG_USB_GADGET_DOWNLOAD=y
> ++CONFIG_G_DNL_MANUFACTURER="Xilinx"
> ++CONFIG_G_DNL_VENDOR_NUM=0x03fd
> ++CONFIG_G_DNL_PRODUCT_NUM=0x0300
> ++CONFIG_REGEX=y
> ++CONFIG_LIB_RAND=y
> +--
> +2.7.4
> +
> diff --git a/meta-xilinx-contrib/recipes-bsp/u-boot/u-boot-xlnx_2017.3.bbappend
> b/meta-xilinx-contrib/recipes-bsp/u-boot/u-boot-xlnx_2017.3.bbappend
> new file mode 100644
> index 0000000..c5e3e95
> --- /dev/null
> +++ b/meta-xilinx-contrib/recipes-bsp/u-boot/u-boot-xlnx_2017.3.bbappend
> @@ -0,0 +1,8 @@
> +FILESEXTRAPATHS_prepend := "${THISDIR}/${PN}/v2017.3:"
> +
> +SRC_URI_append = "file://u-boot-minized.patch \
> + "
> +
> +# u-boot-xlnx compatible with MiniZed
> +HAS_PLATFORM_INIT += "zynq_minized_config"
> +
The u-boot patch should be upstreamed to mainline u-boot.
We cannot hold it in layers.
You could also check with Xilinx at git at xilinx.com for additional review comments on u-boot patch.
> diff --git a/meta-xilinx-contrib/recipes-connectivity/hostapd/hostapd/0001-
> murata-hostapd-conf.patch b/meta-xilinx-contrib/recipes-
> connectivity/hostapd/hostapd/0001-murata-hostapd-conf.patch
> new file mode 100644
> index 0000000..148fec2
> --- /dev/null
> +++ b/meta-xilinx-contrib/recipes-connectivity/hostapd/hostapd/0001-murata-
> hostapd-conf.patch
> @@ -0,0 +1,11 @@
> +diff -ur hostapd-2.6-original/hostapd/hostapd.conf hostapd-2.6-
> modified/hostapd/hostapd.conf
> +--- hostapd-2.6-original/hostapd/hostapd.conf 2016-10-02 13:51:11.000000000
> -0500
> ++++ hostapd-2.6-modified/hostapd/hostapd.conf 2017-12-05
> 15:02:29.842056615 -0600
> +@@ -25,6 +25,7 @@
> + # Use driver=none if building hostapd as a standalone RADIUS server that does
> + # not control any wireless/wired driver.
> + # driver=hostap
> ++driver=nl80211
> +
> + # Driver interface parameters (mainly for development testing use)
> + # driver_params=<params>
> diff --git a/meta-xilinx-contrib/recipes-connectivity/hostapd/hostapd_%.bbappend
> b/meta-xilinx-contrib/recipes-connectivity/hostapd/hostapd_%.bbappend
> new file mode 100644
> index 0000000..c4964cf
> --- /dev/null
> +++ b/meta-xilinx-contrib/recipes-connectivity/hostapd/hostapd_%.bbappend
> @@ -0,0 +1,5 @@
> +FILESEXTRAPATHS_prepend := "${THISDIR}/${PN}:"
> +
> +SRC_URI_append_minized-zynq7 = " file://0001-murata-hostapd-conf.patch"
> +
> +
> diff --git a/meta-xilinx-contrib/recipes-connectivity/wpa-supplicant/wpa-
> supplicant/0001-murata-wpa_supplication-Add-server-in-hs20.patch b/meta-
> xilinx-contrib/recipes-connectivity/wpa-supplicant/wpa-supplicant/0001-murata-
> wpa_supplication-Add-server-in-hs20.patch
> new file mode 100644
> index 0000000..8ff6e17
> --- /dev/null
> +++ b/meta-xilinx-contrib/recipes-connectivity/wpa-supplicant/wpa-
> supplicant/0001-murata-wpa_supplication-Add-server-in-hs20.patch
> @@ -0,0 +1,4575 @@
> +diff -urN awpa_supplicant-2.6-original/hs20/server/ca/clean.sh bwpa_supplicant-
> 2.6-patched-final/hs20/server/ca/clean.sh
> +--- awpa_supplicant-2.6-original/hs20/server/ca/clean.sh 1969-12-31
> 18:00:00.000000000 -0600
> ++++ bwpa_supplicant-2.6-patched-final/hs20/server/ca/clean.sh 2016-10-
> 02 13:51:11.000000000 -0500
> +@@ -0,0 +1,13 @@
> ++#!/bin/sh
> ++
> ++for i in server-client server server-revoked user ocsp; do
> ++ rm -f $i.csr $i.key $i.pem
> ++done
> ++
> ++rm -f openssl.cnf.tmp
> ++if [ -d demoCA ]; then
> ++ rm -r demoCA
> ++fi
> ++rm -f ca.pem logo.asn1 logo.der server.der ocsp-server-cache.der
> ++rm -f my-openssl.cnf my-openssl-root.cnf
> ++#rm -r rootCA
> +diff -urN awpa_supplicant-2.6-original/hs20/server/ca/est-csrattrs.cnf
> bwpa_supplicant-2.6-patched-final/hs20/server/ca/est-csrattrs.cnf
> +--- awpa_supplicant-2.6-original/hs20/server/ca/est-csrattrs.cnf 1969-12-
> 31 18:00:00.000000000 -0600
> ++++ bwpa_supplicant-2.6-patched-final/hs20/server/ca/est-csrattrs.cnf 2016-10-
> 02 13:51:11.000000000 -0500
> +@@ -0,0 +1,17 @@
> ++asn1 = SEQUENCE:attrs
> ++
> ++[attrs]
> ++#oid1 = OID:challengePassword
> ++attr1 = SEQUENCE:extreq
> ++oid2 = OID:sha256WithRSAEncryption
> ++
> ++[extreq]
> ++oid = OID:extensionRequest
> ++vals = SET:extreqvals
> ++
> ++[extreqvals]
> ++
> ++oid1 = OID:macAddress
> ++#oid2 = OID:imei
> ++#oid3 = OID:meid
> ++#oid4 = OID:DevId
> +diff -urN awpa_supplicant-2.6-original/hs20/server/ca/est-csrattrs.sh
> bwpa_supplicant-2.6-patched-final/hs20/server/ca/est-csrattrs.sh
> +--- awpa_supplicant-2.6-original/hs20/server/ca/est-csrattrs.sh 1969-12-31
> 18:00:00.000000000 -0600
> ++++ bwpa_supplicant-2.6-patched-final/hs20/server/ca/est-csrattrs.sh 2016-10-
> 02 13:51:11.000000000 -0500
> +@@ -0,0 +1,4 @@
> ++#!/bin/sh
> ++
> ++openssl asn1parse -genconf est-csrattrs.cnf -out est-csrattrs.der -oid hs20.oid
> ++base64 est-csrattrs.der > est-attrs.b64
> +diff -urN awpa_supplicant-2.6-original/hs20/server/ca/hs20.oid
> bwpa_supplicant-2.6-patched-final/hs20/server/ca/hs20.oid
> +--- awpa_supplicant-2.6-original/hs20/server/ca/hs20.oid 1969-12-31
> 18:00:00.000000000 -0600
> ++++ bwpa_supplicant-2.6-patched-final/hs20/server/ca/hs20.oid 2016-10-
> 02 13:51:11.000000000 -0500
> +@@ -0,0 +1,7 @@
> ++1.3.6.1.1.1.1.22 macAddress
> ++1.2.840.113549.1.9.14 extensionRequest
> ++1.3.6.1.4.1.40808.1.1.1 id-wfa-hotspot-friendlyName
> ++1.3.6.1.4.1.40808.1.1.2 id-kp-HS2.0Auth
> ++1.3.6.1.4.1.40808.1.1.3 imei
> ++1.3.6.1.4.1.40808.1.1.4 meid
> ++1.3.6.1.4.1.40808.1.1.5 DevId
> +diff -urN awpa_supplicant-2.6-original/hs20/server/ca/ocsp-req.sh
> bwpa_supplicant-2.6-patched-final/hs20/server/ca/ocsp-req.sh
> +--- awpa_supplicant-2.6-original/hs20/server/ca/ocsp-req.sh 1969-12-31
> 18:00:00.000000000 -0600
> ++++ bwpa_supplicant-2.6-patched-final/hs20/server/ca/ocsp-req.sh 2016-10-
> 02 13:51:11.000000000 -0500
> +@@ -0,0 +1,11 @@
> ++#!/bin/sh
> ++
> ++for i in *.pem; do
> ++ echo "===[ $i ]==================="
> ++ openssl ocsp -text -CAfile ca.pem -verify_other demoCA/cacert.pem -
> trust_other -issuer demoCA/cacert.pem -cert $i -url http://localhost:8888/
> ++
> ++# openssl ocsp -text -CAfile rootCA/cacert.pem -issuer demoCA/cacert.pem -
> cert $i -url http://localhost:8888/
> ++
> ++# openssl ocsp -text -CAfile rootCA/cacert.pem -verify_other
> demoCA/cacert.pem -trust_other -issuer demoCA/cacert.pem -cert $i -url
> http://localhost:8888/
> ++# openssl ocsp -text -CAfile rootCA/cacert.pem -VAfile ca.pem -trust_other -
> issuer demoCA/cacert.pem -cert $i -url http://localhost:8888/
> ++done
> +diff -urN awpa_supplicant-2.6-original/hs20/server/ca/ocsp-responder-ica.sh
> bwpa_supplicant-2.6-patched-final/hs20/server/ca/ocsp-responder-ica.sh
> +--- awpa_supplicant-2.6-original/hs20/server/ca/ocsp-responder-ica.sh 1969-12-
> 31 18:00:00.000000000 -0600
> ++++ bwpa_supplicant-2.6-patched-final/hs20/server/ca/ocsp-responder-ica.sh
> 2016-10-02 13:51:11.000000000 -0500
> +@@ -0,0 +1,3 @@
> ++#!/bin/sh
> ++
> ++openssl ocsp -index demoCA/index.txt -port 8888 -nmin 5 -rsigner
> demoCA/cacert.pem -rkey demoCA/private/cakey-plain.pem -CA
> demoCA/cacert.pem -resp_no_certs -text
> +diff -urN awpa_supplicant-2.6-original/hs20/server/ca/ocsp-responder.sh
> bwpa_supplicant-2.6-patched-final/hs20/server/ca/ocsp-responder.sh
> +--- awpa_supplicant-2.6-original/hs20/server/ca/ocsp-responder.sh 1969-12-
> 31 18:00:00.000000000 -0600
> ++++ bwpa_supplicant-2.6-patched-final/hs20/server/ca/ocsp-responder.sh
> 2016-10-02 13:51:11.000000000 -0500
> +@@ -0,0 +1,3 @@
> ++#!/bin/sh
> ++
> ++openssl ocsp -index demoCA/index.txt -port 8888 -nmin 5 -rsigner ocsp.pem -
> rkey ocsp.key -CA demoCA/cacert.pem -text
> +diff -urN awpa_supplicant-2.6-original/hs20/server/ca/ocsp-update-cache.sh
> bwpa_supplicant-2.6-patched-final/hs20/server/ca/ocsp-update-cache.sh
> +--- awpa_supplicant-2.6-original/hs20/server/ca/ocsp-update-cache.sh 1969-12-
> 31 18:00:00.000000000 -0600
> ++++ bwpa_supplicant-2.6-patched-final/hs20/server/ca/ocsp-update-cache.sh
> 2016-10-02 13:51:11.000000000 -0500
> +@@ -0,0 +1,10 @@
> ++#!/bin/sh
> ++
> ++openssl ocsp \
> ++ -no_nonce \
> ++ -CAfile ca.pem \
> ++ -verify_other demoCA/cacert.pem \
> ++ -issuer demoCA/cacert.pem \
> ++ -cert server.pem \
> ++ -url http://localhost:8888/ \
> ++ -respout ocsp-server-cache.der
> +diff -urN awpa_supplicant-2.6-original/hs20/server/ca/openssl.cnf
> bwpa_supplicant-2.6-patched-final/hs20/server/ca/openssl.cnf
> +--- awpa_supplicant-2.6-original/hs20/server/ca/openssl.cnf 1969-12-31
> 18:00:00.000000000 -0600
> ++++ bwpa_supplicant-2.6-patched-final/hs20/server/ca/openssl.cnf 2016-10-
> 02 13:51:11.000000000 -0500
> +@@ -0,0 +1,200 @@
> ++# OpenSSL configuration file for Hotspot 2.0 PKI (Intermediate CA)
> ++
> ++HOME = .
> ++RANDFILE = $ENV::HOME/.rnd
> ++oid_section = new_oids
> ++
> ++[ new_oids ]
> ++
> ++#logotypeoid=1.3.6.1.5.5.7.1.12
> ++
> ++####################################################################
> ++[ ca ]
> ++default_ca = CA_default # The default ca section
> ++
> ++####################################################################
> ++[ CA_default ]
> ++
> ++dir = ./demoCA # Where everything is kept
> ++certs = $dir/certs # Where the issued certs are kept
> ++crl_dir = $dir/crl # Where the issued crl are kept
> ++database = $dir/index.txt # database index file.
> ++#unique_subject = no # Set to 'no' to allow creation of
> ++ # several certificates with same subject
> ++new_certs_dir = $dir/newcerts # default place for new certs.
> ++
> ++certificate = $dir/cacert.pem # The CA certificate
> ++serial = $dir/serial # The current serial number
> ++crlnumber = $dir/crlnumber # the current crl number
> ++ # must be commented out to leave a V1
> CRL
> ++crl = $dir/crl.pem # The current CRL
> ++private_key = $dir/private/cakey.pem# The private key
> ++RANDFILE = $dir/private/.rand # private random number file
> ++
> ++x509_extensions = ext_client # The extentions to add to the cert
> ++
> ++name_opt = ca_default # Subject Name options
> ++cert_opt = ca_default # Certificate field options
> ++
> ++# Extension copying option: use with caution.
> ++copy_extensions = copy
> ++
> ++default_days = 365 # how long to certify for
> ++default_crl_days= 30 # how long before next CRL
> ++default_md = default # use public key default MD
> ++preserve = no # keep passed DN ordering
> ++
> ++policy = policy_match
> ++
> ++# For the CA policy
> ++[ policy_match ]
> ++countryName = supplied
> ++stateOrProvinceName = optional
> ++organizationName = supplied
> ++organizationalUnitName = optional
> ++commonName = supplied
> ++emailAddress = optional
> ++
> ++[ policy_osu_server ]
> ++countryName = match
> ++stateOrProvinceName = optional
> ++organizationName = match
> ++organizationalUnitName = supplied
> ++commonName = supplied
> ++emailAddress = optional
> ++
> ++[ policy_anything ]
> ++countryName = optional
> ++stateOrProvinceName = optional
> ++localityName = optional
> ++organizationName = optional
> ++organizationalUnitName = optional
> ++commonName = supplied
> ++emailAddress = optional
> ++
> ++####################################################################
> ++[ req ]
> ++default_bits = 2048
> ++default_keyfile = privkey.pem
> ++distinguished_name = req_distinguished_name
> ++attributes = req_attributes
> ++x509_extensions = v3_ca # The extentions to add to the self signed cert
> ++
> ++input_password = @PASSWORD@
> ++output_password = @PASSWORD@
> ++
> ++string_mask = utf8only
> ++
> ++[ req_distinguished_name ]
> ++countryName = Country Name (2 letter code)
> ++countryName_default = FI
> ++countryName_min = 2
> ++countryName_max = 2
> ++
> ++localityName = Locality Name (eg, city)
> ++localityName_default = Tuusula
> ++
> ++0.organizationName = Organization Name (eg, company)
> ++0.organizationName_default = @DOMAIN@
> ++
> ++##organizationalUnitName = Organizational Unit Name (eg, section)
> ++#organizationalUnitName_default =
> ++#@OU@
> ++
> ++commonName = Common Name (e.g. server FQDN or
> YOUR name)
> ++#@CN@
> ++commonName_max = 64
> ++
> ++emailAddress = Email Address
> ++emailAddress_max = 64
> ++
> ++[ req_attributes ]
> ++
> ++[ v3_ca ]
> ++
> ++# Hotspot 2.0 PKI requirements
> ++subjectKeyIdentifier=hash
> ++authorityKeyIdentifier=keyid:always,issuer
> ++basicConstraints = critical, CA:true, pathlen:0
> ++keyUsage = critical, cRLSign, keyCertSign
> ++authorityInfoAccess = OCSP;URI:@OCSP_URI@
> ++# For SP intermediate CA
> ++#subjectAltName=critical,otherName:1.3.6.1.4.1.40808.1.1.1;UTF8String:engEx
> ample OSU
> ++#nameConstraints=permitted;DNS:. at DOMAIN@
> ++#1.3.6.1.5.5.7.1.12=ASN1:SEQUENCE:LogotypeExtn
> ++
> ++[ v3_osu_server ]
> ++
> ++basicConstraints = critical, CA:true, pathlen:0
> ++keyUsage = critical, keyEncipherment
> ++#@ALTNAME@
> ++
> ++#logotypeoid=ASN1:SEQUENCE:LogotypeExtn
> ++1.3.6.1.5.5.7.1.12=ASN1:SEQUENCE:LogotypeExtn
> ++[LogotypeExtn]
> ++communityLogos=EXP:0,SEQUENCE:LogotypeInfo
> ++[LogotypeInfo]
> ++# note: implicit tag converted to explicit for CHOICE
> ++direct=EXP:0,SEQUENCE:LogotypeData
> ++[LogotypeData]
> ++image=SEQUENCE:LogotypeImage
> ++[LogotypeImage]
> ++imageDetails=SEQUENCE:LogotypeDetails
> ++imageInfo=SEQUENCE:LogotypeImageInfo
> ++[LogotypeDetails]
> ++mediaType=IA5STRING:image/png
> ++logotypeHash=SEQUENCE:HashAlgAndValues
> ++logotypeURI=SEQUENCE:URI
> ++[HashAlgAndValues]
> ++value1=SEQUENCE:HashAlgAndValueSHA256
> ++#value2=SEQUENCE:HashAlgAndValueSHA1
> ++[HashAlgAndValueSHA256]
> ++hashAlg=SEQUENCE:sha256_alg
> ++hashValue=FORMAT:HEX,OCTETSTRING:@LOGO_HASH256@
> ++[HashAlgAndValueSHA1]
> ++hashAlg=SEQUENCE:sha1_alg
> ++hashValue=FORMAT:HEX,OCTETSTRING:@LOGO_HASH1@
> ++[sha256_alg]
> ++algorithm=OID:sha256
> ++[sha1_alg]
> ++algorithm=OID:sha1
> ++[URI]
> ++uri=IA5STRING:@LOGO_URI@
> ++[LogotypeImageInfo]
> ++# default value color(1), component optional
> ++#type=IMP:0,INTEGER:1
> ++fileSize=INTEGER:7549
> ++xSize=INTEGER:128
> ++ySize=INTEGER:80
> ++language=IMP:4,IA5STRING:zxx
> ++
> ++[ crl_ext ]
> ++
> ++# issuerAltName=issuer:copy
> ++authorityKeyIdentifier=keyid:always
> ++
> ++[ v3_OCSP ]
> ++
> ++basicConstraints = CA:FALSE
> ++keyUsage = nonRepudiation, digitalSignature, keyEncipherment
> ++extendedKeyUsage = OCSPSigning
> ++
> ++[ ext_client ]
> ++
> ++basicConstraints=CA:FALSE
> ++subjectKeyIdentifier=hash
> ++authorityKeyIdentifier=keyid,issuer
> ++authorityInfoAccess = OCSP;URI:@OCSP_URI@
> ++#@ALTNAME@
> ++extendedKeyUsage = clientAuth
> ++
> ++[ ext_server ]
> ++
> ++# Hotspot 2.0 PKI requirements
> ++basicConstraints=critical, CA:FALSE
> ++subjectKeyIdentifier=hash
> ++authorityKeyIdentifier=keyid,issuer
> ++authorityInfoAccess = OCSP;URI:@OCSP_URI@
> ++#@ALTNAME@
> ++extendedKeyUsage = critical, serverAuth
> ++keyUsage = critical, keyEncipherment
> +diff -urN awpa_supplicant-2.6-original/hs20/server/ca/openssl-root.cnf
> bwpa_supplicant-2.6-patched-final/hs20/server/ca/openssl-root.cnf
> +--- awpa_supplicant-2.6-original/hs20/server/ca/openssl-root.cnf 1969-12-
> 31 18:00:00.000000000 -0600
> ++++ bwpa_supplicant-2.6-patched-final/hs20/server/ca/openssl-root.cnf
> 2016-10-02 13:51:11.000000000 -0500
> +@@ -0,0 +1,125 @@
> ++# OpenSSL configuration file for Hotspot 2.0 PKI (Root CA)
> ++
> ++HOME = .
> ++RANDFILE = $ENV::HOME/.rnd
> ++oid_section = new_oids
> ++
> ++[ new_oids ]
> ++
> ++#logotypeoid=1.3.6.1.5.5.7.1.12
> ++
> ++####################################################################
> ++[ ca ]
> ++default_ca = CA_default # The default ca section
> ++
> ++####################################################################
> ++[ CA_default ]
> ++
> ++dir = ./rootCA # Where everything is kept
> ++certs = $dir/certs # Where the issued certs are kept
> ++crl_dir = $dir/crl # Where the issued crl are kept
> ++database = $dir/index.txt # database index file.
> ++#unique_subject = no # Set to 'no' to allow creation of
> ++ # several certificates with same subject
> ++new_certs_dir = $dir/newcerts # default place for new certs.
> ++
> ++certificate = $dir/cacert.pem # The CA certificate
> ++serial = $dir/serial # The current serial number
> ++crlnumber = $dir/crlnumber # the current crl number
> ++ # must be commented out to leave a V1
> CRL
> ++crl = $dir/crl.pem # The current CRL
> ++private_key = $dir/private/cakey.pem# The private key
> ++RANDFILE = $dir/private/.rand # private random number file
> ++
> ++x509_extensions = usr_cert # The extentions to add to the cert
> ++
> ++name_opt = ca_default # Subject Name options
> ++cert_opt = ca_default # Certificate field options
> ++
> ++default_days = 365 # how long to certify for
> ++default_crl_days= 30 # how long before next CRL
> ++default_md = default # use public key default MD
> ++preserve = no # keep passed DN ordering
> ++
> ++policy = policy_match
> ++
> ++# For the CA policy
> ++[ policy_match ]
> ++countryName = match
> ++stateOrProvinceName = optional
> ++organizationName = match
> ++organizationalUnitName = optional
> ++commonName = supplied
> ++emailAddress = optional
> ++
> ++[ policy_anything ]
> ++countryName = optional
> ++stateOrProvinceName = optional
> ++localityName = optional
> ++organizationName = optional
> ++organizationalUnitName = optional
> ++commonName = supplied
> ++emailAddress = optional
> ++
> ++####################################################################
> ++[ req ]
> ++default_bits = 2048
> ++default_keyfile = privkey.pem
> ++distinguished_name = req_distinguished_name
> ++attributes = req_attributes
> ++x509_extensions = v3_ca # The extentions to add to the self signed cert
> ++
> ++input_password = @PASSWORD@
> ++output_password = @PASSWORD@
> ++
> ++string_mask = utf8only
> ++
> ++[ req_distinguished_name ]
> ++countryName = Country Name (2 letter code)
> ++countryName_default = US
> ++countryName_min = 2
> ++countryName_max = 2
> ++
> ++localityName = Locality Name (eg, city)
> ++localityName_default = Tuusula
> ++
> ++0.organizationName = Organization Name (eg, company)
> ++0.organizationName_default = WFA Hotspot 2.0
> ++
> ++##organizationalUnitName = Organizational Unit Name (eg, section)
> ++#organizationalUnitName_default =
> ++#@OU@
> ++
> ++commonName = Common Name (e.g. server FQDN or
> YOUR name)
> ++#@CN@
> ++commonName_max = 64
> ++
> ++emailAddress = Email Address
> ++emailAddress_max = 64
> ++
> ++[ req_attributes ]
> ++
> ++[ v3_req ]
> ++
> ++# Extensions to add to a certificate request
> ++basicConstraints = CA:FALSE
> ++keyUsage = nonRepudiation, digitalSignature, keyEncipherment
> ++subjectAltName=DNS:example.com,DNS:another.example.com
> ++
> ++[ v3_ca ]
> ++
> ++# Hotspot 2.0 PKI requirements
> ++subjectKeyIdentifier=hash
> ++basicConstraints = critical,CA:true
> ++keyUsage = critical, cRLSign, keyCertSign
> ++
> ++[ crl_ext ]
> ++
> ++# issuerAltName=issuer:copy
> ++authorityKeyIdentifier=keyid:always
> ++
> ++[ v3_OCSP ]
> ++
> ++basicConstraints = CA:FALSE
> ++keyUsage = nonRepudiation, digitalSignature, keyEncipherment
> ++extendedKeyUsage = OCSPSigning
> +diff -urN awpa_supplicant-2.6-original/hs20/server/ca/setup.sh
> bwpa_supplicant-2.6-patched-final/hs20/server/ca/setup.sh
> +--- awpa_supplicant-2.6-original/hs20/server/ca/setup.sh 1969-12-31
> 18:00:00.000000000 -0600
> ++++ bwpa_supplicant-2.6-patched-final/hs20/server/ca/setup.sh 2016-10-
> 02 13:51:11.000000000 -0500
> +@@ -0,0 +1,209 @@
> ++#!/bin/sh
> ++
> ++if [ -z "$OPENSSL" ]; then
> ++ OPENSSL=openssl
> ++fi
> ++export OPENSSL_CONF=$PWD/openssl.cnf
> ++PASS=whatever
> ++if [ -z "$DOMAIN" ]; then
> ++ DOMAIN=w1.fi
> ++fi
> ++COMPANY=w1.fi
> ++OPER_ENG="engw1.fi TESTING USE"
> ++OPER_FI="finw1.fi TESTIKÄYTTÖ"
> ++CNR="Hotspot 2.0 Trust Root CA - 99"
> ++CNO="ocsp.$DOMAIN"
> ++CNV="osu-revoked.$DOMAIN"
> ++CNOC="osu-client.$DOMAIN"
> ++OSU_SERVER_HOSTNAME="osu.$DOMAIN"
> ++DEBUG=0
> ++OCSP_URI="http://$CNO:8888/"
> ++LOGO_URI="http://osu.w1.fi/w1fi_logo.png"
> ++LOGO_HASH256="4532f7ec36424381617c03c6ce87b55a51d6e7177ffafda243
> cebf280a68954d"
> ++LOGO_HASH1="5e1d5085676eede6b02da14d31c523ec20ffba0b"
> ++
> ++# Command line overrides
> ++USAGE=$( cat <<EOF
> ++Usage:\n
> ++# -c: Company name, used to generate Subject name CN for Intermediate CA\n
> ++# -C: Subject name CN of the Root CA ($CNR)\n
> ++# -D: Enable debugging (set -x, etc)\n
> ++# -g: Logo sha1 hash ($LOGO_HASH1)\n
> ++# -G: Logo sha256 hash ($LOGO_HASH256)\n
> ++# -h: Show this help message\n
> ++# -l: Logo URI ($LOGO_URI)\n
> ++# -m: Domain ($DOMAIN)\n
> ++# -o: Subject name CN for OSU-Client Server ($CNOC)\n
> ++# -O: Subject name CN for OCSP Server ($CNO)\n
> ++# -p: passphrase for private keys ($PASS)\n
> ++# -r: Operator-english ($OPER_ENG)\n
> ++# -R: Operator-finish ($OPER_FI)\n
> ++# -S: OSU Server name ($OSU_SERVER_HOSTNAME)\n
> ++# -u: OCSP-URI ($OCSP_URI)\n
> ++# -V: Subject name CN for OSU-Revoked Server ($CNV)\n
> ++EOF
> ++)
> ++
> ++while getopts "c:C:Dg:G:l:m:o:O:p:r:R:S:u:V:h" flag
> ++ do
> ++ case $flag in
> ++ c) COMPANY=$OPTARG;;
> ++ C) CNR=$OPTARG;;
> ++ D) DEBUG=1;;
> ++ g) LOGO_HASH1=$OPTARG;;
> ++ G) LOGO_HASH256=$OPTARG;;
> ++ h) echo -e $USAGE; exit 0;;
> ++ l) LOGO_URI=$OPTARG;;
> ++ m) DOMAIN=$OPTARG;;
> ++ o) CNOC=$OPTARG;;
> ++ O) CNO=$OPTARG;;
> ++ p) PASS=$OPTARG;;
> ++ r) OPER_ENG=$OPTARG;;
> ++ R) OPER_FI=$OPTARG;;
> ++ S) OSU_SERVER_HOSTNAME=$OPTARG;;
> ++ u) OCSP_URI=$OPTARG;;
> ++ V) CNV=$OPTARG;;
> ++ *) echo "Unknown flag: $flag"; echo -e $USAGE; exit 1;;
> ++ esac
> ++done
> ++
> ++fail()
> ++{
> ++ echo "$*"
> ++ exit 1
> ++}
> ++
> ++echo
> ++echo "---[ Root CA ]----------------------------------------------------------"
> ++echo
> ++
> ++if [ $DEBUG = 1 ]
> ++then
> ++ set -x
> ++fi
> ++
> ++# Set the passphrase and some other common config accordingly.
> ++cat openssl-root.cnf | sed "s/@PASSWORD@/$PASS/" \
> ++ > my-openssl-root.cnf
> ++
> ++cat openssl.cnf | sed "s/@PASSWORD@/$PASS/" |
> ++sed "s, at OCSP_URI@,$OCSP_URI," |
> ++sed "s, at LOGO_URI@,$LOGO_URI," |
> ++sed "s, at LOGO_HASH1@,$LOGO_HASH1," |
> ++sed "s, at LOGO_HASH256@,$LOGO_HASH256," |
> ++sed "s/@DOMAIN@/$DOMAIN/" \
> ++ > my-openssl.cnf
> ++
> ++
> ++cat my-openssl-root.cnf | sed "s/#@CN@/commonName_default = $CNR/" >
> openssl.cnf.tmp
> ++mkdir -p rootCA/certs rootCA/crl rootCA/newcerts rootCA/private
> ++touch rootCA/index.txt
> ++if [ -e rootCA/private/cakey.pem ]; then
> ++ echo " * Use existing Root CA"
> ++else
> ++ echo " * Generate Root CA private key"
> ++ $OPENSSL req -config openssl.cnf.tmp -batch -new -newkey rsa:4096 -keyout
> rootCA/private/cakey.pem -out rootCA/careq.pem || fail "Failed to generate Root
> CA private key"
> ++ echo " * Sign Root CA certificate"
> ++ $OPENSSL ca -config openssl.cnf.tmp -md sha256 -create_serial -out
> rootCA/cacert.pem -days 10957 -batch -keyfile rootCA/private/cakey.pem -passin
> pass:$PASS -selfsign -extensions v3_ca -outdir rootCA/newcerts -infiles
> rootCA/careq.pem || fail "Failed to sign Root CA certificate"
> ++ $OPENSSL x509 -in rootCA/cacert.pem -out rootCA/cacert.der -outform DER
> || fail "Failed to create rootCA DER"
> ++ sha256sum rootCA/cacert.der > rootCA/cacert.fingerprint || fail "Failed to
> create rootCA fingerprint"
> ++fi
> ++if [ ! -e rootCA/crlnumber ]; then
> ++ echo 00 > rootCA/crlnumber
> ++fi
> ++
> ++echo
> ++echo "---[ Intermediate CA ]--------------------------------------------------"
> ++echo
> ++
> ++cat my-openssl.cnf | sed "s/#@CN@/commonName_default = $COMPANY
> Hotspot 2.0 Intermediate CA/" > openssl.cnf.tmp
> ++mkdir -p demoCA/certs demoCA/crl demoCA/newcerts demoCA/private
> ++touch demoCA/index.txt
> ++if [ -e demoCA/private/cakey.pem ]; then
> ++ echo " * Use existing Intermediate CA"
> ++else
> ++ echo " * Generate Intermediate CA private key"
> ++ $OPENSSL req -config openssl.cnf.tmp -batch -new -newkey rsa:2048 -keyout
> demoCA/private/cakey.pem -out demoCA/careq.pem || fail "Failed to generate
> Intermediate CA private key"
> ++ echo " * Sign Intermediate CA certificate"
> ++ $OPENSSL ca -config openssl.cnf.tmp -md sha256 -create_serial -out
> demoCA/cacert.pem -days 3652 -batch -keyfile rootCA/private/cakey.pem -cert
> rootCA/cacert.pem -passin pass:$PASS -extensions v3_ca -infiles
> demoCA/careq.pem || fail "Failed to sign Intermediate CA certificate"
> ++ # horrible from security view point, but for testing purposes since OCSP
> responder does not seem to support -passin
> ++ openssl rsa -in demoCA/private/cakey.pem -out demoCA/private/cakey-
> plain.pem -passin pass:$PASS
> ++ $OPENSSL x509 -in demoCA/cacert.pem -out demoCA/cacert.der -outform
> DER || fail "Failed to create demoCA DER."
> ++ sha256sum demoCA/cacert.der > demoCA/cacert.fingerprint || fail "Failed to
> create demoCA fingerprint"
> ++fi
> ++if [ ! -e demoCA/crlnumber ]; then
> ++ echo 00 > demoCA/crlnumber
> ++fi
> ++
> ++echo
> ++echo "OCSP responder"
> ++echo
> ++
> ++cat my-openssl.cnf | sed "s/#@CN@/commonName_default = $CNO/" >
> openssl.cnf.tmp
> ++$OPENSSL req -config $PWD/openssl.cnf.tmp -batch -new -newkey rsa:2048 -
> nodes -out ocsp.csr -keyout ocsp.key -extensions v3_OCSP
> ++$OPENSSL ca -config $PWD/openssl.cnf.tmp -batch -md sha256 -keyfile
> demoCA/private/cakey.pem -passin pass:$PASS -in ocsp.csr -out ocsp.pem -days
> 730 -extensions v3_OCSP || fail "Could not generate ocsp.pem"
> ++
> ++echo
> ++echo "---[ Server - to be revoked ] ------------------------------------------"
> ++echo
> ++
> ++cat my-openssl.cnf | sed "s/#@CN@/commonName_default = $CNV/" >
> openssl.cnf.tmp
> ++$OPENSSL req -config $PWD/openssl.cnf.tmp -batch -new -newkey rsa:2048 -
> nodes -out server-revoked.csr -keyout server-revoked.key
> ++$OPENSSL ca -config $PWD/openssl.cnf.tmp -batch -md sha256 -in server-
> revoked.csr -out server-revoked.pem -key $PASS -days 730 -extensions ext_server
> ++$OPENSSL ca -revoke server-revoked.pem -key $PASS
> ++
> ++echo
> ++echo "---[ Server - with client ext key use ] ---------------------------------"
> ++echo "---[ Only used for negative-testing for OSU-client implementation ] -----"
> ++echo
> ++
> ++cat my-openssl.cnf | sed "s/#@CN@/commonName_default = $CNOC/" >
> openssl.cnf.tmp
> ++$OPENSSL req -config $PWD/openssl.cnf.tmp -batch -new -newkey rsa:2048 -
> nodes -out server-client.csr -keyout server-client.key || fail "Could not create
> server-client.key"
> ++$OPENSSL ca -config $PWD/openssl.cnf.tmp -batch -md sha256 -in server-
> client.csr -out server-client.pem -key $PASS -days 730 -extensions ext_client || fail
> "Could not create server-client.pem"
> ++
> ++echo
> ++echo "---[ User ]-------------------------------------------------------------"
> ++echo
> ++
> ++cat my-openssl.cnf | sed "s/#@CN@/commonName_default = User/" >
> openssl.cnf.tmp
> ++$OPENSSL req -config $PWD/openssl.cnf.tmp -batch -new -newkey rsa:2048 -
> nodes -out user.csr -keyout user.key || fail "Could not create user.key"
> ++$OPENSSL ca -config $PWD/openssl.cnf.tmp -batch -md sha256 -in user.csr -out
> user.pem -key $PASS -days 730 -extensions ext_client || fail "Could not create
> user.pem"
> ++
> ++echo
> ++echo "---[ Server ]-----------------------------------------------------------"
> ++echo
> ++
> ++ALT="DNS:$OSU_SERVER_HOSTNAME"
> ++ALT="$ALT,otherName:1.3.6.1.4.1.40808.1.1.1;UTF8String:$OPER_ENG"
> ++ALT="$ALT,otherName:1.3.6.1.4.1.40808.1.1.1;UTF8String:$OPER_FI"
> ++
> ++cat my-openssl.cnf |
> ++ sed "s/#@CN@/commonName_default = $OSU_SERVER_HOSTNAME/" |
> ++ sed "s/^##organizationalUnitName/organizationalUnitName/" |
> ++ sed "s/#@OU@/organizationalUnitName_default = Hotspot 2.0 Online
> Sign Up Server/" |
> ++ sed "s/#@ALTNAME@/subjectAltName=critical,$ALT/" \
> ++ > openssl.cnf.tmp
> ++echo $OPENSSL req -config $PWD/openssl.cnf.tmp -batch -sha256 -new -
> newkey rsa:2048 -nodes -out server.csr -keyout server.key -reqexts v3_osu_server
> ++$OPENSSL req -config $PWD/openssl.cnf.tmp -batch -sha256 -new -newkey
> rsa:2048 -nodes -out server.csr -keyout server.key -reqexts v3_osu_server || fail
> "Failed to generate server request"
> ++$OPENSSL ca -config $PWD/openssl.cnf.tmp -batch -md sha256 -in server.csr -
> out server.pem -key $PASS -days 730 -extensions ext_server -policy
> policy_osu_server || fail "Failed to sign server certificate"
> ++
> ++#dump logotype details for debugging
> ++$OPENSSL x509 -in server.pem -out server.der -outform DER
> ++openssl asn1parse -in server.der -inform DER | grep HEX | tail -1 | sed 's/.*://' |
> xxd -r -p > logo.der
> ++openssl asn1parse -in logo.der -inform DER > logo.asn1
> ++
> ++
> ++echo
> ++echo "---[ CRL ]---------------------------------------------------------------"
> ++echo
> ++
> ++$OPENSSL ca -config $PWD/my-openssl.cnf -gencrl -md sha256 -out
> demoCA/crl/crl.pem -passin pass:$PASS
> ++
> ++echo
> ++echo "---[ Verify ]------------------------------------------------------------"
> ++echo
> ++
> ++$OPENSSL verify -CAfile rootCA/cacert.pem demoCA/cacert.pem
> ++$OPENSSL verify -CAfile rootCA/cacert.pem -untrusted demoCA/cacert.pem
> *.pem
> ++
> ++cat rootCA/cacert.pem demoCA/cacert.pem > ca.pem
> +Binary files awpa_supplicant-2.6-original/hs20/server/ca/w1fi_logo.png and
> bwpa_supplicant-2.6-patched-final/hs20/server/ca/w1fi_logo.png differ
> +diff -urN awpa_supplicant-2.6-original/hs20/server/hs20-osu-server.txt
> bwpa_supplicant-2.6-patched-final/hs20/server/hs20-osu-server.txt
> +--- awpa_supplicant-2.6-original/hs20/server/hs20-osu-server.txt 1969-12-
> 31 18:00:00.000000000 -0600
> ++++ bwpa_supplicant-2.6-patched-final/hs20/server/hs20-osu-server.txt
> 2016-10-02 13:51:11.000000000 -0500
> +@@ -0,0 +1,257 @@
> ++Hotspot 2.0 OSU server
> ++======================
> ++
> ++The information in this document is based on the assumption that Ubuntu
> ++12.04 server (64-bit) distribution is used and the web server is
> ++Apache2. Neither of these are requirements for the installation, but if
> ++other combinations are used, the package names and configuration
> ++parameters may need to be adjusted.
> ++
> ++NOTE: This implementation and the example configuration here is meant
> ++only for testing purposes in a lab environment. This design is not
> ++secure to be installed in a publicly available Internet server without
> ++considerable amount of modification and review for security issues.
> ++
> ++NOTE: While this describes use on Ubuntu 12.04, the version of Apache2
> ++included in that distribution is not new enough to support all OSU
> ++server validation steps. In other words, it may be most adapt the steps
> ++described here to Ubuntu 13.10.
> ++
> ++
> ++Build dependencies
> ++------------------
> ++
> ++Ubuntu 12.04 server
> ++- default installation
> ++- upgraded to latest package versions
> ++ sudo apt-get update
> ++ sudo apt-get upgrade
> ++
> ++Packages needed for running the service:
> ++ sudo apt-get install sqlite3
> ++ sudo apt-get install apache2
> ++ sudo apt-get install php5-sqlite libapache2-mod-php5
> ++
> ++Additional packages needed for building the components:
> ++ sudo apt-get install build-essential
> ++ sudo apt-get install libsqlite3-dev
> ++ sudo apt-get install libssl-dev
> ++ sudo apt-get install libxml2-dev
> ++
> ++
> ++Installation location
> ++---------------------
> ++
> ++Select a location for the installation root directory. The example here
> ++assumes /home/user/hs20-server to be used, but this can be changed by
> ++editing couple of files as indicated below.
> ++
> ++sudo mkdir -p /home/user/hs20-server
> ++sudo chown $USER /home/user/hs20-server
> ++mkdir -p /home/user/hs20-server/spp
> ++mkdir -p /home/user/hs20-server/AS
> ++
> ++
> ++Build
> ++-----
> ++
> ++# hostapd as RADIUS server
> ++cd hostapd
> ++
> ++#example build configuration
> ++cat > .config <<EOF
> ++CONFIG_DRIVER_NONE=y
> ++CONFIG_PKCS12=y
> ++CONFIG_RADIUS_SERVER=y
> ++CONFIG_EAP=y
> ++CONFIG_EAP_TLS=y
> ++CONFIG_EAP_MSCHAPV2=y
> ++CONFIG_EAP_PEAP=y
> ++CONFIG_EAP_GTC=y
> ++CONFIG_EAP_TTLS=y
> ++CONFIG_EAP_SIM=y
> ++CONFIG_EAP_AKA=y
> ++CONFIG_EAP_AKA_PRIME=y
> ++CONFIG_SQLITE=y
> ++CONFIG_HS20=y
> ++EOF
> ++
> ++make hostapd hlr_auc_gw
> ++cp hostapd hlr_auc_gw /home/user/hs20-server/AS
> ++
> ++# build hs20_spp_server
> ++cd ../hs20/server
> ++make clean
> ++make
> ++cp hs20_spp_server /home/user/hs20-server/spp
> ++# prepare database (web server user/group needs to have write access)
> ++mkdir -p /home/user/hs20-server/AS/DB
> ++sudo chgrp www-data /home/user/hs20-server/AS/DB
> ++sudo chmod g+w /home/user/hs20-server/AS/DB
> ++sqlite3 /home/user/hs20-server/AS/DB/eap_user.db < sql.txt
> ++sudo chgrp www-data /home/user/hs20-server/AS/DB/eap_user.db
> ++sudo chmod g+w /home/user/hs20-server/AS/DB/eap_user.db
> ++# add example configuration (note: need to update URLs to match the system)
> ++sqlite3 /home/user/hs20-server/AS/DB/eap_user.db < sql-example.txt
> ++
> ++# copy PHP scripts
> ++# Modify config.php if different installation directory is used.
> ++# Modify PHP scripts to get the desired behavior for user interaction (or use
> ++# the examples as-is for initial testing).
> ++cp -r www /home/user/hs20-server
> ++
> ++# 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" -d $old_hostname \
> ++ -I "Hotspot 2.0 Intermediate 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 <<EOF
> ++<Policy>
> ++ <PolicyUpdate>
> ++ <UpdateInterval>30</UpdateInterval>
> ++ <UpdateMethod>ClientInitiated</UpdateMethod>
> ++ <Restriction>Unrestricted</Restriction>
> ++ <URI>https://policy-server.osu.example.com/hs20/spp.php</URI>
> ++ </PolicyUpdate>
> ++</Policy>
> ++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 <<EOF
> ++driver=none
> ++radius_server_clients=as.radius_clients
> ++eap_server=1
> ++eap_user_file=sqlite:DB/eap_user.db
> ++ca_cert=Key/ca.pem
> ++server_cert=Key/server.pem
> ++private_key=Key/server.key
> ++private_key_passwd=passphrase
> ++eap_sim_db=unix:/tmp/hlr_auc_gw.sock db=eap_sim.db
> ++subscr_remediation_url=https://subscription-
> server.osu.example.com/hs20/spp.php
> ++EOF
> ++
> ++# Set RADIUS passphrase for the APs
> ++# Note: Modify to match the setup
> ++cat > /home/user/hs20-server/AS/as.radius_clients <<EOF
> ++0.0.0.0/0 radius
> ++EOF
> ++
> ++
> ++Start RADIUS authentication server
> ++----------------------------------
> ++
> ++cd /home/user/hs20-server/AS
> ++./hostapd -B as-sql.conf
> ++
> ++
> ++OSEN RADIUS server configuration notes
> ++
> ++The OSEN RADIUS server config file should have the 'ocsp_stapling_response'
> ++configuration in it. For example:
> ++
> ++# hostapd-radius config for the radius used by the OSEN AP
> ++interface=eth0#0
> ++driver=none
> ++logger_syslog=-1
> ++logger_syslog_level=2
> ++logger_stdout=-1
> ++logger_stdout_level=2
> ++ctrl_interface=/var/run/hostapd
> ++ctrl_interface_group=0
> ++eap_server=1
> ++eap_user_file=/home/user/hs20-server/AS/hostapd-osen.eap_user
> ++server_id=ben-ota-2-osen
> ++radius_server_auth_port=1811
> ++radius_server_clients=/home/user/hs20-server/AS/hostap.radius_clients
> ++
> ++ca_cert=/home/user/hs20-server/ca/ca.pem
> ++server_cert=/home/user/hs20-server/ca/server.pem
> ++private_key=/home/user/hs20-server/ca/server.key
> ++private_key_passwd=whatever
> ++
> ++ocsp_stapling_response=/home/user/hs20-server/ca/ocsp-server-cache.der
> ++
> ++The /home/user/hs20-server/AS/hostapd-osen.eap_user file should look
> ++similar to this, and should coorelate with the osu_nai entry in
> ++the non-OSEN VAP config file. For instance:
> ++
> ++# cat hostapd-osen.eap_user
> ++# For OSEN authentication (Hotspot 2.0 Release 2)
> ++"osen at w1.fi" WFA-UNAUTH-TLS
> ++
> ++
> ++# Run OCSP server:
> ++cd /home/user/hs20-server/ca
> ++./ocsp-responder.sh&
> ++
> ++# Update cache (This should be run periodically)
> ++./ocsp-update-cache.sh
> ++
> ++
> ++Configure web server
> ++--------------------
> ++
> ++Edit /etc/apache2/sites-available/default-ssl
> ++
> ++Add following block just before "SSL Engine Switch" line":
> ++
> ++ Alias /hs20/ "/home/user/hs20-server/www/"
> ++ <Directory "/home/user/hs20-server/www/">
> ++ Options Indexes MultiViews FollowSymLinks
> ++ AllowOverride None
> ++ Order allow,deny
> ++ Allow from all
> ++ </Directory>
> ++
> ++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.
> ++
> ++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://<server>/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://<server>/hs20/spp.php/signup?realm=example.com
> +diff -urN awpa_supplicant-2.6-original/hs20/server/hs20_spp_server.c
> bwpa_supplicant-2.6-patched-final/hs20/server/hs20_spp_server.c
> +--- awpa_supplicant-2.6-original/hs20/server/hs20_spp_server.c 1969-12-
> 31 18:00:00.000000000 -0600
> ++++ bwpa_supplicant-2.6-patched-final/hs20/server/hs20_spp_server.c
> 2016-10-02 13:51:11.000000000 -0500
> +@@ -0,0 +1,187 @@
> ++/*
> ++ * 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 <time.h>
> ++#include <sqlite3.h>
> ++
> ++#include "common.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);
> ++
> ++ 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;
> ++ }
> ++
> ++ 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<root directory> [-f<debug log>]\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:");
> ++ 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;
> ++ 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 -urN awpa_supplicant-2.6-original/hs20/server/Makefile bwpa_supplicant-
> 2.6-patched-final/hs20/server/Makefile
> +--- awpa_supplicant-2.6-original/hs20/server/Makefile 1969-12-31
> 18:00:00.000000000 -0600
> ++++ bwpa_supplicant-2.6-patched-final/hs20/server/Makefile 2016-10-02
> 13:51:11.000000000 -0500
> +@@ -0,0 +1,46 @@
> ++all: hs20_spp_server
> ++
> ++ifndef CC
> ++CC=gcc
> ++endif
> ++
> ++ifndef LDO
> ++LDO=$(CC)
> ++endif
> ++
> ++ifndef CFLAGS
> ++CFLAGS = -MMD -O2 -Wall -g
> ++endif
> ++
> ++CFLAGS += -I../../src
> ++CFLAGS += -I../../src/utils
> ++CFLAGS += -I../../src/crypto
> ++
> ++LIBS += -lsqlite3
> ++
> ++# Using glibc < 2.17 requires -lrt for clock_gettime()
> ++LIBS += -lrt
> ++
> ++OBJS=spp_server.o
> ++OBJS += hs20_spp_server.o
> ++OBJS += ../../src/utils/xml-utils.o
> ++OBJS += ../../src/utils/base64.o
> ++OBJS += ../../src/utils/common.o
> ++OBJS += ../../src/utils/os_unix.o
> ++OBJS += ../../src/utils/wpa_debug.o
> ++OBJS += ../../src/crypto/md5-internal.o
> ++CFLAGS += $(shell xml2-config --cflags)
> ++LIBS += $(shell xml2-config --libs)
> ++OBJS += ../../src/utils/xml_libxml2.o
> ++
> ++hs20_spp_server: $(OBJS)
> ++ $(LDO) $(LDFLAGS) -o hs20_spp_server $(OBJS) $(LIBS)
> ++
> ++clean:
> ++ rm -f core *~ *.o *.d hs20_spp_server
> ++ rm -f ../../src/utils/*.o
> ++ rm -f ../../src/utils/*.d
> ++ rm -f ../../src/crypto/*.o
> ++ rm -f ../../src/crypto/*.d
> ++
> ++-include $(OBJS:%.o=%.d)
> +diff -urN awpa_supplicant-2.6-original/hs20/server/spp_server.c
> bwpa_supplicant-2.6-patched-final/hs20/server/spp_server.c
> +--- awpa_supplicant-2.6-original/hs20/server/spp_server.c 1969-12-31
> 18:00:00.000000000 -0600
> ++++ bwpa_supplicant-2.6-patched-final/hs20/server/spp_server.c 2016-10-
> 02 13:51:11.000000000 -0500
> +@@ -0,0 +1,2292 @@
> ++/*
> ++ * 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 <stdlib.h>
> ++#include <stdio.h>
> ++#include <string.h>
> ++#include <ctype.h>
> ++#include <time.h>
> ++#include <errno.h>
> ++#include <sqlite3.h>
> ++
> ++#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,
> ++};
> ++
> ++
> ++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 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)
> ++{
> ++ char *sql;
> ++ int ret = 0;
> ++
> ++ sql = sqlite3_mprintf("INSERT INTO sessions(timestamp,id,user,realm,"
> ++ "operation,password,redirect_uri) "
> ++ "VALUES "
> ++ "(strftime('%%Y-%%m-%%d %%H:%%M:%%f','now'),"
> ++ "%Q,%Q,%Q,%d,%Q,%Q)",
> ++ sessionid, user ? user : "", realm ? realm : "",
> ++ operation, pw ? pw : "",
> ++ redirect_uri ? redirect_uri : "");
> ++ 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_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",
> ++ 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 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",
> ++ 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",
> ++ 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 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;
> ++
> ++ node = xml_node_create(ctx->xml, parent, NULL, "UsernamePassword");
> ++ if (node == NULL)
> ++ return NULL;
> ++
> ++ add_text_node(ctx, node, "Username", user);
> ++
> ++ b64 = (char *) base64_encode((unsigned char *) pw, strlen(pw), NULL);
> ++ if (b64 == NULL)
> ++ return NULL;
> ++ 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)
> ++{
> ++ xml_node_t *node;
> ++
> ++ node = build_username_password(ctx, cred, user, pw);
> ++ if (node == NULL)
> ++ return -1;
> ++
> ++ add_text_node(ctx, node, "MachineManaged", "TRUE");
> ++ 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)
> ++{
> ++ 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) < 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);
> ++}
> ++
> ++
> ++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 * 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 *real_user = NULL;
> ++ char *status;
> ++ char *cert;
> ++
> ++ if (dmacc) {
> ++ real_user = db_get_val(ctx, user, realm, "identity", dmacc);
> ++ if (real_user == NULL) {
> ++ debug_print(ctx, 1, "Could not find user identity for "
> ++ "dmacc user '%s'", user);
> ++ return NULL;
> ++ }
> ++ }
> ++
> ++ cert = db_get_val(ctx, user, realm, "cert", dmacc);
> ++ if (cert && cert[0] == '\0')
> ++ cert = NULL;
> ++ if (cert) {
> ++ cred = build_credential_cert(ctx, real_user ? real_user : user,
> ++ realm, cert);
> ++ } 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");
> ++ 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");
> ++ return NULL;
> ++ }
> ++
> ++ snprintf(buf, sizeof(buf),
> ++ "./Wi-Fi/%s/PerProviderSubscription/Credential1/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);
> ++ 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, "Certificate credential - no need for DB "
> ++ "password update on success notification");
> ++ } 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);
> ++ }
> ++
> ++ 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 * 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);
> ++
> ++ 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/Credential1/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);
> ++
> ++ 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);
> ++
> ++ 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
> ++ ret = machine_remediation(ctx, user, realm, session_id, dmacc);
> ++ free(type);
> ++
> ++ return ret;
> ++}
> ++
> ++
> ++static xml_node_t * build_policy(struct hs20_svc *ctx, const char *user,
> ++ const char *realm, int use_dmacc)
> ++{
> ++ char *policy_id;
> ++ char fname[200];
> ++ 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;
> ++ }
> ++
> ++ snprintf(fname, sizeof(fname), "%s/spp/policy/%s.xml",
> ++ ctx->root_dir, policy_id);
> ++ free(policy_id);
> ++ debug_print(ctx, 1, "Use policy file %s", fname);
> ++
> ++ policy = node_from_file(ctx->xml, fname);
> ++ if (policy == NULL)
> ++ return NULL;
> ++
> ++ node = get_node_uri(ctx->xml, policy, "Policy/PolicyUpdate/URI");
> ++ if (node) {
> ++ char *url;
> ++ url = db_get_osu_config_val(ctx, realm, "policy_url");
> ++ if (url == NULL) {
> ++ xml_node_free(ctx->xml, policy);
> ++ return NULL;
> ++ }
> ++ xml_node_set_text(ctx->xml, node, url);
> ++ free(url);
> ++ }
> ++
> ++ 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);
> ++
> ++ 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/Credential1/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)
> ++{
> ++ 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) < 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)
> ++{
> ++ xml_node_t *pps, *c, *trust, *aaa, *aaa1, *upd, *homesp;
> ++ xml_node_t *cred, *eap, *userpw;
> ++
> ++ pps = xml_node_create_root(ctx->xml, NULL, NULL, NULL,
> ++ "PerProviderSubscription");
> ++ if (pps == NULL)
> ++ return NULL;
> ++
> ++ add_text_node(ctx, pps, "UpdateIdentifier", "1");
> ++
> ++ c = xml_node_create(ctx->xml, pps, NULL, "Credential1");
> ++
> ++ add_text_node(ctx, c, "CredentialPriority", "1");
> ++
> ++ 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");
> ++ add_text_node_conf(ctx, realm, aaa1, "CertSHA256Fingerprint",
> ++ "aaa_trust_root_cert_fingerprint");
> ++
> ++ upd = xml_node_create(ctx->xml, c, NULL, "SubscriptionUpdate");
> ++ add_text_node(ctx, upd, "UpdateInterval", "4294967295");
> ++ add_text_node(ctx, upd, "UpdateMethod", "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");
> ++ add_text_node_conf(ctx, realm, trust, "CertSHA256Fingerprint",
> ++ "trust_root_cert_fingerprint");
> ++
> ++ 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 (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)
> ++{
> ++ xml_namespace_t *ns;
> ++ xml_node_t *spp_node, *enroll, *exec_node;
> ++ char *val;
> ++ char password[11];
> ++ char *b64;
> ++
> ++ if (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);
> ++ xml_node_create_text(ctx->xml, enroll, ns, "estUserID", user);
> ++
> ++ b64 = (char *) base64_encode((unsigned char *) 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;
> ++ 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);
> ++ 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");
> ++ pps = build_pps(ctx, user, realm, pw,
> ++ fingerprint ? fingerprint : NULL, machine_managed);
> ++ free(fingerprint);
> ++ 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);
> ++ 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/Credential1/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_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, 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)
> ++ return hs20_user_input_registration(ctx, session_id, 1);
> ++
> ++ 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_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;
> ++ char *version;
> ++ int valid;
> ++ char *supp, *pos;
> ++ char *err;
> ++
> ++ 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);
> ++ 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) < 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);
> ++ 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) {
> ++ if (devinfo)
> ++ db_add_session_devinfo(ctx, session_id, devinfo);
> ++ if (devdetail)
> ++ 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;
> ++ }
> ++
> ++ 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 *sql;
> ++ int ret = -1;
> ++ char *free_account;
> ++ int free_acc;
> ++ char *type;
> ++ int cert = 0;
> ++ char *cert_pem, *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");
> ++ 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);
> ++
> ++ 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);
> ++
> ++ 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;
> ++ }
> ++
> ++ sql = sqlite3_mprintf("INSERT INTO users(identity,realm,phase2,"
> ++ "methods,cert,cert_pem,machine_managed) VALUES "
> ++ "(%Q,%Q,1,%Q,%Q,%Q,%d)",
> ++ user, realm, cert ? "TLS" : "TTLS-MSCHAPV2",
> ++ fingerprint ? fingerprint : "",
> ++ cert_pem ? cert_pem : "",
> ++ pw_mm && atoi(pw_mm) ? 1 : 0);
> ++ 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",
> ++ 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 (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);
> ++ 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, user, realm, session_id, "operation");
> ++ if (!val) {
> ++ debug_print(ctx, 1,
> ++ "No session active for user: %s sessionID: %s",
> ++ user, 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 == 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);
> ++ }
> ++ 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, user, realm, 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 -urN awpa_supplicant-2.6-original/hs20/server/spp_server.h
> bwpa_supplicant-2.6-patched-final/hs20/server/spp_server.h
> +--- awpa_supplicant-2.6-original/hs20/server/spp_server.h 1969-12-31
> 18:00:00.000000000 -0600
> ++++ bwpa_supplicant-2.6-patched-final/hs20/server/spp_server.h 2016-10-
> 02 13:51:11.000000000 -0500
> +@@ -0,0 +1,32 @@
> ++/*
> ++ * 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;
> ++};
> ++
> ++
> ++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 -urN awpa_supplicant-2.6-original/hs20/server/sql-example.txt
> bwpa_supplicant-2.6-patched-final/hs20/server/sql-example.txt
> +--- awpa_supplicant-2.6-original/hs20/server/sql-example.txt 1969-12-31
> 18:00:00.000000000 -0600
> ++++ bwpa_supplicant-2.6-patched-final/hs20/server/sql-example.txt 2016-10-
> 02 13:51:11.000000000 -0500
> +@@ -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','5b393a9246865569485c260
> 5c3304e48212b449367858299beba9384c4cf4647');
> ++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','5b393a9246865569485
> c2605c3304e48212b449367858299beba9384c4cf4647');
> ++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 -urN awpa_supplicant-2.6-original/hs20/server/sql.txt bwpa_supplicant-2.6-
> patched-final/hs20/server/sql.txt
> +--- awpa_supplicant-2.6-original/hs20/server/sql.txt 1969-12-31
> 18:00:00.000000000 -0600
> ++++ bwpa_supplicant-2.6-patched-final/hs20/server/sql.txt 2016-10-02
> 13:51:11.000000000 -0500
> +@@ -0,0 +1,59 @@
> ++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
> ++);
> ++
> ++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
> ++);
> ++
> ++CREATE TABLE wildcards(
> ++ identity TEXT PRIMARY KEY,
> ++ methods TEXT
> ++);
> +diff -urN awpa_supplicant-2.6-original/hs20/server/www/add-free.php
> bwpa_supplicant-2.6-patched-final/hs20/server/www/add-free.php
> +--- awpa_supplicant-2.6-original/hs20/server/www/add-free.php 1969-12-
> 31 18:00:00.000000000 -0600
> ++++ bwpa_supplicant-2.6-patched-final/hs20/server/www/add-free.php
> 2016-10-02 13:51:11.000000000 -0500
> +@@ -0,0 +1,50 @@
> ++<?php
> ++
> ++require('config.php');
> ++
> ++$db = new PDO($osu_db);
> ++if (!$db) {
> ++ die($sqliteerror);
> ++}
> ++
> ++if (isset($_POST["id"]))
> ++ $id = preg_replace("/[^a-fA-F0-9]/", "", $_POST["id"]);
> ++else
> ++ die("Missing session id");
> ++if (strlen($id) < 32)
> ++ die("Invalid session id");
> ++
> ++$row = $db->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 -urN awpa_supplicant-2.6-original/hs20/server/www/add-mo.php
> bwpa_supplicant-2.6-patched-final/hs20/server/www/add-mo.php
> +--- awpa_supplicant-2.6-original/hs20/server/www/add-mo.php 1969-12-
> 31 18:00:00.000000000 -0600
> ++++ bwpa_supplicant-2.6-patched-final/hs20/server/www/add-mo.php
> 2016-10-02 13:51:11.000000000 -0500
> +@@ -0,0 +1,56 @@
> ++<?php
> ++
> ++require('config.php');
> ++
> ++$db = new PDO($osu_db);
> ++if (!$db) {
> ++ die($sqliteerror);
> ++}
> ++
> ++if (isset($_POST["id"]))
> ++ $id = preg_replace("/[^a-fA-F0-9]/", "", $_POST["id"]);
> ++else
> ++ die("Missing session id");
> ++
> ++$user = $_POST["user"];
> ++$pw = $_POST["password"];
> ++if (strlen($id) < 32 || !isset($user) || !isset($pw)) {
> ++ die("Invalid POST data");
> ++}
> ++
> ++if (strlen($user) < 1 || strncasecmp($user, "cert-", 5) == 0) {
> ++ echo "<html><body><p><red>Invalid username</red></p>\n";
> ++ echo "<a href=\"signup.php?session_id=$id\">Try again</a>\n";
> ++ echo "</body></html>\n";
> ++ exit;
> ++}
> ++
> ++$row = $db->query("SELECT rowid,* FROM sessions WHERE id='$id'")->fetch();
> ++if ($row == false) {
> ++ die("Session not found");
> ++}
> ++$realm = $row['realm'];
> ++
> ++$userrow = $db->query("SELECT identity FROM users WHERE identity='$user'
> AND realm='$realm'")->fetch();
> ++if ($userrow) {
> ++ echo "<html><body><p><red>Selected username is not
> available</red></p>\n";
> ++ echo "<a href=\"signup.php?session_id=$id\">Try again</a>\n";
> ++ echo "</body></html>\n";
> ++ exit;
> ++}
> ++
> ++$uri = $row['redirect_uri'];
> ++$rowid = $row['rowid'];
> ++
> ++if (!$db->exec("UPDATE sessions SET user='$user', password='$pw',
> realm='$realm', type='password' 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 -urN awpa_supplicant-2.6-original/hs20/server/www/cert-enroll.php
> bwpa_supplicant-2.6-patched-final/hs20/server/www/cert-enroll.php
> +--- awpa_supplicant-2.6-original/hs20/server/www/cert-enroll.php 1969-12-
> 31 18:00:00.000000000 -0600
> ++++ bwpa_supplicant-2.6-patched-final/hs20/server/www/cert-enroll.php
> 2016-10-02 13:51:11.000000000 -0500
> +@@ -0,0 +1,39 @@
> ++<?php
> ++
> ++require('config.php');
> ++
> ++$db = new PDO($osu_db);
> ++if (!$db) {
> ++ die($sqliteerror);
> ++}
> ++
> ++if (isset($_GET["id"]))
> ++ $id = preg_replace("/[^a-fA-F0-9]/", "", $_GET["id"]);
> ++else
> ++ die("Missing session id");
> ++if (strlen($id) < 32)
> ++ die("Invalid session id");
> ++
> ++$row = $db->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'];
> ++
> ++$user = sha1(mt_rand());
> ++
> ++if (!$db->exec("UPDATE sessions SET user='$user', type='cert' WHERE
> rowid=$rowid")) {
> ++ die("Failed to update session database");
> ++}
> ++
> ++$db->exec("INSERT INTO eventlog(user,realm,sessionid,timestamp,notes) " .
> ++ "VALUES ('', '$realm', '$id', " .
> ++ "strftime('%Y-%m-%d %H:%M:%f','now'), " .
> ++ "'completed user input response for client certificate enrollment')");
> ++
> ++header("Location: $uri", true, 302);
> ++
> ++?>
> +diff -urN awpa_supplicant-2.6-original/hs20/server/www/config.php
> bwpa_supplicant-2.6-patched-final/hs20/server/www/config.php
> +--- awpa_supplicant-2.6-original/hs20/server/www/config.php 1969-12-31
> 18:00:00.000000000 -0600
> ++++ bwpa_supplicant-2.6-patched-final/hs20/server/www/config.php 2016-10-
> 02 13:51:11.000000000 -0500
> +@@ -0,0 +1,4 @@
> ++<?php
> ++$osu_root = "/home/user/hs20-server";
> ++$osu_db = "sqlite:$osu_root/AS/DB/eap_user.db";
> ++?>
> +diff -urN awpa_supplicant-2.6-original/hs20/server/www/est.php
> bwpa_supplicant-2.6-patched-final/hs20/server/www/est.php
> +--- awpa_supplicant-2.6-original/hs20/server/www/est.php 1969-12-31
> 18:00:00.000000000 -0600
> ++++ bwpa_supplicant-2.6-patched-final/hs20/server/www/est.php 2016-10-
> 02 13:51:11.000000000 -0500
> +@@ -0,0 +1,198 @@
> ++<?php
> ++
> ++require('config.php');
> ++
> ++$params = split("/", $_SERVER["PATH_INFO"], 3);
> ++$realm = $params[1];
> ++$cmd = $params[2];
> ++$method = $_SERVER["REQUEST_METHOD"];
> ++
> ++unset($user);
> ++unset($rowid);
> ++
> ++if (!empty($_SERVER['PHP_AUTH_DIGEST'])) {
> ++ $needed = array('nonce'=>1, 'nc'=>1, 'cnonce'=>1, 'qop'=>1, 'username'=>1,
> ++ 'uri'=>1, 'response'=>1);
> ++ $data = array();
> ++ $keys = implode('|', array_keys($needed));
> ++ preg_match_all('@(' . $keys . ')=(?:([\'"])([^\2]+?)\2|([^\s,]+))@',
> ++ $_SERVER['PHP_AUTH_DIGEST'], $matches, PREG_SET_ORDER);
> ++ foreach ($matches as $m) {
> ++ $data[$m[1]] = $m[3] ? $m[3] : $m[4];
> ++ unset($needed[$m[1]]);
> ++ }
> ++ if ($needed) {
> ++ error_log("EST: Missing auth parameter");
> ++ die('Authentication failed');
> ++ }
> ++ $user = $data['username'];
> ++ if (strlen($user) < 1) {
> ++ error_log("EST: Empty username");
> ++ die('Authentication failed');
> ++ }
> ++
> ++ $db = new PDO($osu_db);
> ++ if (!$db) {
> ++ error_log("EST: Could not access database");
> ++ die("Could not access database");
> ++ }
> ++
> ++ $sql = "SELECT rowid,password,operation FROM sessions " .
> ++ "WHERE user='$user' AND realm='$realm'";
> ++ $q = $db->query($sql);
> ++ if (!$q) {
> ++ error_log("EST: Session not found for user=$user realm=$realm");
> ++ die("Session not found");
> ++ }
> ++ $row = $q->fetch();
> ++ if (!$row) {
> ++ error_log("EST: Session fetch failed for user=$user realm=$realm");
> ++ die('Session not found');
> ++ }
> ++ $rowid = $row['rowid'];
> ++
> ++ $oper = $row['operation'];
> ++ if ($oper != '5') {
> ++ error_log("EST: Unexpected operation $oper for user=$user realm=$realm");
> ++ die("Session not found");
> ++ }
> ++ $pw = $row['password'];
> ++ if (strlen($pw) < 1) {
> ++ error_log("EST: Empty password for user=$user realm=$realm");
> ++ die('Authentication failed');
> ++ }
> ++
> ++ $A1 = md5($user . ':' . $realm . ':' . $pw);
> ++ $A2 = md5($method . ':' . $data['uri']);
> ++ $resp = md5($A1 . ':' . $data['nonce'] . ':' . $data['nc'] . ':' .
> ++ $data['cnonce'] . ':' . $data['qop'] . ':' . $A2);
> ++ if ($data['response'] != $resp) {
> ++ error_log("EST: Incorrect authentication response for user=$user
> realm=$realm");
> ++ die('Authentication failed');
> ++ }
> ++}
> ++
> ++
> ++if ($method == "GET" && $cmd == "cacerts") {
> ++ $fname = "$osu_root/est/$realm-cacerts.pkcs7";
> ++ if (!file_exists($fname)) {
> ++ error_log("EST: cacerts - unknown realm $realm");
> ++ die("Unknown realm");
> ++ }
> ++
> ++ header("Content-Transfer-Encoding: base64");
> ++ header("Content-Type: application/pkcs7-mime");
> ++
> ++ $data = file_get_contents($fname);
> ++ echo wordwrap(base64_encode($data), 72, "\n", true);
> ++ echo "\n";
> ++ error_log("EST: cacerts");
> ++} else if ($method == "GET" && $cmd == "csrattrs") {
> ++ header("Content-Transfer-Encoding: base64");
> ++ header("Content-Type: application/csrattrs");
> ++ readfile("$osu_root/est/est-attrs.b64");
> ++ error_log("EST: csrattrs");
> ++} else if ($method == "POST" && $cmd == "simpleenroll") {
> ++ if (!isset($user) || strlen($user) == 0) {
> ++ header('HTTP/1.1 401 Unauthorized');
> ++ header('WWW-Authenticate: Digest realm="'.$realm.
> ++ '",qop="auth",nonce="'.uniqid().'",opaque="'.md5($realm).'"');
> ++ error_log("EST: simpleenroll - require authentication");
> ++ die('Authentication required');
> ++ }
> ++ if (!isset($_SERVER["CONTENT_TYPE"])) {
> ++ error_log("EST: simpleenroll without Content-Type");
> ++ die("Missing Content-Type");
> ++ }
> ++ if (!stristr($_SERVER["CONTENT_TYPE"], "application/pkcs10")) {
> ++ error_log("EST: simpleenroll - unexpected Content-Type: " .
> ++ $_SERVER["CONTENT_TYPE"]);
> ++ die("Unexpected Content-Type");
> ++ }
> ++
> ++ $data = file_get_contents("php://input");
> ++ error_log("EST: simpleenroll - POST data from php://input: " . $data);
> ++ $req = base64_decode($data);
> ++ if ($req == FALSE) {
> ++ error_log("EST: simpleenroll - Invalid base64-encoded PKCS#10 data");
> ++ die("Invalid base64-encoded PKCS#10 data");
> ++ }
> ++ $cadir = "$osu_root/est";
> ++ $reqfile = "$cadir/tmp/cert-req.pkcs10";
> ++ $f = fopen($reqfile, "wb");
> ++ fwrite($f, $req);
> ++ fclose($f);
> ++
> ++ $req_pem = "$reqfile.pem";
> ++ if (file_exists($req_pem))
> ++ unlink($req_pem);
> ++ exec("openssl req -in $reqfile -inform DER -out $req_pem -outform PEM");
> ++ if (!file_exists($req_pem)) {
> ++ error_log("EST: simpleenroll - Failed to parse certificate request");
> ++ die("Failed to parse certificate request");
> ++ }
> ++
> ++ /* FIX: validate request and add HS 2.0 extensions to cert */
> ++ $cert_pem = "$cadir/tmp/req-signed.pem";
> ++ if (file_exists($cert_pem))
> ++ unlink($cert_pem);
> ++ exec("openssl x509 -req -in $req_pem -CAkey $cadir/cakey.pem -out
> $cert_pem -CA $cadir/cacert.pem -CAserial $cadir/serial -days 365 -text");
> ++ if (!file_exists($cert_pem)) {
> ++ error_log("EST: simpleenroll - Failed to sign certificate");
> ++ die("Failed to sign certificate");
> ++ }
> ++
> ++ $cert = file_get_contents($cert_pem);
> ++ $handle = popen("openssl x509 -in $cert_pem -serial -noout", "r");
> ++ $serial = fread($handle, 200);
> ++ pclose($handle);
> ++ $pattern = "/serial=(?P<snhex>[0-9a-fA-F:]*)/m";
> ++ preg_match($pattern, $serial, $matches);
> ++ if (!isset($matches['snhex']) || strlen($matches['snhex']) < 1) {
> ++ error_log("EST: simpleenroll - Could not get serial number");
> ++ die("Could not get serial number");
> ++ }
> ++ $sn = str_replace(":", "", strtoupper($matches['snhex']));
> ++
> ++ $user = "cert-$sn";
> ++ error_log("EST: user = $user");
> ++
> ++ $cert_der = "$cadir/tmp/req-signed.der";
> ++ if (file_exists($cert_der))
> ++ unlink($cert_der);
> ++ exec("openssl x509 -in $cert_pem -inform PEM -out $cert_der -outform DER");
> ++ if (!file_exists($cert_der)) {
> ++ error_log("EST: simpleenroll - Failed to convert certificate");
> ++ die("Failed to convert certificate");
> ++ }
> ++ $der = file_get_contents($cert_der);
> ++ $fingerprint = hash("sha256", $der);
> ++
> ++ $pkcs7 = "$cadir/tmp/est-client.pkcs7";
> ++ if (file_exists($pkcs7))
> ++ unlink($pkcs7);
> ++ exec("openssl crl2pkcs7 -nocrl -certfile $cert_pem -out $pkcs7 -outform DER");
> ++ if (!file_exists($pkcs7)) {
> ++ error_log("EST: simpleenroll - Failed to prepare PKCS#7 file");
> ++ die("Failed to prepare PKCS#7 file");
> ++ }
> ++
> ++ if (!$db->exec("UPDATE sessions SET user='$user', cert='$fingerprint',
> cert_pem='$cert' WHERE rowid=$rowid")) {
> ++ error_log("EST: simpleenroll - Failed to update session database");
> ++ die("Failed to update session database");
> ++ }
> ++
> ++ header("Content-Transfer-Encoding: base64");
> ++ header("Content-Type: application/pkcs7-mime");
> ++
> ++ $data = file_get_contents($pkcs7);
> ++ $resp = wordwrap(base64_encode($data), 72, "\n", true);
> ++ echo $resp . "\n";
> ++ error_log("EST: simpleenroll - PKCS#7 response: " . $resp);
> ++} else {
> ++ header("HTTP/1.0 404 Not Found");
> ++ error_log("EST: Unexpected method or path");
> ++ die("Unexpected method or path");
> ++}
> ++
> ++?>
> +diff -urN awpa_supplicant-2.6-original/hs20/server/www/free.php
> bwpa_supplicant-2.6-patched-final/hs20/server/www/free.php
> +--- awpa_supplicant-2.6-original/hs20/server/www/free.php 1969-12-31
> 18:00:00.000000000 -0600
> ++++ bwpa_supplicant-2.6-patched-final/hs20/server/www/free.php 2016-10-
> 02 13:51:11.000000000 -0500
> +@@ -0,0 +1,23 @@
> ++<html>
> ++<head>
> ++<title>Hotspot 2.0 - public and free hotspot</title>
> ++</head>
> ++<body>
> ++
> ++<?php
> ++
> ++$id = $_GET["session_id"];
> ++
> ++echo "<h3>Hotspot 2.0 - public and free hotspot</h3>\n";
> ++
> ++echo "<form action=\"add-free.php\" method=\"POST\">\n";
> ++echo "<input type=\"hidden\" name=\"id\" value=\"$id\">\n";
> ++
> ++?>
> ++
> ++<p>Terms and conditions..</p>
> ++<input type="submit" value="Accept">
> ++</form>
> ++
> ++</body>
> ++</html>
> +diff -urN awpa_supplicant-2.6-original/hs20/server/www/free-remediation.php
> bwpa_supplicant-2.6-patched-final/hs20/server/www/free-remediation.php
> +--- awpa_supplicant-2.6-original/hs20/server/www/free-remediation.php
> 1969-12-31 18:00:00.000000000 -0600
> ++++ bwpa_supplicant-2.6-patched-final/hs20/server/www/free-remediation.php
> 2016-10-02 13:51:11.000000000 -0500
> +@@ -0,0 +1,19 @@
> ++<html>
> ++<head>
> ++<title>Hotspot 2.0 - public and free hotspot - remediation</title>
> ++</head>
> ++<body>
> ++
> ++<h3>Hotspot 2.0 - public and free hotspot</h3>
> ++
> ++<p>Terms and conditions have changed. You need to accept the new terms
> ++to continue using this network.</p>
> ++
> ++<p>Terms and conditions..</p>
> ++
> ++<?php
> ++echo "<a href=\"redirect.php?id=" . $_GET["session_id"] .
> "\">Accept</a><br>\n";
> ++?>
> ++
> ++</body>
> ++</html>
> +diff -urN awpa_supplicant-2.6-original/hs20/server/www/redirect.php
> bwpa_supplicant-2.6-patched-final/hs20/server/www/redirect.php
> +--- awpa_supplicant-2.6-original/hs20/server/www/redirect.php 1969-12-
> 31 18:00:00.000000000 -0600
> ++++ bwpa_supplicant-2.6-patched-final/hs20/server/www/redirect.php
> 2016-10-02 13:51:11.000000000 -0500
> +@@ -0,0 +1,32 @@
> ++<?php
> ++
> ++require('config.php');
> ++
> ++$db = new PDO($osu_db);
> ++if (!$db) {
> ++ die($sqliteerror);
> ++}
> ++
> ++if (isset($_GET["id"]))
> ++ $id = preg_replace("/[^a-fA-F0-9]/", "", $_GET["id"]);
> ++else
> ++ $id = 0;
> ++
> ++$row = $db->query("SELECT rowid,* FROM sessions WHERE id='$id'")->fetch();
> ++if ($row == false) {
> ++ die("Session not found");
> ++}
> ++
> ++$uri = $row['redirect_uri'];
> ++
> ++header("Location: $uri", true, 302);
> ++
> ++$user = $row['user'];
> ++$realm = $row['realm'];
> ++
> ++$db->exec("INSERT INTO eventlog(user,realm,sessionid,timestamp,notes) " .
> ++ "VALUES ('$user', '$realm', '$id', " .
> ++ "strftime('%Y-%m-%d %H:%M:%f','now'), " .
> ++ "'redirected after user input')");
> ++
> ++?>
> +diff -urN awpa_supplicant-2.6-original/hs20/server/www/remediation.php
> bwpa_supplicant-2.6-patched-final/hs20/server/www/remediation.php
> +--- awpa_supplicant-2.6-original/hs20/server/www/remediation.php 1969-12-
> 31 18:00:00.000000000 -0600
> ++++ bwpa_supplicant-2.6-patched-final/hs20/server/www/remediation.php
> 2016-10-02 13:51:11.000000000 -0500
> +@@ -0,0 +1,18 @@
> ++<html>
> ++<head>
> ++<title>Hotspot 2.0 subscription remediation</title>
> ++</head>
> ++<body>
> ++
> ++<?php
> ++
> ++echo "SessionID: " . $_GET["session_id"] . "<br>\n";
> ++
> ++echo "<a href=\"redirect.php?id=" . $_GET["session_id"] . "\">Complete user
> subscription remediation</a><br>\n";
> ++
> ++?>
> ++
> ++This will provide a new machine-generated password.
> ++
> ++</body>
> ++</html>
> +diff -urN awpa_supplicant-2.6-original/hs20/server/www/signup.php
> bwpa_supplicant-2.6-patched-final/hs20/server/www/signup.php
> +--- awpa_supplicant-2.6-original/hs20/server/www/signup.php 1969-12-
> 31 18:00:00.000000000 -0600
> ++++ bwpa_supplicant-2.6-patched-final/hs20/server/www/signup.php 2016-10-
> 02 13:51:11.000000000 -0500
> +@@ -0,0 +1,46 @@
> ++<html>
> ++<head>
> ++<title>Hotspot 2.0 signup</title>
> ++</head>
> ++<body>
> ++
> ++<?php
> ++
> ++$id = $_GET["session_id"];
> ++
> ++require('config.php');
> ++
> ++$db = new PDO($osu_db);
> ++if (!$db) {
> ++ die($sqliteerror);
> ++}
> ++
> ++$row = $db->query("SELECT realm FROM sessions WHERE id='$id'")->fetch();
> ++if ($row == false) {
> ++ die("Session not found for id: $id");
> ++}
> ++$realm = $row['realm'];
> ++
> ++echo "<h3>Sign up for a subscription - $realm</h3>\n";
> ++
> ++$row = $db->query("SELECT value FROM osu_config WHERE realm='$realm'
> AND field='free_account'")->fetch();
> ++if ($row && strlen($row['value']) > 0) {
> ++ echo "<p><a href=\"free.php?session_id=$id\">Sign up for free
> access</a></p>\n";
> ++}
> ++
> ++echo "<form action=\"add-mo.php\" method=\"POST\">\n";
> ++echo "<input type=\"hidden\" name=\"id\" value=\"$id\">\n";
> ++?>
> ++Select a username and password. Leave password empty to get automatically
> ++generated and machine managed password.<br>
> ++Username: <input type="text" name="user"><br>
> ++Password: <input type="password" name="password"><br>
> ++<input type="submit" value="Complete subscription registration">
> ++</form>
> ++
> ++<?php
> ++echo "<p><a href=\"cert-enroll.php?id=$id\">Enroll a client
> certificate</a></p>\n"
> ++?>
> ++
> ++</body>
> ++</html>
> +diff -urN awpa_supplicant-2.6-original/hs20/server/www/spp.php
> bwpa_supplicant-2.6-patched-final/hs20/server/www/spp.php
> +--- awpa_supplicant-2.6-original/hs20/server/www/spp.php 1969-12-31
> 18:00:00.000000000 -0600
> ++++ bwpa_supplicant-2.6-patched-final/hs20/server/www/spp.php 2016-10-
> 02 13:51:11.000000000 -0500
> +@@ -0,0 +1,128 @@
> ++<?php
> ++
> ++require('config.php');
> ++
> ++if (!stristr($_SERVER["CONTENT_TYPE"], "application/soap+xml")) {
> ++ error_log("spp.php - Unexpected Content-Type " .
> $_SERVER["CONTENT_TYPE"]);
> ++ die("Unexpected Content-Type");
> ++}
> ++
> ++if ($_SERVER["REQUEST_METHOD"] != "POST") {
> ++ error_log("spp.php - Unexpected method " . $_SERVER["REQUEST_METHOD"]);
> ++ die("Unexpected method");
> ++}
> ++
> ++if (isset($_GET["realm"])) {
> ++ $realm = $_GET["realm"];
> ++ $realm = PREG_REPLACE("/[^0-9a-zA-Z\.\-]/i", '', $realm);
> ++} else {
> ++ error_log("spp.php - Realm not specified");
> ++ die("Realm not specified");
> ++}
> ++
> ++unset($user);
> ++putenv("HS20CERT");
> ++
> ++if (!empty($_SERVER['PHP_AUTH_DIGEST'])) {
> ++ $needed = array('nonce'=>1, 'nc'=>1, 'cnonce'=>1, 'qop'=>1, 'username'=>1,
> ++ 'uri'=>1, 'response'=>1);
> ++ $data = array();
> ++ $keys = implode('|', array_keys($needed));
> ++ preg_match_all('@(' . $keys . ')=(?:([\'"])([^\2]+?)\2|([^\s,]+))@',
> ++ $_SERVER['PHP_AUTH_DIGEST'], $matches, PREG_SET_ORDER);
> ++ foreach ($matches as $m) {
> ++ $data[$m[1]] = $m[3] ? $m[3] : $m[4];
> ++ unset($needed[$m[1]]);
> ++ }
> ++ if ($needed) {
> ++ error_log("spp.php - Authentication failed - missing: " . print_r($needed));
> ++ die('Authentication failed');
> ++ }
> ++ $user = $data['username'];
> ++ if (strlen($user) < 1) {
> ++ error_log("spp.php - Authentication failed - empty username");
> ++ die('Authentication failed');
> ++ }
> ++
> ++
> ++ $db = new PDO($osu_db);
> ++ if (!$db) {
> ++ error_log("spp.php - Could not access database");
> ++ die("Could not access database");
> ++ }
> ++ $row = $db->query("SELECT password FROM users " .
> ++ "WHERE identity='$user' AND realm='$realm'")->fetch();
> ++ if (!$row) {
> ++ $row = $db->query("SELECT osu_password FROM users " .
> ++ "WHERE osu_user='$user' AND realm='$realm'")->fetch();
> ++ $pw = $row['osu_password'];
> ++ } else
> ++ $pw = $row['password'];
> ++ if (!$row) {
> ++ error_log("spp.php - Authentication failed - user '$user' not found");
> ++ die('Authentication failed');
> ++ }
> ++ if (strlen($pw) < 1) {
> ++ error_log("spp.php - Authentication failed - empty password");
> ++ die('Authentication failed');
> ++ }
> ++
> ++ $A1 = md5($user . ':' . $realm . ':' . $pw);
> ++ $A2 = md5($_SERVER['REQUEST_METHOD'] . ':' . $data['uri']);
> ++ $resp = md5($A1 . ':' . $data['nonce'] . ':' . $data['nc'] . ':' .
> ++ $data['cnonce'] . ':' . $data['qop'] . ':' . $A2);
> ++ if ($data['response'] != $resp) {
> ++ error_log("Authentication failure - response mismatch");
> ++ die('Authentication failed');
> ++ }
> ++} else if (isset($_SERVER["SSL_CLIENT_VERIFY"]) &&
> ++ $_SERVER["SSL_CLIENT_VERIFY"] == "SUCCESS" &&
> ++ isset($_SERVER["SSL_CLIENT_M_SERIAL"])) {
> ++ $user = "cert-" . $_SERVER["SSL_CLIENT_M_SERIAL"];
> ++ putenv("HS20CERT=yes");
> ++} else if (!isset($_SERVER["PATH_INFO"]) ||
> ++ $_SERVER["PATH_INFO"] != "/signup") {
> ++ header('HTTP/1.1 401 Unauthorized');
> ++ header('WWW-Authenticate: Digest realm="'.$realm.
> ++ '",qop="auth",nonce="'.uniqid().'",opaque="'.md5($realm).'"');
> ++ error_log("spp.php - Authentication required (not signup)");
> ++ die('Authentication required (not signup)');
> ++}
> ++
> ++
> ++if (isset($user) && strlen($user) > 0)
> ++ putenv("HS20USER=$user");
> ++else
> ++ putenv("HS20USER");
> ++
> ++putenv("HS20REALM=$realm");
> ++$postdata = file_get_contents("php://input");
> ++putenv("HS20POST=$postdata");
> ++$addr = $_SERVER["REMOTE_ADDR"];
> ++putenv("HS20ADDR=$addr");
> ++
> ++$last = exec("$osu_root/spp/hs20_spp_server -r$osu_root -
> f/tmp/hs20_spp_server.log", $output, $ret);
> ++
> ++if ($ret == 2) {
> ++ if (empty($_SERVER['PHP_AUTH_DIGEST'])) {
> ++ header('HTTP/1.1 401 Unauthorized');
> ++ header('WWW-Authenticate: Digest realm="'.$realm.
> ++ '",qop="auth",nonce="'.uniqid().'",opaque="'.md5($realm).'"');
> ++ error_log("spp.php - Authentication required (ret 2)");
> ++ die('Authentication required');
> ++ } else {
> ++ error_log("spp.php - Unexpected authentication error");
> ++ die("Unexpected authentication error");
> ++ }
> ++}
> ++if ($ret != 0) {
> ++ error_log("spp.php - Failed to process SPP request");
> ++ die("Failed to process SPP request");
> ++}
> ++//error_log("spp.php: Response: " . implode($output));
> ++
> ++header("Content-Type: application/soap+xml");
> ++
> ++echo implode($output);
> ++
> ++?>
> +diff -urN awpa_supplicant-2.6-original/hs20/server/www/users.php
> bwpa_supplicant-2.6-patched-final/hs20/server/www/users.php
> +--- awpa_supplicant-2.6-original/hs20/server/www/users.php 1969-12-31
> 18:00:00.000000000 -0600
> ++++ bwpa_supplicant-2.6-patched-final/hs20/server/www/users.php 2016-10-
> 02 13:51:11.000000000 -0500
> +@@ -0,0 +1,349 @@
> ++<?php
> ++
> ++require('config.php');
> ++
> ++$db = new PDO($osu_db);
> ++if (!$db) {
> ++ die($sqliteerror);
> ++}
> ++
> ++if (isset($_GET["id"])) {
> ++ $id = $_GET["id"];
> ++ if (!is_numeric($id))
> ++ $id = 0;
> ++} else
> ++ $id = 0;
> ++if (isset($_GET["cmd"]))
> ++ $cmd = $_GET["cmd"];
> ++else
> ++ $cmd = '';
> ++
> ++if ($cmd == 'eventlog' && $id > 0) {
> ++ $row = $db->query("SELECT dump FROM eventlog WHERE rowid=$id")-
> >fetch();
> ++ $dump = $row['dump'];
> ++ if ($dump[0] == '<') {
> ++ header("Content-type: text/xml");
> ++ echo "<?xml version=\"1.0\"?>\n";
> ++ echo $dump;
> ++ } else {
> ++ header("Content-type: text/plain");
> ++ echo $dump;
> ++ }
> ++ exit;
> ++}
> ++
> ++if ($cmd == 'mo' && $id > 0) {
> ++ $mo = $_GET["mo"];
> ++ if (!isset($mo))
> ++ exit;
> ++ if ($mo != "devinfo" && $mo != "devdetail" && $mo != "pps")
> ++ exit;
> ++ $row = $db->query("SELECT $mo FROM users WHERE rowid=$id")-
> >fetch();
> ++ header("Content-type: text/xml");
> ++ echo "<?xml version=\"1.0\"?>\n";
> ++ echo $row[$mo];
> ++ exit;
> ++}
> ++
> ++if ($cmd == 'cert' && $id > 0) {
> ++ $row = $db->query("SELECT cert_pem FROM users WHERE rowid=$id")-
> >fetch();
> ++ header("Content-type: text/plain");
> ++ echo $row['cert_pem'];
> ++ exit;
> ++}
> ++
> ++?>
> ++
> ++<html>
> ++<head><title>HS 2.0 users</title></head>
> ++<body>
> ++
> ++<?php
> ++
> ++if ($cmd == 'subrem-clear' && $id > 0) {
> ++ $db->exec("UPDATE users SET remediation='' WHERE rowid=$id");
> ++}
> ++if ($cmd == 'subrem-add-user' && $id > 0) {
> ++ $db->exec("UPDATE users SET remediation='user' WHERE rowid=$id");
> ++}
> ++if ($cmd == 'subrem-add-machine' && $id > 0) {
> ++ $db->exec("UPDATE users SET remediation='machine' WHERE
> rowid=$id");
> ++}
> ++if ($cmd == 'subrem-add-policy' && $id > 0) {
> ++ $db->exec("UPDATE users SET remediation='policy' WHERE rowid=$id");
> ++}
> ++if ($cmd == 'subrem-add-free' && $id > 0) {
> ++ $db->exec("UPDATE users SET remediation='free' WHERE rowid=$id");
> ++}
> ++if ($cmd == 'fetch-pps-on' && $id > 0) {
> ++ $db->exec("UPDATE users SET fetch_pps=1 WHERE rowid=$id");
> ++}
> ++if ($cmd == 'fetch-pps-off' && $id > 0) {
> ++ $db->exec("UPDATE users SET fetch_pps=0 WHERE rowid=$id");
> ++}
> ++if ($cmd == 'reset-pw' && $id > 0) {
> ++ $db->exec("UPDATE users SET password='ChangeMe' WHERE rowid=$id");
> ++}
> ++if ($cmd == "policy" && $id > 0 && isset($_GET["policy"])) {
> ++ $policy = $_GET["policy"];
> ++ if ($policy == "no-policy" ||
> ++ is_readable("$osu_root/spp/policy/$policy.xml")) {
> ++ $db->exec("UPDATE users SET policy='$policy' WHERE
> rowid=$id");
> ++ }
> ++}
> ++if ($cmd == "account-type" && $id > 0 && isset($_GET["type"])) {
> ++ $type = $_GET["type"];
> ++ if ($type == "shared")
> ++ $db->exec("UPDATE users SET shared=1 WHERE rowid=$id");
> ++ if ($type == "default")
> ++ $db->exec("UPDATE users SET shared=0 WHERE rowid=$id");
> ++}
> ++
> ++if ($cmd == "set-osu-cred" && $id > 0) {
> ++ $osu_user = $_POST["osu_user"];
> ++ $osu_password = $_POST["osu_password"];
> ++ if (strlen($osu_user) == 0)
> ++ $osu_password = "";
> ++ $db->exec("UPDATE users SET osu_user='$osu_user',
> osu_password='$osu_password' WHERE rowid=$id");
> ++}
> ++
> ++$dump = 0;
> ++
> ++if ($id > 0) {
> ++
> ++if (isset($_GET["dump"])) {
> ++ $dump = $_GET["dump"];
> ++ if (!is_numeric($dump))
> ++ $dump = 0;
> ++} else
> ++ $dump = 0;
> ++
> ++echo "[<a href=\"users.php\">All users</a>] ";
> ++if ($dump == 0)
> ++ echo "[<a href=\"users.php?id=$id&dump=1\">Include debug dump</a>]
> ";
> ++else
> ++ echo "[<a href=\"users.php?id=$id\">Without debug dump</a>] ";
> ++echo "<br>\n";
> ++
> ++$row = $db->query("SELECT rowid,* FROM users WHERE rowid=$id")->fetch();
> ++
> ++echo "<H3>" . $row['identity'] . "@" . $row['realm'] . "</H3>\n";
> ++
> ++echo "MO: ";
> ++if (strlen($row['devinfo']) > 0) {
> ++ echo "[<a
> href=\"users.php?cmd=mo&id=$id&mo=devinfo\">DevInfo</a>]\n";
> ++}
> ++if (strlen($row['devdetail']) > 0) {
> ++ echo "[<a
> href=\"users.php?cmd=mo&id=$id&mo=devdetail\">DevDetail</a>]\n";
> ++}
> ++if (strlen($row['pps']) > 0) {
> ++ echo "[<a href=\"users.php?cmd=mo&id=$id&mo=pps\">PPS</a>]\n";
> ++}
> ++if (strlen($row['cert_pem']) > 0) {
> ++ echo "[<a href=\"users.php?cmd=cert&id=$id\">Certificate</a>]\n";
> ++}
> ++echo "<BR>\n";
> ++
> ++echo "Fetch PPS MO: ";
> ++if ($row['fetch_pps'] == "1") {
> ++ echo "On next connection " .
> ++ "[<a href=\"users.php?cmd=fetch-pps-off&id=$id\">" .
> ++ "do not fetch</a>]<br>\n";
> ++} else {
> ++ echo "Do not fetch " .
> ++ "[<a href=\"users.php?cmd=fetch-pps-on&id=$id\">" .
> ++ "request fetch</a>]<br>\n";
> ++}
> ++
> ++$cert = $row['cert'];
> ++if (strlen($cert) > 0) {
> ++ echo "Certificate fingerprint: $cert<br>\n";
> ++}
> ++
> ++echo "Remediation: ";
> ++$rem = $row['remediation'];
> ++if ($rem == "") {
> ++ echo "Not required";
> ++ echo " [<a href=\"users.php?cmd=subrem-add-user&id=" .
> ++ $row['rowid'] . "\">add:user</a>]";
> ++ echo " [<a href=\"users.php?cmd=subrem-add-machine&id=" .
> ++ $row['rowid'] . "\">add:machine</a>]";
> ++ echo " [<a href=\"users.php?cmd=subrem-add-policy&id=" .
> ++ $row['rowid'] . "\">add:policy</a>]";
> ++ echo " [<a href=\"users.php?cmd=subrem-add-free&id=" .
> ++ $row['rowid'] . "\">add:free</a>]";
> ++} else if ($rem == "user") {
> ++ echo "User [<a href=\"users.php?cmd=subrem-clear&id=" .
> ++ $row['rowid'] . "\">clear</a>]";
> ++} else if ($rem == "policy") {
> ++ echo "Policy [<a href=\"users.php?cmd=subrem-clear&id=" .
> ++ $row['rowid'] . "\">clear</a>]";
> ++} else if ($rem == "free") {
> ++ echo "Free [<a href=\"users.php?cmd=subrem-clear&id=" .
> ++ $row['rowid'] . "\">clear</a>]";
> ++} else {
> ++ echo "Machine [<a href=\"users.php?cmd=subrem-clear&id=" .
> ++ $row['rowid'] . "\">clear</a>]";
> ++}
> ++echo "<br>\n";
> ++
> ++echo "<form>Policy: <select name=\"policy\" " .
> ++ "onChange=\"window.location='users.php?cmd=policy&id=" .
> ++ $row['rowid'] . "&policy=' + this.value;\">\n";
> ++echo "<option value=\"" . $row['policy'] . "\" selected>" . $row['policy'] .
> ++ "</option>\n";
> ++$files = scandir("$osu_root/spp/policy");
> ++foreach ($files as $file) {
> ++ if (!preg_match("/.xml$/", $file))
> ++ continue;
> ++ if ($file == $row['policy'] . ".xml")
> ++ continue;
> ++ $p = substr($file, 0, -4);
> ++ echo "<option value=\"$p\">$p</option>\n";
> ++}
> ++echo "<option value=\"no-policy\">no policy</option>\n";
> ++echo "</select></form>\n";
> ++
> ++echo "<form>Account type: <select name=\"type\" " .
> ++ "onChange=\"window.location='users.php?cmd=account-type&id=" .
> ++ $row['rowid'] . "&type=' + this.value;\">\n";
> ++if ($row['shared'] > 0) {
> ++ $default_sel = "";
> ++ $shared_sel = " selected";
> ++} else {
> ++ $default_sel = " selected";
> ++ $shared_sel = "";
> ++}
> ++echo "<option value=\"default\"$default_sel>default</option>\n";
> ++echo "<option value=\"shared\"$shared_sel>shared</option>\n";
> ++echo "</select></form>\n";
> ++
> ++echo "Phase 2 method(s): " . $row['methods'] . "<br>\n";
> ++
> ++echo "<br>\n";
> ++echo "<a href=\"users.php?cmd=reset-pw&id=" .
> ++ $row['rowid'] . "\">Reset AAA password</a><br>\n";
> ++
> ++echo "<br>\n";
> ++echo "<form action=\"users.php?cmd=set-osu-cred&id=" . $row['rowid'] .
> ++ "\" method=\"POST\">\n";
> ++echo "OSU credentials (if username empty, AAA credentials are used):<br>\n";
> ++echo "username: <input type=\"text\" name=\"osu_user\" value=\"" .
> ++ $row['osu_user'] . "\">\n";
> ++echo "password: <input type=\"password\" name=\"osu_password\">\n";
> ++echo "<input type=\"submit\" value=\"Set OSU credentials\">\n";
> ++echo "</form>\n";
> ++
> ++echo "<hr>\n";
> ++
> ++$user = $row['identity'];
> ++$osu_user = $row['osu_user'];
> ++$realm = $row['realm'];
> ++}
> ++
> ++if ($id > 0 || ($id == 0 && $cmd == 'eventlog')) {
> ++
> ++ if ($id == 0) {
> ++ echo "[<a href=\"users.php\">All users</a>] ";
> ++ echo "<br>\n";
> ++ }
> ++
> ++echo "<table border=1>\n";
> ++echo "<tr>";
> ++if ($id == 0) {
> ++ echo "<th>user<th>realm";
> ++}
> ++echo "<th>time<th>address<th>sessionID<th>notes";
> ++if ($dump > 0)
> ++ echo "<th>dump";
> ++echo "\n";
> ++if (isset($_GET["limit"])) {
> ++ $limit = $_GET["limit"];
> ++ if (!is_numeric($limit))
> ++ $limit = 20;
> ++} else
> ++ $limit = 20;
> ++if ($id == 0)
> ++ $res = $db->query("SELECT rowid,* FROM eventlog ORDER BY timestamp DESC
> LIMIT $limit");
> ++else if (strlen($osu_user) > 0)
> ++ $res = $db->query("SELECT rowid,* FROM eventlog WHERE (user='$user' OR
> user='$osu_user') AND realm='$realm' ORDER BY timestamp DESC LIMIT $limit");
> ++else
> ++ $res = $db->query("SELECT rowid,* FROM eventlog WHERE user='$user' AND
> realm='$realm' ORDER BY timestamp DESC LIMIT $limit");
> ++foreach ($res as $row) {
> ++ echo "<tr>";
> ++ if ($id == 0) {
> ++ echo "<td>" . $row['user'] . "\n";
> ++ echo "<td>" . $row['realm'] . "\n";
> ++ }
> ++ echo "<td>" . $row['timestamp'] . "\n";
> ++ echo "<td>" . $row['addr'] . "\n";
> ++ echo "<td>" . $row['sessionid'] . "\n";
> ++ echo "<td>" . $row['notes'] . "\n";
> ++ $d = $row['dump'];
> ++ if (strlen($d) > 0) {
> ++ echo "[<a href=\"users.php?cmd=eventlog&id=" . $row['rowid'] .
> ++ "\">";
> ++ if ($d[0] == '<')
> ++ echo "XML";
> ++ else
> ++ echo "txt";
> ++ echo "</a>]\n";
> ++ if ($dump > 0)
> ++ echo "<td>" . htmlspecialchars($d) . "\n";
> ++ }
> ++}
> ++echo "</table>\n";
> ++
> ++}
> ++
> ++
> ++if ($id == 0 && $cmd != 'eventlog') {
> ++
> ++echo "[<a href=\"users.php?cmd=eventlog&limit=50\">Eventlog</a>] ";
> ++echo "<br>\n";
> ++
> ++echo "<table border=1>\n";
> ++echo "<tr><th>User<th>Realm<th>Remediation<th>Policy<th>Account
> type<th>Phase 2 method(s)<th>DevId\n";
> ++
> ++$res = $db->query('SELECT rowid,* FROM users WHERE phase2=1');
> ++foreach ($res as $row) {
> ++ echo "<tr><td><a href=\"users.php?id=" . $row['rowid'] . "\"> " .
> ++ $row['identity'] . " </a>";
> ++ echo "<td>" . $row['realm'];
> ++ $rem = $row['remediation'];
> ++ echo "<td>";
> ++ if ($rem == "") {
> ++ echo "Not required";
> ++ } else if ($rem == "user") {
> ++ echo "User";
> ++ } else if ($rem == "policy") {
> ++ echo "Policy";
> ++ } else if ($rem == "free") {
> ++ echo "Free";
> ++ } else {
> ++ echo "Machine";
> ++ }
> ++ echo "<td>" . $row['policy'];
> ++ if ($row['shared'] > 0)
> ++ echo "<td>shared";
> ++ else
> ++ echo "<td>default";
> ++ echo "<td>" . $row['methods'];
> ++ echo "<td>";
> ++ $xml = xml_parser_create();
> ++ xml_parse_into_struct($xml, $row['devinfo'], $devinfo);
> ++ foreach($devinfo as $k) {
> ++ if ($k['tag'] == 'DEVID') {
> ++ echo $k['value'];
> ++ break;
> ++ }
> ++ }
> ++ echo "\n";
> ++}
> ++echo "</table>\n";
> ++
> ++}
> ++
> ++?>
> ++
> ++</html>
> diff --git a/meta-xilinx-contrib/recipes-connectivity/wpa-supplicant/wpa-
> supplicant_%.bbappend b/meta-xilinx-contrib/recipes-connectivity/wpa-
> supplicant/wpa-supplicant_%.bbappend
> new file mode 100644
> index 0000000..4225667
> --- /dev/null
> +++ b/meta-xilinx-contrib/recipes-connectivity/wpa-supplicant/wpa-
> supplicant_%.bbappend
> @@ -0,0 +1,4 @@
> +FILESEXTRAPATHS_prepend := "${THISDIR}/${PN}:"
> +
> +SRC_URI_append_minized-zynq7 = " file://0001-murata-wpa_supplication-Add-
> server-in-hs20.patch"
> +
> diff --git a/meta-xilinx-contrib/recipes-kernel/cypress-orga-backport/cypress-orga-
> backport_4.12.bb b/meta-xilinx-contrib/recipes-kernel/cypress-orga-
> backport/cypress-orga-backport_4.12.bb
> new file mode 100644
> index 0000000..a9b1ad4
> --- /dev/null
> +++ b/meta-xilinx-contrib/recipes-kernel/cypress-orga-backport/cypress-orga-
> backport_4.12.bb
> @@ -0,0 +1,73 @@
> +# Copyright (C) 2017 Khem Raj <raj.khem at gmail.com>
> +# Released under the MIT license (see COPYING.MIT for the terms)
> +
> +
> +DESCRIPTION = "Cypress Orga Wi-Fi driver backport recipe"
> +HOMEPAGE = "https://github.com/murata-wireless"
> +SECTION = "kernel/modules"
> +LICENSE = "GPLv2"
> +LIC_FILES_CHKSUM =
> "file://COPYING;md5=d7810fab7487fb0aad327b76f1be7cd7"
> +
> +SRC_URI = "git://github.com/murata-wireless/cyw-fmac-v4.12-
> orga;protocol=http;branch=imx-morty-orga"
> +SRCREV = "dc0592f5b81d427d91ec706c92e8337710a894a8"
> +
> +S = "${WORKDIR}/git"
> +
> +EXTRA_OEMAKE = "KLIB_BUILD=${STAGING_KERNEL_DIR} KLIB=${D}
> DESTDIR=${D}"
> +
> +DEPENDS += "virtual/kernel"
> +inherit module-base
> +addtask make_scripts after do_patch before do_configure
> +do_make_scripts[lockfiles] = "${TMPDIR}/kernel-scripts.lock"
> +do_make_scripts[deptask] = "do_populate_sysroot"
> +
> +do_configure_prepend() {
> + cp ${STAGING_KERNEL_BUILDDIR}/.config
> ${STAGING_KERNEL_DIR}/.config
> + CC=${BUILD_CC} oe_runmake defconfig-brcmfmac
> +}
> +
> +do_configure_append() {
> + unset LDFLAGS
> + oe_runmake
> +}
> +
> +
> +
> +
> +do_compile() {
> + echo "KERNEL VERSION: ${KERNEL_VERSION}"
> + unset CFLAGS CPPFLAGS CXXFLAGS LDFLAGS
> + oe_runmake KERNEL_PATH=${STAGING_KERNEL_DIR} \
> + KERNEL_SRC=${STAGING_KERNEL_DIR} \
> + KERNEL_VERSION=${KERNEL_VERSION} \
> + CC="${KERNEL_CC}" LD="${KERNEL_LD}" \
> + AR="${KERNEL_AR}" \
> + ${MAKE_TARGETS}
> +}
> +
> +do_install() {
> +
> + install -d ${D}/lib/modules/${KERNEL_VERSION}/updates/compat
> + install -d ${D}/lib/modules/${KERNEL_VERSION}/updates/net/wireless
> + install -d
> ${D}/lib/modules/${KERNEL_VERSION}/updates/drivers/net/wireless/broadcom/b
> rcm80211/brcmutil
> + install -d
> ${D}/lib/modules/${KERNEL_VERSION}/updates/drivers/net/wireless/broadcom/b
> rcm80211/brcmfmac
> +
> + install -m 644 ${S}/compat/compat.ko \
> +
> ${D}/lib/modules/${KERNEL_VERSION}/updates/compat/compat.ko
> + install -m 644 ${S}/net/wireless/cfg80211.ko \
> +
> ${D}/lib/modules/${KERNEL_VERSION}/updates/net/wireless/cfg80211.ko
> + install -m 644
> ${S}/drivers/net/wireless/broadcom/brcm80211/brcmutil/brcmutil.ko \
> +
> ${D}/lib/modules/${KERNEL_VERSION}/updates/drivers/net/wireless/broa
> dcom/brcm80211/brcmutil/brcmutil.ko
> + install -m 644
> ${S}/drivers/net/wireless/broadcom/brcm80211/brcmfmac/brcmfmac.ko \
> +
> ${D}/lib/modules/${KERNEL_VERSION}/updates/drivers/net/wireless/broa
> dcom/brcm80211/brcmfmac/brcmfmac.ko
> +
> + rm ${STAGING_KERNEL_DIR}/.config
> +}
> +
> +
> +FILES_${PN} = " \
> + /lib/modules/${KERNEL_VERSION}/updates/compat/compat.ko \
> + /lib/modules/${KERNEL_VERSION}/updates/net/wireless/cfg80211.ko \
> +
> /lib/modules/${KERNEL_VERSION}/updates/drivers/net/wireless/broadco
> m/brcm80211/brcmutil/brcmutil.ko \
> +
> /lib/modules/${KERNEL_VERSION}/updates/drivers/net/wireless/broadco
> m/brcm80211/brcmfmac/brcmfmac.ko \
> +"
> diff --git a/meta-xilinx-contrib/recipes-kernel/linux/linux-xlnx/v2017.3/wifi-
> bluetooth.cfg b/meta-xilinx-contrib/recipes-kernel/linux/linux-xlnx/v2017.3/wifi-
> bluetooth.cfg
> new file mode 100644
> index 0000000..f71e53a
> --- /dev/null
> +++ b/meta-xilinx-contrib/recipes-kernel/linux/linux-xlnx/v2017.3/wifi-
> bluetooth.cfg
> @@ -0,0 +1,33 @@
> +#
> +# Bluetooth config
> +#
> +CONFIG_BT=y
> +CONFIG_BT_BREDR=y
> +CONFIG_BT_HS=y
> +CONFIG_BT_LE=y
> +CONFIG_BT_BCM=y
> +CONFIG_BT_HCIUART=y
> +CONFIG_BT_HCIUART_H4=y
> +CONFIG_BT_HCIUART_BCM=y
> +CONFIG_BT_HIDP=y
> +CONFIG_CFG80211=y
> +CONFIG_CFG80211_DEFAULT_PS=y
> +CONFIG_CFG80211_CRDA_SUPPORT=y
> +CONFIG_BRCMUTIL=y
> +CONFIG_BRCMFMAC=y
> +CONFIG_BRCMFMAC_PROTO_BCDC=y
> +CONFIG_BRCMFMAC_SDIO=y
> +CONFIG_CRYPTO_BLKCIPHER=y
> +CONFIG_CRYPTO_MANAGER=y
> +CONFIG_CRYPTO_ECB=y
> +CONFIG_CRYPTO_CMAC=y
> +CONFIG_CRYPTO_SHA256=y
> +
> +#
> +# Regulator config
> +#
> +CONFIG_REGMAP_IRQ=y
> +CONFIG_I2C_XILINX=y
> +CONFIG_MFD_DA9062=y
> +CONFIG_REGULATOR_DA9062=y
> +
> diff --git a/meta-xilinx-contrib/recipes-kernel/linux/linux-xlnx_2017.3.bbappend
> b/meta-xilinx-contrib/recipes-kernel/linux/linux-xlnx_2017.3.bbappend
> index 83b08f1..48ff77a 100644
> --- a/meta-xilinx-contrib/recipes-kernel/linux/linux-xlnx_2017.3.bbappend
> +++ b/meta-xilinx-contrib/recipes-kernel/linux/linux-xlnx_2017.3.bbappend
> @@ -6,3 +6,4 @@ SRC_URI_append_zybo-linux-bd-zynq7 = " \
> file://0003-drm-xilinx-Fix-DPMS-transition-to-on.patch \
> "
>
> +SRC_URI_append_minized-zynq7 = " file://wifi-bluetooth.cfg"
> --
> 2.7.4
>
This patch is way too long to complete the review.
Can you split the patches as a series and resubmit
Thanks,
Manju
More information about the meta-xilinx
mailing list