diff options
Diffstat (limited to 'hs20')
44 files changed, 0 insertions, 12397 deletions
diff --git a/hs20/client/.gitignore b/hs20/client/.gitignore deleted file mode 100644 index f6c13d3e5dfa..000000000000 --- a/hs20/client/.gitignore +++ /dev/null @@ -1,4 +0,0 @@ -hs20-osu-client -SP -osu-ca.pem -spp.xsd diff --git a/hs20/client/Android.mk b/hs20/client/Android.mk deleted file mode 100644 index e4db32208d50..000000000000 --- a/hs20/client/Android.mk +++ /dev/null @@ -1,81 +0,0 @@ -LOCAL_PATH := $(call my-dir) - -INCLUDES = $(LOCAL_PATH) -INCLUDES += $(LOCAL_PATH)/../../src/utils -INCLUDES += $(LOCAL_PATH)/../../src/common -INCLUDES += $(LOCAL_PATH)/../../src -INCLUDES += external/libxml2/include -INCLUDES += external/curl/include -INCLUDES += external/webkit/Source/WebKit/gtk - -# We try to keep this compiling against older platform versions. -# The new icu location (external/icu) exports its own headers, but -# the older versions in external/icu4c don't, and we need to add those -# headers to the include path by hand. -ifeq ($(wildcard external/icu),) -INCLUDES += external/icu4c/common -else -# The LOCAL_EXPORT_C_INCLUDE_DIRS from ICU did not seem to fully resolve the -# build (e.g., "mm -B" failed to build, but following that with "mm" allowed -# the build to complete). For now, add the include directory manually here for -# Android 5.0. -ver = $(filter 5.0%,$(PLATFORM_VERSION)) -ifneq (,$(strip $(ver))) -INCLUDES += external/icu/icu4c/source/common -endif -endif - - -L_CFLAGS += -DCONFIG_CTRL_IFACE -L_CFLAGS += -DCONFIG_CTRL_IFACE_UNIX -L_CFLAGS += -DCONFIG_CTRL_IFACE_CLIENT_DIR=\"/data/misc/wifi/sockets\" - -OBJS = spp_client.c -OBJS += oma_dm_client.c -OBJS += osu_client.c -OBJS += est.c -OBJS += ../../src/common/wpa_ctrl.c -OBJS += ../../src/common/wpa_helpers.c -OBJS += ../../src/utils/xml-utils.c -#OBJS += ../../src/utils/browser-android.c -OBJS += ../../src/utils/browser-wpadebug.c -OBJS += ../../src/utils/wpabuf.c -OBJS += ../../src/utils/eloop.c -OBJS += ../../src/wps/httpread.c -OBJS += ../../src/wps/http_server.c -OBJS += ../../src/utils/xml_libxml2.c -OBJS += ../../src/utils/http_curl.c -OBJS += ../../src/utils/base64.c -OBJS += ../../src/utils/os_unix.c -L_CFLAGS += -DCONFIG_DEBUG_FILE -OBJS += ../../src/utils/wpa_debug.c -OBJS += ../../src/utils/common.c -OBJS += ../../src/crypto/crypto_internal.c -OBJS += ../../src/crypto/md5-internal.c -OBJS += ../../src/crypto/sha1-internal.c -OBJS += ../../src/crypto/sha256-internal.c -OBJS += ../../src/crypto/tls_openssl_ocsp.c - -L_CFLAGS += -DEAP_TLS_OPENSSL - -L_CFLAGS += -Wno-unused-parameter - - -######################## -include $(CLEAR_VARS) -LOCAL_MODULE := hs20-osu-client -LOCAL_MODULE_TAGS := optional - -LOCAL_SHARED_LIBRARIES := libc libcutils -LOCAL_SHARED_LIBRARIES += libcrypto libssl -#LOCAL_SHARED_LIBRARIES += libxml2 -LOCAL_STATIC_LIBRARIES += libxml2 -LOCAL_SHARED_LIBRARIES += libicuuc -LOCAL_SHARED_LIBRARIES += libcurl - -LOCAL_CFLAGS := $(L_CFLAGS) -LOCAL_SRC_FILES := $(OBJS) -LOCAL_C_INCLUDES := $(INCLUDES) -include $(BUILD_EXECUTABLE) - -######################## diff --git a/hs20/client/Makefile b/hs20/client/Makefile deleted file mode 100644 index 4dcfe2d3bf2c..000000000000 --- a/hs20/client/Makefile +++ /dev/null @@ -1,81 +0,0 @@ -ALL=hs20-osu-client - -include ../../src/build.rules - -CFLAGS += -I../../src/utils -CFLAGS += -I../../src/common -CFLAGS += -I../../src - -ifndef CONFIG_NO_BROWSER -ifndef CONFIG_BROWSER_SYSTEM -TEST_WK := $(shell pkg-config --silence-errors --cflags webkitgtk-3.0) -ifeq ($(TEST_WK),) -# Try webkit2 -GTKCFLAGS := $(shell pkg-config --cflags gtk+-3.0 webkit2gtk-4.0) -GTKLIBS := $(shell pkg-config --libs gtk+-3.0 webkit2gtk-4.0) -CFLAGS += -DUSE_WEBKIT2 -else -GTKCFLAGS := $(shell pkg-config --cflags gtk+-3.0 webkitgtk-3.0) -GTKLIBS := $(shell pkg-config --libs gtk+-3.0 webkitgtk-3.0) -endif - -CFLAGS += $(GTKCFLAGS) -LIBS += $(GTKLIBS) -endif -endif - -OBJS=spp_client.o -OBJS += oma_dm_client.o -OBJS += osu_client.o -OBJS += est.o -OBJS += ../../src/utils/xml-utils.o -CFLAGS += -DCONFIG_CTRL_IFACE -CFLAGS += -DCONFIG_CTRL_IFACE_UNIX -OBJS += ../../src/common/wpa_ctrl.o ../../src/common/wpa_helpers.o -ifdef CONFIG_NO_BROWSER -CFLAGS += -DCONFIG_NO_BROWSER -else -ifdef CONFIG_BROWSER_SYSTEM -OBJS += ../../src/utils/eloop.o -OBJS += ../../src/utils/wpabuf.o -OBJS += ../../src/wps/httpread.o -OBJS += ../../src/wps/http_server.o -OBJS += ../../src/utils/browser-system.o -else -OBJS += ../../src/utils/browser.o -endif -endif -OBJS += ../../src/utils/xml_libxml2.o -OBJS += ../../src/utils/http_curl.o -OBJS += ../../src/utils/base64.o -OBJS += ../../src/utils/os_unix.o -CFLAGS += -DCONFIG_DEBUG_FILE -OBJS += ../../src/utils/wpa_debug.o -OBJS += ../../src/utils/common.o -OBJS += ../../src/crypto/crypto_internal.o -OBJS += ../../src/crypto/md5-internal.o -OBJS += ../../src/crypto/sha1-internal.o -OBJS += ../../src/crypto/sha256-internal.o - -CFLAGS += $(shell xml2-config --cflags) -LIBS += $(shell xml2-config --libs) - -# Allow static/custom linking of libcurl. -ifdef CUST_CURL_LINKAGE -LIBS += ${CUST_CURL_LINKAGE} -else -LIBS += -lcurl -endif - -CFLAGS += -DEAP_TLS_OPENSSL -OBJS += ../../src/crypto/tls_openssl_ocsp.o -LIBS += -lssl -lcrypto - -_OBJS_VAR := OBJS -include ../../src/objs.mk -hs20-osu-client: $(OBJS) - $(Q)$(LDO) $(LDFLAGS) -o hs20-osu-client $(OBJS) $(LIBS) - @$(E) " LD " $@ - -clean: common-clean - rm -f core *~ diff --git a/hs20/client/devdetail.xml b/hs20/client/devdetail.xml deleted file mode 100644 index 6d0389e8a133..000000000000 --- a/hs20/client/devdetail.xml +++ /dev/null @@ -1,47 +0,0 @@ -<DevDetail xmlns="urn:oma:mo:oma-dm-devdetail:1.0"> - <Ext> - <org.wi-fi> - <Wi-Fi> - <EAPMethodList> - <EAPMethod1> - <EAPType>13</EAPType> - </EAPMethod1> - <EAPMethod2> - <EAPType>21</EAPType> - <InnerMethod>MS-CHAP-V2</InnerMethod> - </EAPMethod2> - <EAPMethod3> - <EAPType>18</EAPType> - </EAPMethod3> - <EAPMethod4> - <EAPType>23</EAPType> - </EAPMethod4> - <EAPMethod5> - <EAPType>50</EAPType> - </EAPMethod5> - </EAPMethodList> - <ManufacturingCertificate>false</ManufacturingCertificate> - <Wi-FiMACAddress>020102030405</Wi-FiMACAddress> - <IMSI>310026000000000</IMSI> - <IMEI_MEID>imei:490123456789012</IMEI_MEID> - <ClientTriggerRedirectURI>http://localhost:12345/</ClientTriggerRedirectURI> - <Ops> - <launchBrowserToURI></launchBrowserToURI> - <negotiateClientCertTLS></negotiateClientCertTLS> - <getCertificate></getCertificate> - </Ops> - </Wi-Fi> - </org.wi-fi> - </Ext> - <URI> - <MaxDepth>0</MaxDepth> - <MaxTotLen>0</MaxTotLen> - <MaxSegLen>0</MaxSegLen> - </URI> - <DevType>MobilePhone</DevType> - <OEM>Manufacturer</OEM> - <FwV>1.0</FwV> - <SwV>1.0</SwV> - <HwV>1.0</HwV> - <LrgObj>false</LrgObj> -</DevDetail> diff --git a/hs20/client/devinfo.xml b/hs20/client/devinfo.xml deleted file mode 100644 index d48a520a98a1..000000000000 --- a/hs20/client/devinfo.xml +++ /dev/null @@ -1,7 +0,0 @@ -<DevInfo xmlns="urn:oma:mo:oma-dm-devinfo:1.0"> - <DevId>urn:Example:HS20-station:123456</DevId> - <Man>Manufacturer</Man> - <Mod>HS20-station</Mod> - <DmV>1.2</DmV> - <Lang>en</Lang> -</DevInfo> diff --git a/hs20/client/est.c b/hs20/client/est.c deleted file mode 100644 index 97f9132100c4..000000000000 --- a/hs20/client/est.c +++ /dev/null @@ -1,769 +0,0 @@ -/* - * Hotspot 2.0 OSU client - EST client - * Copyright (c) 2012-2014, Qualcomm Atheros, Inc. - * - * This software may be distributed under the terms of the BSD license. - * See README for more details. - */ - -#include "includes.h" -#include <openssl/err.h> -#include <openssl/evp.h> -#include <openssl/pem.h> -#include <openssl/pkcs7.h> -#include <openssl/rsa.h> -#include <openssl/asn1.h> -#include <openssl/asn1t.h> -#include <openssl/x509.h> -#include <openssl/x509v3.h> -#include <openssl/opensslv.h> -#ifdef OPENSSL_IS_BORINGSSL -#include <openssl/buf.h> -#endif /* OPENSSL_IS_BORINGSSL */ - -#include "common.h" -#include "utils/base64.h" -#include "utils/xml-utils.h" -#include "utils/http-utils.h" -#include "osu_client.h" - - -static int pkcs7_to_cert(struct hs20_osu_client *ctx, const u8 *pkcs7, - size_t len, char *pem_file, char *der_file) -{ -#ifdef OPENSSL_IS_BORINGSSL - CBS pkcs7_cbs; -#else /* OPENSSL_IS_BORINGSSL */ - PKCS7 *p7 = NULL; - const unsigned char *p = pkcs7; -#endif /* OPENSSL_IS_BORINGSSL */ - STACK_OF(X509) *certs; - int i, num, ret = -1; - BIO *out = NULL; - -#ifdef OPENSSL_IS_BORINGSSL - certs = sk_X509_new_null(); - if (!certs) - goto fail; - CBS_init(&pkcs7_cbs, pkcs7, len); - if (!PKCS7_get_certificates(certs, &pkcs7_cbs)) { - wpa_printf(MSG_INFO, "Could not parse PKCS#7 object: %s", - ERR_error_string(ERR_get_error(), NULL)); - write_result(ctx, "Could not parse PKCS#7 object from EST"); - goto fail; - } -#else /* OPENSSL_IS_BORINGSSL */ - p7 = d2i_PKCS7(NULL, &p, len); - if (p7 == NULL) { - wpa_printf(MSG_INFO, "Could not parse PKCS#7 object: %s", - ERR_error_string(ERR_get_error(), NULL)); - write_result(ctx, "Could not parse PKCS#7 object from EST"); - goto fail; - } - - switch (OBJ_obj2nid(p7->type)) { - case NID_pkcs7_signed: - certs = p7->d.sign->cert; - break; - case NID_pkcs7_signedAndEnveloped: - certs = p7->d.signed_and_enveloped->cert; - break; - default: - certs = NULL; - break; - } -#endif /* OPENSSL_IS_BORINGSSL */ - - if (!certs || ((num = sk_X509_num(certs)) == 0)) { - wpa_printf(MSG_INFO, "No certificates found in PKCS#7 object"); - write_result(ctx, "No certificates found in PKCS#7 object"); - goto fail; - } - - if (der_file) { - FILE *f = fopen(der_file, "wb"); - if (f == NULL) - goto fail; - i2d_X509_fp(f, sk_X509_value(certs, 0)); - fclose(f); - } - - if (pem_file) { - out = BIO_new(BIO_s_file()); - if (out == NULL || - BIO_write_filename(out, pem_file) <= 0) - goto fail; - - for (i = 0; i < num; i++) { - X509 *cert = sk_X509_value(certs, i); - X509_print(out, cert); - PEM_write_bio_X509(out, cert); - BIO_puts(out, "\n"); - } - } - - ret = 0; - -fail: -#ifdef OPENSSL_IS_BORINGSSL - if (certs) - sk_X509_pop_free(certs, X509_free); -#else /* OPENSSL_IS_BORINGSSL */ - PKCS7_free(p7); -#endif /* OPENSSL_IS_BORINGSSL */ - if (out) - BIO_free_all(out); - - return ret; -} - - -int est_load_cacerts(struct hs20_osu_client *ctx, const char *url) -{ - char *buf, *resp; - size_t buflen; - unsigned char *pkcs7; - size_t pkcs7_len, resp_len; - int res; - - buflen = os_strlen(url) + 100; - buf = os_malloc(buflen); - if (buf == NULL) - return -1; - - os_snprintf(buf, buflen, "%s/cacerts", url); - wpa_printf(MSG_INFO, "Download EST cacerts from %s", buf); - write_summary(ctx, "Download EST cacerts from %s", buf); - ctx->no_osu_cert_validation = 1; - http_ocsp_set(ctx->http, 1); - res = http_download_file(ctx->http, buf, "Cert/est-cacerts.txt", - ctx->ca_fname); - http_ocsp_set(ctx->http, - (ctx->workarounds & WORKAROUND_OCSP_OPTIONAL) ? 1 : 2); - ctx->no_osu_cert_validation = 0; - if (res < 0) { - wpa_printf(MSG_INFO, "Failed to download EST cacerts from %s", - buf); - write_result(ctx, "Failed to download EST cacerts from %s", - buf); - os_free(buf); - return -1; - } - os_free(buf); - - resp = os_readfile("Cert/est-cacerts.txt", &resp_len); - if (resp == NULL) { - wpa_printf(MSG_INFO, "Could not read Cert/est-cacerts.txt"); - write_result(ctx, "Could not read EST cacerts"); - return -1; - } - - pkcs7 = base64_decode(resp, resp_len, &pkcs7_len); - if (pkcs7 && pkcs7_len < resp_len / 2) { - wpa_printf(MSG_INFO, "Too short base64 decode (%u bytes; downloaded %u bytes) - assume this was binary", - (unsigned int) pkcs7_len, (unsigned int) resp_len); - os_free(pkcs7); - pkcs7 = NULL; - } - if (pkcs7 == NULL) { - wpa_printf(MSG_INFO, "EST workaround - Could not decode base64, assume this is DER encoded PKCS7"); - pkcs7 = os_malloc(resp_len); - if (pkcs7) { - os_memcpy(pkcs7, resp, resp_len); - pkcs7_len = resp_len; - } - } - os_free(resp); - - if (pkcs7 == NULL) { - wpa_printf(MSG_INFO, "Could not fetch PKCS7 cacerts"); - write_result(ctx, "Could not fetch EST PKCS#7 cacerts"); - return -1; - } - - res = pkcs7_to_cert(ctx, pkcs7, pkcs7_len, "Cert/est-cacerts.pem", - NULL); - os_free(pkcs7); - if (res < 0) { - wpa_printf(MSG_INFO, "Could not parse CA certs from PKCS#7 cacerts response"); - write_result(ctx, "Could not parse CA certs from EST PKCS#7 cacerts response"); - return -1; - } - unlink("Cert/est-cacerts.txt"); - - return 0; -} - - -/* - * CsrAttrs ::= SEQUENCE SIZE (0..MAX) OF AttrOrOID - * - * AttrOrOID ::= CHOICE { - * oid OBJECT IDENTIFIER, - * attribute Attribute } - * - * Attribute ::= SEQUENCE { - * type OBJECT IDENTIFIER, - * values SET SIZE(1..MAX) OF OBJECT IDENTIFIER } - */ - -typedef struct { - ASN1_OBJECT *type; - STACK_OF(ASN1_OBJECT) *values; -} Attribute; - -typedef struct { - int type; - union { - ASN1_OBJECT *oid; - Attribute *attribute; - } d; -} AttrOrOID; - -#if OPENSSL_VERSION_NUMBER >= 0x10100000L && !defined(OPENSSL_IS_BORINGSSL) -DEFINE_STACK_OF(AttrOrOID) -#endif - -typedef struct { - int type; - STACK_OF(AttrOrOID) *attrs; -} CsrAttrs; - -ASN1_SEQUENCE(Attribute) = { - ASN1_SIMPLE(Attribute, type, ASN1_OBJECT), - ASN1_SET_OF(Attribute, values, ASN1_OBJECT) -} ASN1_SEQUENCE_END(Attribute); - -ASN1_CHOICE(AttrOrOID) = { - ASN1_SIMPLE(AttrOrOID, d.oid, ASN1_OBJECT), - ASN1_SIMPLE(AttrOrOID, d.attribute, Attribute) -} ASN1_CHOICE_END(AttrOrOID); - -ASN1_CHOICE(CsrAttrs) = { - ASN1_SEQUENCE_OF(CsrAttrs, attrs, AttrOrOID) -} ASN1_CHOICE_END(CsrAttrs); - -IMPLEMENT_ASN1_FUNCTIONS(CsrAttrs); - - -static void add_csrattrs_oid(struct hs20_osu_client *ctx, ASN1_OBJECT *oid, - STACK_OF(X509_EXTENSION) *exts) -{ - char txt[100]; - int res; - - if (!oid) - return; - - res = OBJ_obj2txt(txt, sizeof(txt), oid, 1); - if (res < 0 || res >= (int) sizeof(txt)) - return; - - if (os_strcmp(txt, "1.2.840.113549.1.9.7") == 0) { - wpa_printf(MSG_INFO, "TODO: csrattr challengePassword"); - } else if (os_strcmp(txt, "1.2.840.113549.1.1.11") == 0) { - wpa_printf(MSG_INFO, "csrattr sha256WithRSAEncryption"); - } else { - wpa_printf(MSG_INFO, "Ignore unsupported csrattr oid %s", txt); - } -} - - -static void add_csrattrs_ext_req(struct hs20_osu_client *ctx, - STACK_OF(ASN1_OBJECT) *values, - STACK_OF(X509_EXTENSION) *exts) -{ - char txt[100]; - int i, num, res; - - num = sk_ASN1_OBJECT_num(values); - for (i = 0; i < num; i++) { - ASN1_OBJECT *oid = sk_ASN1_OBJECT_value(values, i); - - res = OBJ_obj2txt(txt, sizeof(txt), oid, 1); - if (res < 0 || res >= (int) sizeof(txt)) - continue; - - if (os_strcmp(txt, "1.3.6.1.1.1.1.22") == 0) { - wpa_printf(MSG_INFO, "TODO: extReq macAddress"); - } else if (os_strcmp(txt, "1.3.6.1.4.1.40808.1.1.3") == 0) { - wpa_printf(MSG_INFO, "TODO: extReq imei"); - } else if (os_strcmp(txt, "1.3.6.1.4.1.40808.1.1.4") == 0) { - wpa_printf(MSG_INFO, "TODO: extReq meid"); - } else if (os_strcmp(txt, "1.3.6.1.4.1.40808.1.1.5") == 0) { - wpa_printf(MSG_INFO, "TODO: extReq DevId"); - } else { - wpa_printf(MSG_INFO, "Ignore unsupported cstattr extensionsRequest %s", - txt); - } - } -} - - -static void add_csrattrs_attr(struct hs20_osu_client *ctx, Attribute *attr, - STACK_OF(X509_EXTENSION) *exts) -{ - char txt[100], txt2[100]; - int i, num, res; - - if (!attr || !attr->type || !attr->values) - return; - - res = OBJ_obj2txt(txt, sizeof(txt), attr->type, 1); - if (res < 0 || res >= (int) sizeof(txt)) - return; - - if (os_strcmp(txt, "1.2.840.113549.1.9.14") == 0) { - add_csrattrs_ext_req(ctx, attr->values, exts); - return; - } - - num = sk_ASN1_OBJECT_num(attr->values); - for (i = 0; i < num; i++) { - ASN1_OBJECT *oid = sk_ASN1_OBJECT_value(attr->values, i); - - res = OBJ_obj2txt(txt2, sizeof(txt2), oid, 1); - if (res < 0 || res >= (int) sizeof(txt2)) - continue; - - wpa_printf(MSG_INFO, "Ignore unsupported cstattr::attr %s oid %s", - txt, txt2); - } -} - - -static void add_csrattrs(struct hs20_osu_client *ctx, CsrAttrs *csrattrs, - STACK_OF(X509_EXTENSION) *exts) -{ - int i, num; - - if (!csrattrs || ! csrattrs->attrs) - return; - -#ifdef OPENSSL_IS_BORINGSSL - num = sk_num(CHECKED_CAST(_STACK *, STACK_OF(AttrOrOID) *, - csrattrs->attrs)); - for (i = 0; i < num; i++) { - AttrOrOID *ao = sk_value( - CHECKED_CAST(_STACK *, const STACK_OF(AttrOrOID) *, - csrattrs->attrs), i); - switch (ao->type) { - case 0: - add_csrattrs_oid(ctx, ao->d.oid, exts); - break; - case 1: - add_csrattrs_attr(ctx, ao->d.attribute, exts); - break; - } - } -#else /* OPENSSL_IS_BORINGSSL */ -#if OPENSSL_VERSION_NUMBER >= 0x10100000L && !defined(OPENSSL_IS_BORINGSSL) - num = sk_AttrOrOID_num(csrattrs->attrs); -#else - num = SKM_sk_num(AttrOrOID, csrattrs->attrs); -#endif - for (i = 0; i < num; i++) { -#if OPENSSL_VERSION_NUMBER >= 0x10100000L && !defined(OPENSSL_IS_BORINGSSL) - AttrOrOID *ao = sk_AttrOrOID_value(csrattrs->attrs, i); -#else - AttrOrOID *ao = SKM_sk_value(AttrOrOID, csrattrs->attrs, i); -#endif - switch (ao->type) { - case 0: - add_csrattrs_oid(ctx, ao->d.oid, exts); - break; - case 1: - add_csrattrs_attr(ctx, ao->d.attribute, exts); - break; - } - } -#endif /* OPENSSL_IS_BORINGSSL */ -} - - -static int generate_csr(struct hs20_osu_client *ctx, char *key_pem, - char *csr_pem, char *est_req, char *old_cert, - CsrAttrs *csrattrs) -{ - EVP_PKEY_CTX *pctx = NULL; - EVP_PKEY *pkey = NULL; - RSA *rsa; - X509_REQ *req = NULL; - int ret = -1; - unsigned int val; - X509_NAME *subj = NULL; - char name[100]; - STACK_OF(X509_EXTENSION) *exts = NULL; - X509_EXTENSION *ex; - BIO *out; - CONF *ctmp = NULL; - - wpa_printf(MSG_INFO, "Generate RSA private key"); - write_summary(ctx, "Generate RSA private key"); - pctx = EVP_PKEY_CTX_new_id(EVP_PKEY_RSA, NULL); - if (!pctx) - return -1; - - if (EVP_PKEY_keygen_init(pctx) <= 0) - goto fail; - - if (EVP_PKEY_CTX_set_rsa_keygen_bits(pctx, 2048) <= 0) - goto fail; - - if (EVP_PKEY_keygen(pctx, &pkey) <= 0) - goto fail; - EVP_PKEY_CTX_free(pctx); - pctx = NULL; - - rsa = EVP_PKEY_get1_RSA(pkey); - if (rsa == NULL) - goto fail; - - if (key_pem) { - FILE *f = fopen(key_pem, "wb"); - if (f == NULL) - goto fail; - if (!PEM_write_RSAPrivateKey(f, rsa, NULL, NULL, 0, NULL, - NULL)) { - wpa_printf(MSG_INFO, "Could not write private key: %s", - ERR_error_string(ERR_get_error(), NULL)); - fclose(f); - goto fail; - } - fclose(f); - } - - wpa_printf(MSG_INFO, "Generate CSR"); - write_summary(ctx, "Generate CSR"); - req = X509_REQ_new(); - if (req == NULL) - goto fail; - - if (old_cert) { - FILE *f; - X509 *cert; - int res; - - f = fopen(old_cert, "r"); - if (f == NULL) - goto fail; - cert = PEM_read_X509(f, NULL, NULL, NULL); - fclose(f); - - if (cert == NULL) - goto fail; - res = X509_REQ_set_subject_name(req, - X509_get_subject_name(cert)); - X509_free(cert); - if (!res) - goto fail; - } else { - os_get_random((u8 *) &val, sizeof(val)); - os_snprintf(name, sizeof(name), "cert-user-%u", val); - subj = X509_NAME_new(); - if (subj == NULL || - !X509_NAME_add_entry_by_txt(subj, "CN", MBSTRING_ASC, - (unsigned char *) name, - -1, -1, 0) || - !X509_REQ_set_subject_name(req, subj)) - goto fail; - X509_NAME_free(subj); - subj = NULL; - } - - if (!X509_REQ_set_pubkey(req, pkey)) - goto fail; - - exts = sk_X509_EXTENSION_new_null(); - if (!exts) - goto fail; - - ex = X509V3_EXT_nconf_nid(ctmp, NULL, NID_basic_constraints, - "CA:FALSE"); - if (ex == NULL || - !sk_X509_EXTENSION_push(exts, ex)) - goto fail; - - ex = X509V3_EXT_nconf_nid(ctmp, NULL, NID_key_usage, - "nonRepudiation,digitalSignature,keyEncipherment"); - if (ex == NULL || - !sk_X509_EXTENSION_push(exts, ex)) - goto fail; - - ex = X509V3_EXT_nconf_nid(ctmp, NULL, NID_ext_key_usage, - "1.3.6.1.4.1.40808.1.1.2"); - if (ex == NULL || - !sk_X509_EXTENSION_push(exts, ex)) - goto fail; - - add_csrattrs(ctx, csrattrs, exts); - - if (!X509_REQ_add_extensions(req, exts)) - goto fail; - sk_X509_EXTENSION_pop_free(exts, X509_EXTENSION_free); - exts = NULL; - - if (!X509_REQ_sign(req, pkey, EVP_sha256())) - goto fail; - - out = BIO_new(BIO_s_mem()); - if (out) { - char *txt; - size_t rlen; - -#if !defined(ANDROID) || !defined(OPENSSL_IS_BORINGSSL) - X509_REQ_print(out, req); -#endif - rlen = BIO_ctrl_pending(out); - txt = os_malloc(rlen + 1); - if (txt) { - int res = BIO_read(out, txt, rlen); - if (res > 0) { - txt[res] = '\0'; - wpa_printf(MSG_MSGDUMP, "OpenSSL: Certificate request:\n%s", - txt); - } - os_free(txt); - } - BIO_free(out); - } - - if (csr_pem) { - FILE *f = fopen(csr_pem, "w"); - if (f == NULL) - goto fail; -#if !defined(ANDROID) || !defined(OPENSSL_IS_BORINGSSL) - X509_REQ_print_fp(f, req); -#endif - if (!PEM_write_X509_REQ(f, req)) { - fclose(f); - goto fail; - } - fclose(f); - } - - if (est_req) { - BIO *mem = BIO_new(BIO_s_mem()); - BUF_MEM *ptr; - char *pos, *end, *buf_end; - FILE *f; - - if (mem == NULL) - goto fail; - if (!PEM_write_bio_X509_REQ(mem, req)) { - BIO_free(mem); - goto fail; - } - - BIO_get_mem_ptr(mem, &ptr); - pos = ptr->data; - buf_end = pos + ptr->length; - - /* Remove START/END lines */ - while (pos < buf_end && *pos != '\n') - pos++; - if (pos == buf_end) { - BIO_free(mem); - goto fail; - } - pos++; - - end = pos; - while (end < buf_end && *end != '-') - end++; - - f = fopen(est_req, "w"); - if (f == NULL) { - BIO_free(mem); - goto fail; - } - fwrite(pos, end - pos, 1, f); - fclose(f); - - BIO_free(mem); - } - - ret = 0; -fail: - if (exts) - sk_X509_EXTENSION_pop_free(exts, X509_EXTENSION_free); - if (subj) - X509_NAME_free(subj); - if (req) - X509_REQ_free(req); - if (pkey) - EVP_PKEY_free(pkey); - if (pctx) - EVP_PKEY_CTX_free(pctx); - return ret; -} - - -int est_build_csr(struct hs20_osu_client *ctx, const char *url) -{ - char *buf; - size_t buflen; - int res; - char old_cert_buf[200]; - char *old_cert = NULL; - CsrAttrs *csrattrs = NULL; - - buflen = os_strlen(url) + 100; - buf = os_malloc(buflen); - if (buf == NULL) - return -1; - - os_snprintf(buf, buflen, "%s/csrattrs", url); - wpa_printf(MSG_INFO, "Download csrattrs from %s", buf); - write_summary(ctx, "Download EST csrattrs from %s", buf); - ctx->no_osu_cert_validation = 1; - http_ocsp_set(ctx->http, 1); - res = http_download_file(ctx->http, buf, "Cert/est-csrattrs.txt", - ctx->ca_fname); - http_ocsp_set(ctx->http, - (ctx->workarounds & WORKAROUND_OCSP_OPTIONAL) ? 1 : 2); - ctx->no_osu_cert_validation = 0; - os_free(buf); - if (res < 0) { - wpa_printf(MSG_INFO, "Failed to download EST csrattrs - assume no extra attributes are needed"); - } else { - size_t resp_len; - char *resp; - unsigned char *attrs; - const unsigned char *pos; - size_t attrs_len; - - resp = os_readfile("Cert/est-csrattrs.txt", &resp_len); - if (resp == NULL) { - wpa_printf(MSG_INFO, "Could not read csrattrs"); - return -1; - } - - attrs = base64_decode(resp, resp_len, &attrs_len); - os_free(resp); - - if (attrs == NULL) { - wpa_printf(MSG_INFO, "Could not base64 decode csrattrs"); - return -1; - } - unlink("Cert/est-csrattrs.txt"); - - pos = attrs; - csrattrs = d2i_CsrAttrs(NULL, &pos, attrs_len); - os_free(attrs); - if (csrattrs == NULL) { - wpa_printf(MSG_INFO, "Failed to parse csrattrs ASN.1"); - /* Continue assuming no additional requirements */ - } - } - - if (ctx->client_cert_present) { - os_snprintf(old_cert_buf, sizeof(old_cert_buf), - "SP/%s/client-cert.pem", ctx->fqdn); - old_cert = old_cert_buf; - } - - res = generate_csr(ctx, "Cert/privkey-plain.pem", "Cert/est-req.pem", - "Cert/est-req.b64", old_cert, csrattrs); - if (csrattrs) - CsrAttrs_free(csrattrs); - - return res; -} - - -int est_simple_enroll(struct hs20_osu_client *ctx, const char *url, - const char *user, const char *pw) -{ - char *buf, *resp, *req, *req2; - size_t buflen, resp_len, len, pkcs7_len; - unsigned char *pkcs7; - char client_cert_buf[200]; - char client_key_buf[200]; - const char *client_cert = NULL, *client_key = NULL; - int res; - - req = os_readfile("Cert/est-req.b64", &len); - if (req == NULL) { - wpa_printf(MSG_INFO, "Could not read Cert/req.b64"); - return -1; - } - req2 = os_realloc(req, len + 1); - if (req2 == NULL) { - os_free(req); - return -1; - } - req2[len] = '\0'; - req = req2; - wpa_printf(MSG_DEBUG, "EST simpleenroll request: %s", req); - - buflen = os_strlen(url) + 100; - buf = os_malloc(buflen); - if (buf == NULL) { - os_free(req); - return -1; - } - - if (ctx->client_cert_present) { - os_snprintf(buf, buflen, "%s/simplereenroll", url); - os_snprintf(client_cert_buf, sizeof(client_cert_buf), - "SP/%s/client-cert.pem", ctx->fqdn); - client_cert = client_cert_buf; - os_snprintf(client_key_buf, sizeof(client_key_buf), - "SP/%s/client-key.pem", ctx->fqdn); - client_key = client_key_buf; - } else - os_snprintf(buf, buflen, "%s/simpleenroll", url); - wpa_printf(MSG_INFO, "EST simpleenroll URL: %s", buf); - write_summary(ctx, "EST simpleenroll URL: %s", buf); - ctx->no_osu_cert_validation = 1; - http_ocsp_set(ctx->http, 1); - resp = http_post(ctx->http, buf, req, "application/pkcs10", - "Content-Transfer-Encoding: base64", - ctx->ca_fname, user, pw, client_cert, client_key, - &resp_len); - http_ocsp_set(ctx->http, - (ctx->workarounds & WORKAROUND_OCSP_OPTIONAL) ? 1 : 2); - ctx->no_osu_cert_validation = 0; - os_free(buf); - if (resp == NULL) { - wpa_printf(MSG_INFO, "EST certificate enrollment failed"); - write_result(ctx, "EST certificate enrollment failed"); - return -1; - } - wpa_printf(MSG_DEBUG, "EST simpleenroll response: %s", resp); - - pkcs7 = base64_decode(resp, resp_len, &pkcs7_len); - if (pkcs7 == NULL) { - wpa_printf(MSG_INFO, "EST workaround - Could not decode base64, assume this is DER encoded PKCS7"); - pkcs7 = os_malloc(resp_len); - if (pkcs7) { - os_memcpy(pkcs7, resp, resp_len); - pkcs7_len = resp_len; - } - } - os_free(resp); - - if (pkcs7 == NULL) { - wpa_printf(MSG_INFO, "Failed to parse simpleenroll base64 response"); - write_result(ctx, "Failed to parse EST simpleenroll base64 response"); - return -1; - } - - res = pkcs7_to_cert(ctx, pkcs7, pkcs7_len, "Cert/est_cert.pem", - "Cert/est_cert.der"); - os_free(pkcs7); - - if (res < 0) { - wpa_printf(MSG_INFO, "EST: Failed to extract certificate from PKCS7 file"); - write_result(ctx, "EST: Failed to extract certificate from EST PKCS7 file"); - return -1; - } - - wpa_printf(MSG_INFO, "EST simple%senroll completed successfully", - ctx->client_cert_present ? "re" : ""); - write_summary(ctx, "EST simple%senroll completed successfully", - ctx->client_cert_present ? "re" : ""); - - return 0; -} diff --git a/hs20/client/oma_dm_client.c b/hs20/client/oma_dm_client.c deleted file mode 100644 index bcd68b8775d5..000000000000 --- a/hs20/client/oma_dm_client.c +++ /dev/null @@ -1,1398 +0,0 @@ -/* - * Hotspot 2.0 - OMA DM client - * Copyright (c) 2013-2014, Qualcomm Atheros, Inc. - * - * This software may be distributed under the terms of the BSD license. - * See README for more details. - */ - -#include "includes.h" - -#include "common.h" -#include "wpa_helpers.h" -#include "xml-utils.h" -#include "http-utils.h" -#include "utils/browser.h" -#include "osu_client.h" - - -#define DM_SERVER_INITIATED_MGMT 1200 -#define DM_CLIENT_INITIATED_MGMT 1201 -#define DM_GENERIC_ALERT 1226 - -/* OMA-TS-SyncML-RepPro-V1_2_2 - 10. Response Status Codes */ -#define DM_RESP_OK 200 -#define DM_RESP_AUTH_ACCEPTED 212 -#define DM_RESP_CHUNKED_ITEM_ACCEPTED 213 -#define DM_RESP_NOT_EXECUTED 215 -#define DM_RESP_ATOMIC_ROLL_BACK_OK 216 -#define DM_RESP_NOT_MODIFIED 304 -#define DM_RESP_BAD_REQUEST 400 -#define DM_RESP_UNAUTHORIZED 401 -#define DM_RESP_FORBIDDEN 403 -#define DM_RESP_NOT_FOUND 404 -#define DM_RESP_COMMAND_NOT_ALLOWED 405 -#define DM_RESP_OPTIONAL_FEATURE_NOT_SUPPORTED 406 -#define DM_RESP_MISSING_CREDENTIALS 407 -#define DM_RESP_CONFLICT 409 -#define DM_RESP_GONE 410 -#define DM_RESP_INCOMPLETE_COMMAND 412 -#define DM_RESP_REQ_ENTITY_TOO_LARGE 413 -#define DM_RESP_URI_TOO_LONG 414 -#define DM_RESP_UNSUPPORTED_MEDIA_TYPE_OR_FORMAT 415 -#define DM_RESP_REQ_TOO_BIG 416 -#define DM_RESP_ALREADY_EXISTS 418 -#define DM_RESP_DEVICE_FULL 420 -#define DM_RESP_SIZE_MISMATCH 424 -#define DM_RESP_PERMISSION_DENIED 425 -#define DM_RESP_COMMAND_FAILED 500 -#define DM_RESP_COMMAND_NOT_IMPLEMENTED 501 -#define DM_RESP_ATOMIC_ROLL_BACK_FAILED 516 - -#define DM_HS20_SUBSCRIPTION_CREATION \ - "org.wi-fi.hotspot2dot0.SubscriptionCreation" -#define DM_HS20_SUBSCRIPTION_PROVISIONING \ - "org.wi-fi.hotspot2dot0.SubscriptionProvisioning" -#define DM_HS20_SUBSCRIPTION_REMEDIATION \ - "org.wi-fi.hotspot2dot0.SubscriptionRemediation" -#define DM_HS20_POLICY_UPDATE \ - "org.wi-fi.hotspot2dot0.PolicyUpdate" - -#define DM_URI_PPS "./Wi-Fi/org.wi-fi/PerProviderSubscription" -#define DM_URI_LAUNCH_BROWSER \ - "./DevDetail/Ext/org.wi-fi/Wi-Fi/Ops/launchBrowserToURI" - - -static void add_item(struct hs20_osu_client *ctx, xml_node_t *parent, - const char *locuri, const char *data); - - -static const char * int2str(int val) -{ - static char buf[20]; - snprintf(buf, sizeof(buf), "%d", val); - return buf; -} - - -static char * oma_dm_get_target_locuri(struct hs20_osu_client *ctx, - xml_node_t *node) -{ - xml_node_t *locuri; - char *uri, *ret = NULL; - - locuri = get_node(ctx->xml, node, "Item/Target/LocURI"); - if (locuri == NULL) - return NULL; - - uri = xml_node_get_text(ctx->xml, locuri); - if (uri) - ret = os_strdup(uri); - xml_node_get_text_free(ctx->xml, uri); - return ret; -} - - -static void oma_dm_add_locuri(struct hs20_osu_client *ctx, xml_node_t *parent, - const char *element, const char *uri) -{ - xml_node_t *node; - - node = xml_node_create(ctx->xml, parent, NULL, element); - if (node == NULL) - return; - xml_node_create_text(ctx->xml, node, NULL, "LocURI", uri); -} - - -static xml_node_t * oma_dm_build_hdr(struct hs20_osu_client *ctx, - const char *url, int msgid) -{ - xml_node_t *syncml, *synchdr; - xml_namespace_t *ns; - - if (!ctx->devid) { - wpa_printf(MSG_ERROR, - "DevId from devinfo.xml is not available - cannot use OMA DM"); - return NULL; - } - - syncml = xml_node_create_root(ctx->xml, "SYNCML:SYNCML1.2", NULL, &ns, - "SyncML"); - - synchdr = xml_node_create(ctx->xml, syncml, NULL, "SyncHdr"); - xml_node_create_text(ctx->xml, synchdr, NULL, "VerDTD", "1.2"); - xml_node_create_text(ctx->xml, synchdr, NULL, "VerProto", "DM/1.2"); - xml_node_create_text(ctx->xml, synchdr, NULL, "SessionID", "1"); - xml_node_create_text(ctx->xml, synchdr, NULL, "MsgID", int2str(msgid)); - - oma_dm_add_locuri(ctx, synchdr, "Target", url); - oma_dm_add_locuri(ctx, synchdr, "Source", ctx->devid); - - return syncml; -} - - -static void oma_dm_add_cmdid(struct hs20_osu_client *ctx, xml_node_t *parent, - int cmdid) -{ - xml_node_create_text(ctx->xml, parent, NULL, "CmdID", int2str(cmdid)); -} - - -static xml_node_t * add_alert(struct hs20_osu_client *ctx, xml_node_t *parent, - int cmdid, int data) -{ - xml_node_t *node; - - node = xml_node_create(ctx->xml, parent, NULL, "Alert"); - if (node == NULL) - return NULL; - oma_dm_add_cmdid(ctx, node, cmdid); - xml_node_create_text(ctx->xml, node, NULL, "Data", int2str(data)); - - return node; -} - - -static xml_node_t * add_status(struct hs20_osu_client *ctx, xml_node_t *parent, - int msgref, int cmdref, int cmdid, - const char *cmd, int data, const char *targetref) -{ - xml_node_t *node; - - node = xml_node_create(ctx->xml, parent, NULL, "Status"); - if (node == NULL) - return NULL; - oma_dm_add_cmdid(ctx, node, cmdid); - xml_node_create_text(ctx->xml, node, NULL, "MsgRef", int2str(msgref)); - if (cmdref) - xml_node_create_text(ctx->xml, node, NULL, "CmdRef", - int2str(cmdref)); - xml_node_create_text(ctx->xml, node, NULL, "Cmd", cmd); - xml_node_create_text(ctx->xml, node, NULL, "Data", int2str(data)); - if (targetref) { - xml_node_create_text(ctx->xml, node, NULL, "TargetRef", - targetref); - } - - return node; -} - - -static xml_node_t * add_results(struct hs20_osu_client *ctx, xml_node_t *parent, - int msgref, int cmdref, int cmdid, - const char *locuri, const char *data) -{ - xml_node_t *node; - - node = xml_node_create(ctx->xml, parent, NULL, "Results"); - if (node == NULL) - return NULL; - - oma_dm_add_cmdid(ctx, node, cmdid); - xml_node_create_text(ctx->xml, node, NULL, "MsgRef", int2str(msgref)); - xml_node_create_text(ctx->xml, node, NULL, "CmdRef", int2str(cmdref)); - add_item(ctx, node, locuri, data); - - return node; -} - - -static char * mo_str(struct hs20_osu_client *ctx, const char *urn, - const char *fname) -{ - xml_node_t *fnode, *tnds; - char *str; - - fnode = node_from_file(ctx->xml, fname); - if (!fnode) - return NULL; - tnds = mo_to_tnds(ctx->xml, fnode, 0, urn, "syncml:dmddf1.2"); - xml_node_free(ctx->xml, fnode); - if (!tnds) - return NULL; - - str = xml_node_to_str(ctx->xml, tnds); - xml_node_free(ctx->xml, tnds); - if (str == NULL) - return NULL; - wpa_printf(MSG_INFO, "MgmtTree: %s", str); - - return str; -} - - -static void add_item(struct hs20_osu_client *ctx, xml_node_t *parent, - const char *locuri, const char *data) -{ - xml_node_t *item, *node; - - item = xml_node_create(ctx->xml, parent, NULL, "Item"); - oma_dm_add_locuri(ctx, item, "Source", locuri); - node = xml_node_create(ctx->xml, item, NULL, "Meta"); - xml_node_create_text_ns(ctx->xml, node, "syncml:metinf", "Format", - "Chr"); - xml_node_create_text_ns(ctx->xml, node, "syncml:metinf", "Type", - "text/plain"); - xml_node_create_text(ctx->xml, item, NULL, "Data", data); -} - - -static void add_replace_devinfo(struct hs20_osu_client *ctx, xml_node_t *parent, - int cmdid) -{ - xml_node_t *info, *child, *replace; - const char *name; - char locuri[200], *txt; - - info = node_from_file(ctx->xml, "devinfo.xml"); - if (info == NULL) { - wpa_printf(MSG_INFO, "Could not read devinfo.xml"); - return; - } - - replace = xml_node_create(ctx->xml, parent, NULL, "Replace"); - if (replace == NULL) { - xml_node_free(ctx->xml, info); - return; - } - oma_dm_add_cmdid(ctx, replace, cmdid); - - xml_node_for_each_child(ctx->xml, child, info) { - xml_node_for_each_check(ctx->xml, child); - name = xml_node_get_localname(ctx->xml, child); - os_snprintf(locuri, sizeof(locuri), "./DevInfo/%s", name); - txt = xml_node_get_text(ctx->xml, child); - if (txt) { - add_item(ctx, replace, locuri, txt); - xml_node_get_text_free(ctx->xml, txt); - } - } - - xml_node_free(ctx->xml, info); -} - - -static void oma_dm_add_hs20_generic_alert(struct hs20_osu_client *ctx, - xml_node_t *syncbody, - int cmdid, const char *oper, - const char *data) -{ - xml_node_t *node, *item; - char buf[200]; - - node = add_alert(ctx, syncbody, cmdid, DM_GENERIC_ALERT); - - item = xml_node_create(ctx->xml, node, NULL, "Item"); - oma_dm_add_locuri(ctx, item, "Source", DM_URI_PPS); - node = xml_node_create(ctx->xml, item, NULL, "Meta"); - snprintf(buf, sizeof(buf), "Reversed-Domain-Name: %s", oper); - xml_node_create_text_ns(ctx->xml, node, "syncml:metinf", "Type", buf); - xml_node_create_text_ns(ctx->xml, node, "syncml:metinf", "Format", - "xml"); - xml_node_create_text(ctx->xml, item, NULL, "Data", data); -} - - -static xml_node_t * build_oma_dm_1(struct hs20_osu_client *ctx, - const char *url, int msgid, const char *oper) -{ - xml_node_t *syncml, *syncbody; - char *str; - int cmdid = 0; - - syncml = oma_dm_build_hdr(ctx, url, msgid); - if (syncml == NULL) - return NULL; - - syncbody = xml_node_create(ctx->xml, syncml, NULL, "SyncBody"); - if (syncbody == NULL) { - xml_node_free(ctx->xml, syncml); - return NULL; - } - - cmdid++; - add_alert(ctx, syncbody, cmdid, DM_CLIENT_INITIATED_MGMT); - - str = mo_str(ctx, NULL, "devdetail.xml"); - if (str == NULL) { - xml_node_free(ctx->xml, syncml); - return NULL; - } - cmdid++; - oma_dm_add_hs20_generic_alert(ctx, syncbody, cmdid, oper, str); - os_free(str); - - cmdid++; - add_replace_devinfo(ctx, syncbody, cmdid); - - xml_node_create(ctx->xml, syncbody, NULL, "Final"); - - return syncml; -} - - -static xml_node_t * build_oma_dm_1_sub_reg(struct hs20_osu_client *ctx, - const char *url, int msgid) -{ - xml_node_t *syncml; - - syncml = build_oma_dm_1(ctx, url, msgid, DM_HS20_SUBSCRIPTION_CREATION); - if (syncml) - debug_dump_node(ctx, "OMA-DM Package 1 (sub reg)", syncml); - - return syncml; -} - - -static xml_node_t * build_oma_dm_1_sub_prov(struct hs20_osu_client *ctx, - const char *url, int msgid) -{ - xml_node_t *syncml; - - syncml = build_oma_dm_1(ctx, url, msgid, - DM_HS20_SUBSCRIPTION_PROVISIONING); - if (syncml) - debug_dump_node(ctx, "OMA-DM Package 1 (sub prov)", syncml); - - return syncml; -} - - -static xml_node_t * build_oma_dm_1_pol_upd(struct hs20_osu_client *ctx, - const char *url, int msgid) -{ - xml_node_t *syncml; - - syncml = build_oma_dm_1(ctx, url, msgid, DM_HS20_POLICY_UPDATE); - if (syncml) - debug_dump_node(ctx, "OMA-DM Package 1 (pol upd)", syncml); - - return syncml; -} - - -static xml_node_t * build_oma_dm_1_sub_rem(struct hs20_osu_client *ctx, - const char *url, int msgid) -{ - xml_node_t *syncml; - - syncml = build_oma_dm_1(ctx, url, msgid, - DM_HS20_SUBSCRIPTION_REMEDIATION); - if (syncml) - debug_dump_node(ctx, "OMA-DM Package 1 (sub rem)", syncml); - - return syncml; -} - - -static int oma_dm_exec_browser(struct hs20_osu_client *ctx, xml_node_t *exec) -{ - xml_node_t *node; - char *data; - int res; - - node = get_node(ctx->xml, exec, "Item/Data"); - if (node == NULL) { - wpa_printf(MSG_INFO, "No Data node found"); - return DM_RESP_BAD_REQUEST; - } - - data = xml_node_get_text(ctx->xml, node); - if (data == NULL) { - wpa_printf(MSG_INFO, "Invalid data"); - return DM_RESP_BAD_REQUEST; - } - wpa_printf(MSG_INFO, "Data: %s", data); - wpa_printf(MSG_INFO, "Launch browser to URI '%s'", data); - write_summary(ctx, "Launch browser to URI '%s'", data); - res = hs20_web_browser(data, 1); - xml_node_get_text_free(ctx->xml, data); - if (res > 0) { - wpa_printf(MSG_INFO, "User response in browser completed successfully"); - write_summary(ctx, "User response in browser completed successfully"); - return DM_RESP_OK; - } else { - wpa_printf(MSG_INFO, "Failed to receive user response"); - write_summary(ctx, "Failed to receive user response"); - return DM_RESP_COMMAND_FAILED; - } -} - - -static int oma_dm_exec_get_cert(struct hs20_osu_client *ctx, xml_node_t *exec) -{ - xml_node_t *node, *getcert; - char *data; - const char *name; - int res; - - wpa_printf(MSG_INFO, "Client certificate enrollment"); - write_summary(ctx, "Client certificate enrollment"); - - node = get_node(ctx->xml, exec, "Item/Data"); - if (node == NULL) { - wpa_printf(MSG_INFO, "No Data node found"); - return DM_RESP_BAD_REQUEST; - } - - data = xml_node_get_text(ctx->xml, node); - if (data == NULL) { - wpa_printf(MSG_INFO, "Invalid data"); - return DM_RESP_BAD_REQUEST; - } - wpa_printf(MSG_INFO, "Data: %s", data); - getcert = xml_node_from_buf(ctx->xml, data); - xml_node_get_text_free(ctx->xml, data); - - if (getcert == NULL) { - wpa_printf(MSG_INFO, "Could not parse Item/Data node contents"); - return DM_RESP_BAD_REQUEST; - } - - debug_dump_node(ctx, "OMA-DM getCertificate", getcert); - - name = xml_node_get_localname(ctx->xml, getcert); - if (name == NULL || os_strcasecmp(name, "getCertificate") != 0) { - wpa_printf(MSG_INFO, "Unexpected getCertificate node name '%s'", - name); - return DM_RESP_BAD_REQUEST; - } - - res = osu_get_certificate(ctx, getcert); - - xml_node_free(ctx->xml, getcert); - - return res == 0 ? DM_RESP_OK : DM_RESP_COMMAND_FAILED; -} - - -static int oma_dm_exec(struct hs20_osu_client *ctx, xml_node_t *exec) -{ - char *locuri; - int ret; - - locuri = oma_dm_get_target_locuri(ctx, exec); - if (locuri == NULL) { - wpa_printf(MSG_INFO, "No Target LocURI node found"); - return DM_RESP_BAD_REQUEST; - } - - wpa_printf(MSG_INFO, "Target LocURI: %s", locuri); - - if (os_strcasecmp(locuri, "./DevDetail/Ext/org.wi-fi/Wi-Fi/Ops/" - "launchBrowserToURI") == 0) { - ret = oma_dm_exec_browser(ctx, exec); - } else if (os_strcasecmp(locuri, "./DevDetail/Ext/org.wi-fi/Wi-Fi/Ops/" - "getCertificate") == 0) { - ret = oma_dm_exec_get_cert(ctx, exec); - } else { - wpa_printf(MSG_INFO, "Unsupported exec Target LocURI"); - ret = DM_RESP_NOT_FOUND; - } - os_free(locuri); - - return ret; -} - - -static int oma_dm_run_add(struct hs20_osu_client *ctx, const char *locuri, - xml_node_t *add, xml_node_t *pps, - const char *pps_fname) -{ - const char *pos; - size_t fqdn_len; - xml_node_t *node, *tnds, *unode, *pps_node; - char *data, *uri, *upos, *end; - int use_tnds = 0; - size_t uri_len; - - wpa_printf(MSG_INFO, "Add command target LocURI: %s", locuri); - - if (os_strncasecmp(locuri, "./Wi-Fi/", 8) != 0) { - wpa_printf(MSG_INFO, "Do not allow Add outside ./Wi-Fi"); - return DM_RESP_PERMISSION_DENIED; - } - pos = locuri + 8; - - if (ctx->fqdn == NULL) - return DM_RESP_COMMAND_FAILED; - fqdn_len = os_strlen(ctx->fqdn); - if (os_strncasecmp(pos, ctx->fqdn, fqdn_len) != 0 || - pos[fqdn_len] != '/') { - wpa_printf(MSG_INFO, "Do not allow Add outside ./Wi-Fi/%s", - ctx->fqdn); - return DM_RESP_PERMISSION_DENIED; - } - pos += fqdn_len + 1; - - if (os_strncasecmp(pos, "PerProviderSubscription/", 24) != 0) { - wpa_printf(MSG_INFO, - "Do not allow Add outside ./Wi-Fi/%s/PerProviderSubscription", - ctx->fqdn); - return DM_RESP_PERMISSION_DENIED; - } - pos += 24; - - wpa_printf(MSG_INFO, "Add command for PPS node %s", pos); - - pps_node = get_node(ctx->xml, pps, pos); - if (pps_node) { - wpa_printf(MSG_INFO, "Specified PPS node exists already"); - return DM_RESP_ALREADY_EXISTS; - } - - uri = os_strdup(pos); - if (uri == NULL) - return DM_RESP_COMMAND_FAILED; - while (!pps_node) { - upos = os_strrchr(uri, '/'); - if (!upos) - break; - upos[0] = '\0'; - pps_node = get_node(ctx->xml, pps, uri); - wpa_printf(MSG_INFO, "Node %s %s", uri, - pps_node ? "exists" : "does not exist"); - } - - wpa_printf(MSG_INFO, "Parent URI: %s", uri); - - if (!pps_node) { - /* Add at root of PPS MO */ - pps_node = pps; - } - - uri_len = os_strlen(uri); - os_strlcpy(uri, pos + uri_len, os_strlen(pos)); - upos = uri; - while (*upos == '/') - upos++; - wpa_printf(MSG_INFO, "Nodes to add: %s", upos); - - for (;;) { - end = os_strchr(upos, '/'); - if (!end) - break; - *end = '\0'; - wpa_printf(MSG_INFO, "Adding interim node %s", upos); - pps_node = xml_node_create(ctx->xml, pps_node, NULL, upos); - if (pps_node == NULL) { - os_free(uri); - return DM_RESP_COMMAND_FAILED; - } - upos = end + 1; - } - - wpa_printf(MSG_INFO, "Adding node %s", upos); - - node = get_node(ctx->xml, add, "Item/Meta/Type"); - if (node) { - char *type; - type = xml_node_get_text(ctx->xml, node); - if (type == NULL) { - wpa_printf(MSG_ERROR, "Could not find type text"); - os_free(uri); - return DM_RESP_BAD_REQUEST; - } - use_tnds = node && - os_strstr(type, "application/vnd.syncml.dmtnds+xml"); - } - - node = get_node(ctx->xml, add, "Item/Data"); - if (node == NULL) { - wpa_printf(MSG_INFO, "No Add/Item/Data found"); - os_free(uri); - return DM_RESP_BAD_REQUEST; - } - - data = xml_node_get_text(ctx->xml, node); - if (data == NULL) { - wpa_printf(MSG_INFO, "Could not get Add/Item/Data text"); - os_free(uri); - return DM_RESP_BAD_REQUEST; - } - - wpa_printf(MSG_DEBUG, "Add/Item/Data: %s", data); - - if (use_tnds) { - tnds = xml_node_from_buf(ctx->xml, data); - xml_node_get_text_free(ctx->xml, data); - if (tnds == NULL) { - wpa_printf(MSG_INFO, - "Could not parse Add/Item/Data text"); - os_free(uri); - return DM_RESP_BAD_REQUEST; - } - - unode = tnds_to_mo(ctx->xml, tnds); - xml_node_free(ctx->xml, tnds); - if (unode == NULL) { - wpa_printf(MSG_INFO, "Could not parse TNDS text"); - os_free(uri); - return DM_RESP_BAD_REQUEST; - } - - debug_dump_node(ctx, "Parsed TNDS", unode); - - xml_node_add_child(ctx->xml, pps_node, unode); - } else { - /* TODO: What to do here? */ - os_free(uri); - return DM_RESP_BAD_REQUEST; - } - - os_free(uri); - - if (update_pps_file(ctx, pps_fname, pps) < 0) - return DM_RESP_COMMAND_FAILED; - - ctx->pps_updated = 1; - - return DM_RESP_OK; -} - - -static int oma_dm_add(struct hs20_osu_client *ctx, xml_node_t *add, - xml_node_t *pps, const char *pps_fname) -{ - xml_node_t *node; - char *locuri; - char fname[300]; - int ret; - - node = get_node(ctx->xml, add, "Item/Target/LocURI"); - if (node == NULL) { - wpa_printf(MSG_INFO, "No Target LocURI node found"); - return DM_RESP_BAD_REQUEST; - } - locuri = xml_node_get_text(ctx->xml, node); - if (locuri == NULL) { - wpa_printf(MSG_ERROR, "No LocURI node text found"); - return DM_RESP_BAD_REQUEST; - } - wpa_printf(MSG_INFO, "Target LocURI: %s", locuri); - if (os_strncasecmp(locuri, "./Wi-Fi/", 8) != 0) { - wpa_printf(MSG_INFO, "Unsupported Add Target LocURI"); - xml_node_get_text_free(ctx->xml, locuri); - return DM_RESP_PERMISSION_DENIED; - } - - node = get_node(ctx->xml, add, "Item/Data"); - if (node == NULL) { - wpa_printf(MSG_INFO, "No Data node found"); - xml_node_get_text_free(ctx->xml, locuri); - return DM_RESP_BAD_REQUEST; - } - - if (pps_fname && os_file_exists(pps_fname)) { - ret = oma_dm_run_add(ctx, locuri, add, pps, pps_fname); - if (ret != DM_RESP_OK) { - xml_node_get_text_free(ctx->xml, locuri); - return ret; - } - ret = 0; - os_strlcpy(fname, pps_fname, sizeof(fname)); - } else - ret = hs20_add_pps_mo(ctx, locuri, node, fname, sizeof(fname)); - xml_node_get_text_free(ctx->xml, locuri); - if (ret < 0) - return ret == -2 ? DM_RESP_ALREADY_EXISTS : - DM_RESP_COMMAND_FAILED; - - if (ctx->no_reconnect == 2) { - os_snprintf(ctx->pps_fname, sizeof(ctx->pps_fname), "%s", - fname); - ctx->pps_cred_set = 1; - return DM_RESP_OK; - } - - wpa_printf(MSG_INFO, "Updating wpa_supplicant credentials"); - cmd_set_pps(ctx, fname); - - if (ctx->no_reconnect) - return DM_RESP_OK; - - wpa_printf(MSG_INFO, "Requesting reconnection with updated configuration"); - if (wpa_command(ctx->ifname, "INTERWORKING_SELECT auto") < 0) - wpa_printf(MSG_INFO, "Failed to request wpa_supplicant to reconnect"); - - return DM_RESP_OK; -} - - -static int oma_dm_replace(struct hs20_osu_client *ctx, xml_node_t *replace, - xml_node_t *pps, const char *pps_fname) -{ - char *locuri, *pos; - size_t fqdn_len; - xml_node_t *node, *tnds, *unode, *pps_node, *parent; - char *data; - int use_tnds = 0; - - locuri = oma_dm_get_target_locuri(ctx, replace); - if (locuri == NULL) - return DM_RESP_BAD_REQUEST; - - wpa_printf(MSG_INFO, "Replace command target LocURI: %s", locuri); - if (os_strncasecmp(locuri, "./Wi-Fi/", 8) != 0) { - wpa_printf(MSG_INFO, "Do not allow Replace outside ./Wi-Fi"); - os_free(locuri); - return DM_RESP_PERMISSION_DENIED; - } - pos = locuri + 8; - - if (ctx->fqdn == NULL) { - os_free(locuri); - return DM_RESP_COMMAND_FAILED; - } - fqdn_len = os_strlen(ctx->fqdn); - if (os_strncasecmp(pos, ctx->fqdn, fqdn_len) != 0 || - pos[fqdn_len] != '/') { - wpa_printf(MSG_INFO, "Do not allow Replace outside ./Wi-Fi/%s", - ctx->fqdn); - os_free(locuri); - return DM_RESP_PERMISSION_DENIED; - } - pos += fqdn_len + 1; - - if (os_strncasecmp(pos, "PerProviderSubscription/", 24) != 0) { - wpa_printf(MSG_INFO, - "Do not allow Replace outside ./Wi-Fi/%s/PerProviderSubscription", - ctx->fqdn); - os_free(locuri); - return DM_RESP_PERMISSION_DENIED; - } - pos += 24; - - wpa_printf(MSG_INFO, "Replace command for PPS node %s", pos); - - pps_node = get_node(ctx->xml, pps, pos); - if (pps_node == NULL) { - wpa_printf(MSG_INFO, "Specified PPS node not found"); - os_free(locuri); - return DM_RESP_NOT_FOUND; - } - - node = get_node(ctx->xml, replace, "Item/Meta/Type"); - if (node) { - char *type; - type = xml_node_get_text(ctx->xml, node); - if (type == NULL) { - wpa_printf(MSG_INFO, "Could not find type text"); - os_free(locuri); - return DM_RESP_BAD_REQUEST; - } - use_tnds = node && - os_strstr(type, "application/vnd.syncml.dmtnds+xml"); - } - - node = get_node(ctx->xml, replace, "Item/Data"); - if (node == NULL) { - wpa_printf(MSG_INFO, "No Replace/Item/Data found"); - os_free(locuri); - return DM_RESP_BAD_REQUEST; - } - - data = xml_node_get_text(ctx->xml, node); - if (data == NULL) { - wpa_printf(MSG_INFO, "Could not get Replace/Item/Data text"); - os_free(locuri); - return DM_RESP_BAD_REQUEST; - } - - wpa_printf(MSG_DEBUG, "Replace/Item/Data: %s", data); - - if (use_tnds) { - tnds = xml_node_from_buf(ctx->xml, data); - xml_node_get_text_free(ctx->xml, data); - if (tnds == NULL) { - wpa_printf(MSG_INFO, - "Could not parse Replace/Item/Data text"); - os_free(locuri); - return DM_RESP_BAD_REQUEST; - } - - unode = tnds_to_mo(ctx->xml, tnds); - xml_node_free(ctx->xml, tnds); - if (unode == NULL) { - wpa_printf(MSG_INFO, "Could not parse TNDS text"); - os_free(locuri); - return DM_RESP_BAD_REQUEST; - } - - debug_dump_node(ctx, "Parsed TNDS", unode); - - parent = xml_node_get_parent(ctx->xml, pps_node); - xml_node_detach(ctx->xml, pps_node); - xml_node_add_child(ctx->xml, parent, unode); - } else { - xml_node_set_text(ctx->xml, pps_node, data); - xml_node_get_text_free(ctx->xml, data); - } - - os_free(locuri); - - if (update_pps_file(ctx, pps_fname, pps) < 0) - return DM_RESP_COMMAND_FAILED; - - ctx->pps_updated = 1; - - return DM_RESP_OK; -} - - -static int oma_dm_get(struct hs20_osu_client *ctx, xml_node_t *get, - xml_node_t *pps, const char *pps_fname, char **value) -{ - char *locuri, *pos; - size_t fqdn_len; - xml_node_t *pps_node; - const char *name; - - *value = NULL; - - locuri = oma_dm_get_target_locuri(ctx, get); - if (locuri == NULL) - return DM_RESP_BAD_REQUEST; - - wpa_printf(MSG_INFO, "Get command target LocURI: %s", locuri); - if (os_strncasecmp(locuri, "./Wi-Fi/", 8) != 0) { - wpa_printf(MSG_INFO, "Do not allow Get outside ./Wi-Fi"); - os_free(locuri); - return DM_RESP_PERMISSION_DENIED; - } - pos = locuri + 8; - - if (ctx->fqdn == NULL) - return DM_RESP_COMMAND_FAILED; - fqdn_len = os_strlen(ctx->fqdn); - if (os_strncasecmp(pos, ctx->fqdn, fqdn_len) != 0 || - pos[fqdn_len] != '/') { - wpa_printf(MSG_INFO, "Do not allow Get outside ./Wi-Fi/%s", - ctx->fqdn); - os_free(locuri); - return DM_RESP_PERMISSION_DENIED; - } - pos += fqdn_len + 1; - - if (os_strncasecmp(pos, "PerProviderSubscription/", 24) != 0) { - wpa_printf(MSG_INFO, - "Do not allow Get outside ./Wi-Fi/%s/PerProviderSubscription", - ctx->fqdn); - os_free(locuri); - return DM_RESP_PERMISSION_DENIED; - } - pos += 24; - - wpa_printf(MSG_INFO, "Get command for PPS node %s", pos); - - pps_node = get_node(ctx->xml, pps, pos); - if (pps_node == NULL) { - wpa_printf(MSG_INFO, "Specified PPS node not found"); - os_free(locuri); - return DM_RESP_NOT_FOUND; - } - - name = xml_node_get_localname(ctx->xml, pps_node); - wpa_printf(MSG_INFO, "Get command returned node with name '%s'", name); - if (os_strcasecmp(name, "Password") == 0) { - wpa_printf(MSG_INFO, "Do not allow Get for Password node"); - os_free(locuri); - return DM_RESP_PERMISSION_DENIED; - } - - /* - * TODO: No support for DMTNDS, so if interior node, reply with a - * list of children node names in Results element. The child list type is - * defined in [DMTND]. - */ - - *value = xml_node_get_text(ctx->xml, pps_node); - if (*value == NULL) - return DM_RESP_COMMAND_FAILED; - - return DM_RESP_OK; -} - - -static int oma_dm_get_cmdid(struct hs20_osu_client *ctx, xml_node_t *node) -{ - xml_node_t *cnode; - char *str; - int ret; - - cnode = get_node(ctx->xml, node, "CmdID"); - if (cnode == NULL) - return 0; - - str = xml_node_get_text(ctx->xml, cnode); - if (str == NULL) - return 0; - ret = atoi(str); - xml_node_get_text_free(ctx->xml, str); - return ret; -} - - -static xml_node_t * oma_dm_send_recv(struct hs20_osu_client *ctx, - const char *url, xml_node_t *syncml, - const char *ext_hdr, - const char *username, const char *password, - const char *client_cert, - const char *client_key) -{ - xml_node_t *resp; - char *str, *res; - char *resp_uri = NULL; - - str = xml_node_to_str(ctx->xml, syncml); - xml_node_free(ctx->xml, syncml); - if (str == NULL) - return NULL; - - wpa_printf(MSG_INFO, "Send OMA DM Package"); - write_summary(ctx, "Send OMA DM Package"); - os_free(ctx->server_url); - ctx->server_url = os_strdup(url); - res = http_post(ctx->http, url, str, "application/vnd.syncml.dm+xml", - ext_hdr, ctx->ca_fname, username, password, - client_cert, client_key, NULL); - os_free(str); - os_free(resp_uri); - resp_uri = NULL; - - if (res == NULL) { - const char *err = http_get_err(ctx->http); - if (err) { - wpa_printf(MSG_INFO, "HTTP error: %s", err); - write_result(ctx, "HTTP error: %s", err); - } else { - write_summary(ctx, "Failed to send OMA DM Package"); - } - return NULL; - } - wpa_printf(MSG_DEBUG, "Server response: %s", res); - - wpa_printf(MSG_INFO, "Process OMA DM Package"); - write_summary(ctx, "Process received OMA DM Package"); - resp = xml_node_from_buf(ctx->xml, res); - os_free(res); - if (resp == NULL) { - wpa_printf(MSG_INFO, "Failed to parse OMA DM response"); - return NULL; - } - - debug_dump_node(ctx, "OMA DM Package", resp); - - return resp; -} - - -static xml_node_t * oma_dm_process(struct hs20_osu_client *ctx, const char *url, - xml_node_t *resp, int msgid, - char **ret_resp_uri, - xml_node_t *pps, const char *pps_fname) -{ - xml_node_t *syncml, *syncbody, *hdr, *body, *child; - const char *name; - char *resp_uri = NULL; - int server_msgid = 0; - int cmdid = 0; - int server_cmdid; - int resp_needed = 0; - char *tmp; - int final = 0; - char *locuri; - - *ret_resp_uri = NULL; - - name = xml_node_get_localname(ctx->xml, resp); - if (name == NULL || os_strcasecmp(name, "SyncML") != 0) { - wpa_printf(MSG_INFO, "SyncML node not found"); - return NULL; - } - - hdr = get_node(ctx->xml, resp, "SyncHdr"); - body = get_node(ctx->xml, resp, "SyncBody"); - if (hdr == NULL || body == NULL) { - wpa_printf(MSG_INFO, "Could not find SyncHdr or SyncBody"); - return NULL; - } - - xml_node_for_each_child(ctx->xml, child, hdr) { - xml_node_for_each_check(ctx->xml, child); - name = xml_node_get_localname(ctx->xml, child); - wpa_printf(MSG_INFO, "SyncHdr %s", name); - if (os_strcasecmp(name, "RespURI") == 0) { - tmp = xml_node_get_text(ctx->xml, child); - if (tmp) - resp_uri = os_strdup(tmp); - xml_node_get_text_free(ctx->xml, tmp); - } else if (os_strcasecmp(name, "MsgID") == 0) { - tmp = xml_node_get_text(ctx->xml, child); - if (tmp) - server_msgid = atoi(tmp); - xml_node_get_text_free(ctx->xml, tmp); - } - } - - wpa_printf(MSG_INFO, "Server MsgID: %d", server_msgid); - if (resp_uri) - wpa_printf(MSG_INFO, "RespURI: %s", resp_uri); - - syncml = oma_dm_build_hdr(ctx, resp_uri ? resp_uri : url, msgid); - if (syncml == NULL) { - os_free(resp_uri); - return NULL; - } - - syncbody = xml_node_create(ctx->xml, syncml, NULL, "SyncBody"); - cmdid++; - add_status(ctx, syncbody, server_msgid, 0, cmdid, "SyncHdr", - DM_RESP_AUTH_ACCEPTED, NULL); - - xml_node_for_each_child(ctx->xml, child, body) { - xml_node_for_each_check(ctx->xml, child); - server_cmdid = oma_dm_get_cmdid(ctx, child); - name = xml_node_get_localname(ctx->xml, child); - wpa_printf(MSG_INFO, "SyncBody CmdID=%d - %s", - server_cmdid, name); - if (os_strcasecmp(name, "Exec") == 0) { - int res = oma_dm_exec(ctx, child); - cmdid++; - locuri = oma_dm_get_target_locuri(ctx, child); - if (locuri == NULL) - res = DM_RESP_BAD_REQUEST; - add_status(ctx, syncbody, server_msgid, server_cmdid, - cmdid, name, res, locuri); - os_free(locuri); - resp_needed = 1; - } else if (os_strcasecmp(name, "Add") == 0) { - int res = oma_dm_add(ctx, child, pps, pps_fname); - cmdid++; - locuri = oma_dm_get_target_locuri(ctx, child); - if (locuri == NULL) - res = DM_RESP_BAD_REQUEST; - add_status(ctx, syncbody, server_msgid, server_cmdid, - cmdid, name, res, locuri); - os_free(locuri); - resp_needed = 1; - } else if (os_strcasecmp(name, "Replace") == 0) { - int res; - res = oma_dm_replace(ctx, child, pps, pps_fname); - cmdid++; - locuri = oma_dm_get_target_locuri(ctx, child); - if (locuri == NULL) - res = DM_RESP_BAD_REQUEST; - add_status(ctx, syncbody, server_msgid, server_cmdid, - cmdid, name, res, locuri); - os_free(locuri); - resp_needed = 1; - } else if (os_strcasecmp(name, "Status") == 0) { - /* TODO: Verify success */ - } else if (os_strcasecmp(name, "Get") == 0) { - int res; - char *value; - res = oma_dm_get(ctx, child, pps, pps_fname, &value); - cmdid++; - locuri = oma_dm_get_target_locuri(ctx, child); - if (locuri == NULL) - res = DM_RESP_BAD_REQUEST; - add_status(ctx, syncbody, server_msgid, server_cmdid, - cmdid, name, res, locuri); - if (res == DM_RESP_OK && value) { - cmdid++; - add_results(ctx, syncbody, server_msgid, - server_cmdid, cmdid, locuri, value); - } - os_free(locuri); - xml_node_get_text_free(ctx->xml, value); - resp_needed = 1; -#if 0 /* TODO: MUST support */ - } else if (os_strcasecmp(name, "Delete") == 0) { -#endif -#if 0 /* TODO: MUST support */ - } else if (os_strcasecmp(name, "Sequence") == 0) { -#endif - } else if (os_strcasecmp(name, "Final") == 0) { - final = 1; - break; - } else { - locuri = oma_dm_get_target_locuri(ctx, child); - add_status(ctx, syncbody, server_msgid, server_cmdid, - cmdid, name, DM_RESP_COMMAND_NOT_IMPLEMENTED, - locuri); - os_free(locuri); - resp_needed = 1; - } - } - - if (!final) { - wpa_printf(MSG_INFO, "Final node not found"); - xml_node_free(ctx->xml, syncml); - os_free(resp_uri); - return NULL; - } - - if (!resp_needed) { - wpa_printf(MSG_INFO, "Exchange completed - no response needed"); - xml_node_free(ctx->xml, syncml); - os_free(resp_uri); - return NULL; - } - - xml_node_create(ctx->xml, syncbody, NULL, "Final"); - - debug_dump_node(ctx, "OMA-DM Package 3", syncml); - - *ret_resp_uri = resp_uri; - return syncml; -} - - -int cmd_oma_dm_prov(struct hs20_osu_client *ctx, const char *url) -{ - xml_node_t *syncml, *resp; - char *resp_uri = NULL; - int msgid = 0; - - if (url == NULL) { - wpa_printf(MSG_INFO, "Invalid prov command (missing URL)"); - return -1; - } - - wpa_printf(MSG_INFO, "OMA-DM credential provisioning requested"); - write_summary(ctx, "OMA-DM credential provisioning"); - - msgid++; - syncml = build_oma_dm_1_sub_reg(ctx, url, msgid); - if (syncml == NULL) - return -1; - - while (syncml) { - resp = oma_dm_send_recv(ctx, resp_uri ? resp_uri : url, - syncml, NULL, NULL, NULL, NULL, NULL); - if (resp == NULL) - return -1; - - msgid++; - syncml = oma_dm_process(ctx, url, resp, msgid, &resp_uri, - NULL, NULL); - xml_node_free(ctx->xml, resp); - } - - os_free(resp_uri); - - return ctx->pps_cred_set ? 0 : -1; -} - - -int cmd_oma_dm_sim_prov(struct hs20_osu_client *ctx, const char *url) -{ - xml_node_t *syncml, *resp; - char *resp_uri = NULL; - int msgid = 0; - - if (url == NULL) { - wpa_printf(MSG_INFO, "Invalid prov command (missing URL)"); - return -1; - } - - wpa_printf(MSG_INFO, "OMA-DM SIM provisioning requested"); - ctx->no_reconnect = 2; - - wpa_printf(MSG_INFO, "Wait for IP address before starting SIM provisioning"); - write_summary(ctx, "Wait for IP address before starting SIM provisioning"); - - if (wait_ip_addr(ctx->ifname, 15) < 0) { - wpa_printf(MSG_INFO, "Could not get IP address for WLAN - try connection anyway"); - } - write_summary(ctx, "OMA-DM SIM provisioning"); - - msgid++; - syncml = build_oma_dm_1_sub_prov(ctx, url, msgid); - if (syncml == NULL) - return -1; - - while (syncml) { - resp = oma_dm_send_recv(ctx, resp_uri ? resp_uri : url, - syncml, NULL, NULL, NULL, NULL, NULL); - if (resp == NULL) - return -1; - - msgid++; - syncml = oma_dm_process(ctx, url, resp, msgid, &resp_uri, - NULL, NULL); - xml_node_free(ctx->xml, resp); - } - - os_free(resp_uri); - - if (ctx->pps_cred_set) { - wpa_printf(MSG_INFO, "Updating wpa_supplicant credentials"); - cmd_set_pps(ctx, ctx->pps_fname); - - wpa_printf(MSG_INFO, "Requesting reconnection with updated configuration"); - write_summary(ctx, "Requesting reconnection with updated configuration"); - if (wpa_command(ctx->ifname, "INTERWORKING_SELECT auto") < 0) { - wpa_printf(MSG_INFO, "Failed to request wpa_supplicant to reconnect"); - write_summary(ctx, "Failed to request wpa_supplicant to reconnect"); - return -1; - } - } - - return ctx->pps_cred_set ? 0 : -1; -} - - -void oma_dm_pol_upd(struct hs20_osu_client *ctx, const char *address, - const char *pps_fname, - const char *client_cert, const char *client_key, - const char *cred_username, const char *cred_password, - xml_node_t *pps) -{ - xml_node_t *syncml, *resp; - char *resp_uri = NULL; - int msgid = 0; - - wpa_printf(MSG_INFO, "OMA-DM policy update"); - write_summary(ctx, "OMA-DM policy update"); - - msgid++; - syncml = build_oma_dm_1_pol_upd(ctx, address, msgid); - if (syncml == NULL) - return; - - while (syncml) { - resp = oma_dm_send_recv(ctx, resp_uri ? resp_uri : address, - syncml, NULL, cred_username, - cred_password, client_cert, client_key); - if (resp == NULL) - return; - - msgid++; - syncml = oma_dm_process(ctx, address, resp, msgid, &resp_uri, - pps, pps_fname); - xml_node_free(ctx->xml, resp); - } - - os_free(resp_uri); - - if (ctx->pps_updated) { - wpa_printf(MSG_INFO, "Update wpa_supplicant credential based on updated PPS MO"); - write_summary(ctx, "Update wpa_supplicant credential based on updated PPS MO and request connection"); - cmd_set_pps(ctx, pps_fname); - if (wpa_command(ctx->ifname, "INTERWORKING_SELECT auto") < 0) { - wpa_printf(MSG_INFO, - "Failed to request wpa_supplicant to reconnect"); - write_summary(ctx, - "Failed to request wpa_supplicant to reconnect"); - } - } -} - - -void oma_dm_sub_rem(struct hs20_osu_client *ctx, const char *address, - const char *pps_fname, - const char *client_cert, const char *client_key, - const char *cred_username, const char *cred_password, - xml_node_t *pps) -{ - xml_node_t *syncml, *resp; - char *resp_uri = NULL; - int msgid = 0; - - wpa_printf(MSG_INFO, "OMA-DM subscription remediation"); - write_summary(ctx, "OMA-DM subscription remediation"); - - msgid++; - syncml = build_oma_dm_1_sub_rem(ctx, address, msgid); - if (syncml == NULL) - return; - - while (syncml) { - resp = oma_dm_send_recv(ctx, resp_uri ? resp_uri : address, - syncml, NULL, cred_username, - cred_password, client_cert, client_key); - if (resp == NULL) - return; - - msgid++; - syncml = oma_dm_process(ctx, address, resp, msgid, &resp_uri, - pps, pps_fname); - xml_node_free(ctx->xml, resp); - } - - os_free(resp_uri); - - wpa_printf(MSG_INFO, "Update wpa_supplicant credential based on updated PPS MO and request reconnection"); - write_summary(ctx, "Update wpa_supplicant credential based on updated PPS MO and request reconnection"); - cmd_set_pps(ctx, pps_fname); - if (wpa_command(ctx->ifname, "INTERWORKING_SELECT auto") < 0) { - wpa_printf(MSG_INFO, "Failed to request wpa_supplicant to reconnect"); - write_summary(ctx, "Failed to request wpa_supplicant to reconnect"); - } -} - - -void cmd_oma_dm_add(struct hs20_osu_client *ctx, const char *pps_fname, - const char *add_fname) -{ - xml_node_t *pps, *add; - int res; - - ctx->fqdn = os_strdup("wi-fi.org"); - - pps = node_from_file(ctx->xml, pps_fname); - if (pps == NULL) { - wpa_printf(MSG_INFO, "PPS file %s could not be parsed", - pps_fname); - return; - } - - add = node_from_file(ctx->xml, add_fname); - if (add == NULL) { - wpa_printf(MSG_INFO, "Add file %s could not be parsed", - add_fname); - xml_node_free(ctx->xml, pps); - return; - } - - res = oma_dm_add(ctx, add, pps, pps_fname); - wpa_printf(MSG_INFO, "oma_dm_add --> %d", res); - - xml_node_free(ctx->xml, pps); - xml_node_free(ctx->xml, add); -} - - -void cmd_oma_dm_replace(struct hs20_osu_client *ctx, const char *pps_fname, - const char *replace_fname) -{ - xml_node_t *pps, *replace; - int res; - - ctx->fqdn = os_strdup("wi-fi.org"); - - pps = node_from_file(ctx->xml, pps_fname); - if (pps == NULL) { - wpa_printf(MSG_INFO, "PPS file %s could not be parsed", - pps_fname); - return; - } - - replace = node_from_file(ctx->xml, replace_fname); - if (replace == NULL) { - wpa_printf(MSG_INFO, "Replace file %s could not be parsed", - replace_fname); - xml_node_free(ctx->xml, pps); - return; - } - - res = oma_dm_replace(ctx, replace, pps, pps_fname); - wpa_printf(MSG_INFO, "oma_dm_replace --> %d", res); - - xml_node_free(ctx->xml, pps); - xml_node_free(ctx->xml, replace); -} diff --git a/hs20/client/osu_client.c b/hs20/client/osu_client.c deleted file mode 100644 index 11bf0db35e93..000000000000 --- a/hs20/client/osu_client.c +++ /dev/null @@ -1,3431 +0,0 @@ -/* - * Hotspot 2.0 OSU client - * Copyright (c) 2012-2014, 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 <sys/stat.h> -#ifdef ANDROID -#include "private/android_filesystem_config.h" -#endif /* ANDROID */ - -#include "common.h" -#include "utils/browser.h" -#include "utils/base64.h" -#include "utils/xml-utils.h" -#include "utils/http-utils.h" -#include "common/wpa_ctrl.h" -#include "common/wpa_helpers.h" -#include "eap_common/eap_defs.h" -#include "crypto/crypto.h" -#include "crypto/sha256.h" -#include "osu_client.h" - -const char *spp_xsd_fname = "spp.xsd"; - - -void write_result(struct hs20_osu_client *ctx, const char *fmt, ...) -{ - va_list ap; - FILE *f; - char buf[500]; - - va_start(ap, fmt); - vsnprintf(buf, sizeof(buf), fmt, ap); - va_end(ap); - write_summary(ctx, "%s", buf); - - if (!ctx->result_file) - return; - - f = fopen(ctx->result_file, "w"); - if (f == NULL) - return; - - va_start(ap, fmt); - vfprintf(f, fmt, ap); - va_end(ap); - fprintf(f, "\n"); - fclose(f); -} - - -void write_summary(struct hs20_osu_client *ctx, const char *fmt, ...) -{ - va_list ap; - FILE *f; - - if (!ctx->summary_file) - return; - - f = fopen(ctx->summary_file, "a"); - if (f == NULL) - return; - - va_start(ap, fmt); - vfprintf(f, fmt, ap); - va_end(ap); - fprintf(f, "\n"); - fclose(f); -} - - -void debug_dump_node(struct hs20_osu_client *ctx, const char *title, - xml_node_t *node) -{ - char *str = xml_node_to_str(ctx->xml, node); - wpa_printf(MSG_DEBUG, "[hs20] %s: '%s'", title, str); - free(str); -} - - -static int valid_fqdn(const char *fqdn) -{ - const char *pos; - - /* TODO: could make this more complete.. */ - if (strchr(fqdn, '.') == 0 || strlen(fqdn) > 255) - return 0; - for (pos = fqdn; *pos; pos++) { - if (*pos >= 'a' && *pos <= 'z') - continue; - if (*pos >= 'A' && *pos <= 'Z') - continue; - if (*pos >= '0' && *pos <= '9') - continue; - if (*pos == '-' || *pos == '.' || *pos == '_') - continue; - return 0; - } - return 1; -} - - -static int android_update_permission(const char *path, mode_t mode) -{ -#ifdef ANDROID - /* we need to change file/folder permission for Android */ - - if (!path) { - wpa_printf(MSG_ERROR, "file path null"); - return -1; - } - - /* Allow processes running with Group ID as AID_WIFI, - * to read files from SP, SP/<fqdn>, Cert and osu-info directories */ - if (lchown(path, -1, AID_WIFI)) { - wpa_printf(MSG_INFO, "CTRL: Could not lchown directory: %s", - strerror(errno)); - return -1; - } - - if (chmod(path, mode) < 0) { - wpa_printf(MSG_INFO, "CTRL: Could not chmod directory: %s", - strerror(errno)); - return -1; - } -#endif /* ANDROID */ - - return 0; -} - - -int osu_get_certificate(struct hs20_osu_client *ctx, xml_node_t *getcert) -{ - xml_node_t *node; - char *url, *user = NULL, *pw = NULL; - char *proto; - int ret = -1; - - proto = xml_node_get_attr_value(ctx->xml, getcert, - "enrollmentProtocol"); - if (!proto) - return -1; - wpa_printf(MSG_INFO, "getCertificate - enrollmentProtocol=%s", proto); - write_summary(ctx, "getCertificate - enrollmentProtocol=%s", proto); - if (os_strcasecmp(proto, "EST") != 0) { - wpa_printf(MSG_INFO, "Unsupported enrollmentProtocol"); - xml_node_get_attr_value_free(ctx->xml, proto); - return -1; - } - xml_node_get_attr_value_free(ctx->xml, proto); - - node = get_node(ctx->xml, getcert, "enrollmentServerURI"); - if (node == NULL) { - wpa_printf(MSG_INFO, "Could not find enrollmentServerURI node"); - xml_node_get_attr_value_free(ctx->xml, proto); - return -1; - } - url = xml_node_get_text(ctx->xml, node); - if (url == NULL) { - wpa_printf(MSG_INFO, "Could not get URL text"); - return -1; - } - wpa_printf(MSG_INFO, "enrollmentServerURI: %s", url); - write_summary(ctx, "enrollmentServerURI: %s", url); - - node = get_node(ctx->xml, getcert, "estUserID"); - if (node == NULL && !ctx->client_cert_present) { - wpa_printf(MSG_INFO, "Could not find estUserID node"); - goto fail; - } - if (node) { - user = xml_node_get_text(ctx->xml, node); - if (user == NULL) { - wpa_printf(MSG_INFO, "Could not get estUserID text"); - goto fail; - } - wpa_printf(MSG_INFO, "estUserID: %s", user); - write_summary(ctx, "estUserID: %s", user); - } - - node = get_node(ctx->xml, getcert, "estPassword"); - if (node == NULL && !ctx->client_cert_present) { - wpa_printf(MSG_INFO, "Could not find estPassword node"); - goto fail; - } - if (node) { - pw = xml_node_get_base64_text(ctx->xml, node, NULL); - if (pw == NULL) { - wpa_printf(MSG_INFO, "Could not get estPassword text"); - goto fail; - } - wpa_printf(MSG_INFO, "estPassword: %s", pw); - } - - mkdir("Cert", S_IRWXU); - android_update_permission("Cert", S_IRWXU | S_IRWXG); - - if (est_load_cacerts(ctx, url) < 0 || - est_build_csr(ctx, url) < 0 || - est_simple_enroll(ctx, url, user, pw) < 0) - goto fail; - - ret = 0; -fail: - xml_node_get_text_free(ctx->xml, url); - xml_node_get_text_free(ctx->xml, user); - xml_node_get_text_free(ctx->xml, pw); - - return ret; -} - - -static int process_est_cert(struct hs20_osu_client *ctx, xml_node_t *cert, - const char *fqdn) -{ - u8 digest1[SHA256_MAC_LEN], digest2[SHA256_MAC_LEN]; - char *der, *pem; - size_t der_len, pem_len; - char *fingerprint; - char buf[200]; - - wpa_printf(MSG_INFO, "PPS for certificate credential - fqdn=%s", fqdn); - - fingerprint = xml_node_get_text(ctx->xml, cert); - if (fingerprint == NULL) - return -1; - if (hexstr2bin(fingerprint, digest1, SHA256_MAC_LEN) < 0) { - wpa_printf(MSG_INFO, "Invalid SHA256 hash value"); - write_result(ctx, "Invalid client certificate SHA256 hash value in PPS"); - xml_node_get_text_free(ctx->xml, fingerprint); - return -1; - } - xml_node_get_text_free(ctx->xml, fingerprint); - - der = os_readfile("Cert/est_cert.der", &der_len); - if (der == NULL) { - wpa_printf(MSG_INFO, "Could not find client certificate from EST"); - write_result(ctx, "Could not find client certificate from EST"); - return -1; - } - - if (sha256_vector(1, (const u8 **) &der, &der_len, digest2) < 0) { - os_free(der); - return -1; - } - os_free(der); - - if (os_memcmp(digest1, digest2, sizeof(digest1)) != 0) { - wpa_printf(MSG_INFO, "Client certificate from EST does not match fingerprint from PPS MO"); - write_result(ctx, "Client certificate from EST does not match fingerprint from PPS MO"); - return -1; - } - - wpa_printf(MSG_INFO, "Client certificate from EST matches PPS MO"); - unlink("Cert/est_cert.der"); - - os_snprintf(buf, sizeof(buf), "SP/%s/client-ca.pem", fqdn); - if (rename("Cert/est-cacerts.pem", buf) < 0) { - wpa_printf(MSG_INFO, "Could not move est-cacerts.pem to client-ca.pem: %s", - strerror(errno)); - return -1; - } - pem = os_readfile(buf, &pem_len); - - os_snprintf(buf, sizeof(buf), "SP/%s/client-cert.pem", fqdn); - if (rename("Cert/est_cert.pem", buf) < 0) { - wpa_printf(MSG_INFO, "Could not move est_cert.pem to client-cert.pem: %s", - strerror(errno)); - os_free(pem); - return -1; - } - - if (pem) { - FILE *f = fopen(buf, "a"); - if (f) { - fwrite(pem, pem_len, 1, f); - fclose(f); - } - os_free(pem); - } - - os_snprintf(buf, sizeof(buf), "SP/%s/client-key.pem", fqdn); - if (rename("Cert/privkey-plain.pem", buf) < 0) { - wpa_printf(MSG_INFO, "Could not move privkey-plain.pem to client-key.pem: %s", - strerror(errno)); - return -1; - } - - unlink("Cert/est-req.b64"); - unlink("Cert/est-req.pem"); - rmdir("Cert"); - - return 0; -} - - -#define TMP_CERT_DL_FILE "tmp-cert-download" - -static int download_cert(struct hs20_osu_client *ctx, xml_node_t *params, - const char *fname) -{ - xml_node_t *url_node, *hash_node; - char *url, *hash; - char *cert; - size_t len; - u8 digest1[SHA256_MAC_LEN], digest2[SHA256_MAC_LEN]; - int res; - char *b64; - FILE *f; - - url_node = get_node(ctx->xml, params, "CertURL"); - hash_node = get_node(ctx->xml, params, "CertSHA256Fingerprint"); - if (url_node == NULL || hash_node == NULL) - return -1; - url = xml_node_get_text(ctx->xml, url_node); - hash = xml_node_get_text(ctx->xml, hash_node); - if (url == NULL || hash == NULL) { - xml_node_get_text_free(ctx->xml, url); - xml_node_get_text_free(ctx->xml, hash); - return -1; - } - - wpa_printf(MSG_INFO, "CertURL: %s", url); - wpa_printf(MSG_INFO, "SHA256 hash: %s", hash); - - if (hexstr2bin(hash, digest1, SHA256_MAC_LEN) < 0) { - wpa_printf(MSG_INFO, "Invalid SHA256 hash value"); - write_result(ctx, "Invalid SHA256 hash value for downloaded certificate"); - xml_node_get_text_free(ctx->xml, hash); - return -1; - } - xml_node_get_text_free(ctx->xml, hash); - - write_summary(ctx, "Download certificate from %s", url); - ctx->no_osu_cert_validation = 1; - http_ocsp_set(ctx->http, 1); - res = http_download_file(ctx->http, url, TMP_CERT_DL_FILE, NULL); - http_ocsp_set(ctx->http, - (ctx->workarounds & WORKAROUND_OCSP_OPTIONAL) ? 1 : 2); - ctx->no_osu_cert_validation = 0; - xml_node_get_text_free(ctx->xml, url); - if (res < 0) - return -1; - - cert = os_readfile(TMP_CERT_DL_FILE, &len); - remove(TMP_CERT_DL_FILE); - if (cert == NULL) - return -1; - - if (sha256_vector(1, (const u8 **) &cert, &len, digest2) < 0) { - os_free(cert); - return -1; - } - - if (os_memcmp(digest1, digest2, sizeof(digest1)) != 0) { - wpa_printf(MSG_INFO, "Downloaded certificate fingerprint did not match"); - write_result(ctx, "Downloaded certificate fingerprint did not match"); - os_free(cert); - return -1; - } - - b64 = base64_encode(cert, len, NULL); - os_free(cert); - if (b64 == NULL) - return -1; - - f = fopen(fname, "wb"); - if (f == NULL) { - os_free(b64); - return -1; - } - - fprintf(f, "-----BEGIN CERTIFICATE-----\n" - "%s" - "-----END CERTIFICATE-----\n", - b64); - - os_free(b64); - fclose(f); - - wpa_printf(MSG_INFO, "Downloaded certificate into %s and validated fingerprint", - fname); - write_summary(ctx, "Downloaded certificate into %s and validated fingerprint", - fname); - - return 0; -} - - -static int cmd_dl_osu_ca(struct hs20_osu_client *ctx, const char *pps_fname, - const char *ca_fname) -{ - xml_node_t *pps, *node; - int ret; - - pps = node_from_file(ctx->xml, pps_fname); - if (pps == NULL) { - wpa_printf(MSG_INFO, "Could not read or parse '%s'", pps_fname); - return -1; - } - - node = get_child_node(ctx->xml, pps, - "SubscriptionUpdate/TrustRoot"); - if (node == NULL) { - wpa_printf(MSG_INFO, "No SubscriptionUpdate/TrustRoot/CertURL found from PPS"); - xml_node_free(ctx->xml, pps); - return -1; - } - - ret = download_cert(ctx, node, ca_fname); - xml_node_free(ctx->xml, pps); - - return ret; -} - - -static int cmd_dl_polupd_ca(struct hs20_osu_client *ctx, const char *pps_fname, - const char *ca_fname) -{ - xml_node_t *pps, *node; - int ret; - - pps = node_from_file(ctx->xml, pps_fname); - if (pps == NULL) { - wpa_printf(MSG_INFO, "Could not read or parse '%s'", pps_fname); - return -1; - } - - node = get_child_node(ctx->xml, pps, - "Policy/PolicyUpdate/TrustRoot"); - if (node == NULL) { - wpa_printf(MSG_INFO, "No Policy/PolicyUpdate/TrustRoot/CertURL found from PPS"); - xml_node_free(ctx->xml, pps); - return -2; - } - - ret = download_cert(ctx, node, ca_fname); - xml_node_free(ctx->xml, pps); - - return ret; -} - - -static int cmd_dl_aaa_ca(struct hs20_osu_client *ctx, const char *pps_fname, - const char *ca_fname) -{ - xml_node_t *pps, *node, *aaa; - int ret; - - pps = node_from_file(ctx->xml, pps_fname); - if (pps == NULL) { - wpa_printf(MSG_INFO, "Could not read or parse '%s'", pps_fname); - return -1; - } - - node = get_child_node(ctx->xml, pps, - "AAAServerTrustRoot"); - if (node == NULL) { - wpa_printf(MSG_INFO, "No AAAServerTrustRoot/CertURL found from PPS"); - xml_node_free(ctx->xml, pps); - return -2; - } - - aaa = xml_node_first_child(ctx->xml, node); - if (aaa == NULL) { - wpa_printf(MSG_INFO, "No AAAServerTrustRoot/CertURL found from PPS"); - xml_node_free(ctx->xml, pps); - return -1; - } - - ret = download_cert(ctx, aaa, ca_fname); - xml_node_free(ctx->xml, pps); - - return ret; -} - - -static int download_trust_roots(struct hs20_osu_client *ctx, - const char *pps_fname) -{ - char *dir, *pos; - char fname[300]; - int ret, ret1; - - dir = os_strdup(pps_fname); - if (dir == NULL) - return -1; - pos = os_strrchr(dir, '/'); - if (pos == NULL) { - os_free(dir); - return -1; - } - *pos = '\0'; - - snprintf(fname, sizeof(fname), "%s/ca.pem", dir); - ret = cmd_dl_osu_ca(ctx, pps_fname, fname); - snprintf(fname, sizeof(fname), "%s/polupd-ca.pem", dir); - ret1 = cmd_dl_polupd_ca(ctx, pps_fname, fname); - if (ret == 0 && ret1 == -1) - ret = -1; - snprintf(fname, sizeof(fname), "%s/aaa-ca.pem", dir); - ret1 = cmd_dl_aaa_ca(ctx, pps_fname, fname); - if (ret == 0 && ret1 == -1) - ret = -1; - - os_free(dir); - - return ret; -} - - -static int server_dnsname_suffix_match(struct hs20_osu_client *ctx, - const char *fqdn) -{ - size_t match_len, len, i; - const char *val; - - match_len = os_strlen(fqdn); - - for (i = 0; i < ctx->server_dnsname_count; i++) { - wpa_printf(MSG_INFO, - "Checking suffix match against server dNSName %s", - ctx->server_dnsname[i]); - val = ctx->server_dnsname[i]; - len = os_strlen(val); - - if (match_len > len) - continue; - - if (os_strncasecmp(val + len - match_len, fqdn, match_len) != 0) - continue; /* no match */ - - if (match_len == len) - return 1; /* exact match */ - - if (val[len - match_len - 1] == '.') - return 1; /* full label match completes suffix match */ - - /* Reject due to incomplete label match */ - } - - /* None of the dNSName(s) matched */ - return 0; -} - - -int hs20_add_pps_mo(struct hs20_osu_client *ctx, const char *uri, - xml_node_t *add_mo, char *fname, size_t fname_len) -{ - char *str; - char *fqdn, *pos; - xml_node_t *tnds, *mo, *cert; - const char *name; - int ret; - - if (strncmp(uri, "./Wi-Fi/", 8) != 0) { - wpa_printf(MSG_INFO, "Unsupported location for addMO to add PPS MO: '%s'", - uri); - write_result(ctx, "Unsupported location for addMO to add PPS MO: '%s'", - uri); - return -1; - } - - fqdn = strdup(uri + 8); - if (fqdn == NULL) - return -1; - pos = strchr(fqdn, '/'); - if (pos) { - if (os_strcasecmp(pos, "/PerProviderSubscription") != 0) { - wpa_printf(MSG_INFO, "Unsupported location for addMO to add PPS MO (extra directory): '%s'", - uri); - write_result(ctx, "Unsupported location for addMO to " - "add PPS MO (extra directory): '%s'", uri); - free(fqdn); - return -1; - } - *pos = '\0'; /* remove trailing slash and PPS node name */ - } - wpa_printf(MSG_INFO, "SP FQDN: %s", fqdn); - - if (!server_dnsname_suffix_match(ctx, fqdn)) { - wpa_printf(MSG_INFO, - "FQDN '%s' for new PPS MO did not have suffix match with server's dNSName values, count: %d", - fqdn, (int) ctx->server_dnsname_count); - write_result(ctx, "FQDN '%s' for new PPS MO did not have suffix match with server's dNSName values", - fqdn); - free(fqdn); - return -1; - } - - if (!valid_fqdn(fqdn)) { - wpa_printf(MSG_INFO, "Invalid FQDN '%s'", fqdn); - write_result(ctx, "Invalid FQDN '%s'", fqdn); - free(fqdn); - return -1; - } - - mkdir("SP", S_IRWXU); - snprintf(fname, fname_len, "SP/%s", fqdn); - if (mkdir(fname, S_IRWXU) < 0) { - if (errno != EEXIST) { - int err = errno; - wpa_printf(MSG_INFO, "mkdir(%s) failed: %s", - fname, strerror(err)); - free(fqdn); - return -1; - } - } - - android_update_permission("SP", S_IRWXU | S_IRWXG); - android_update_permission(fname, S_IRWXU | S_IRWXG); - - snprintf(fname, fname_len, "SP/%s/pps.xml", fqdn); - - if (os_file_exists(fname)) { - wpa_printf(MSG_INFO, "PPS file '%s' exists - reject addMO", - fname); - write_result(ctx, "PPS file '%s' exists - reject addMO", - fname); - free(fqdn); - return -2; - } - wpa_printf(MSG_INFO, "Using PPS file: %s", fname); - - str = xml_node_get_text(ctx->xml, add_mo); - if (str == NULL) { - wpa_printf(MSG_INFO, "Could not extract MO text"); - free(fqdn); - return -1; - } - wpa_printf(MSG_DEBUG, "[hs20] addMO text: '%s'", str); - - tnds = xml_node_from_buf(ctx->xml, str); - xml_node_get_text_free(ctx->xml, str); - if (tnds == NULL) { - wpa_printf(MSG_INFO, "[hs20] Could not parse addMO text"); - free(fqdn); - return -1; - } - - mo = tnds_to_mo(ctx->xml, tnds); - if (mo == NULL) { - wpa_printf(MSG_INFO, "[hs20] Could not parse addMO TNDS text"); - free(fqdn); - return -1; - } - - debug_dump_node(ctx, "Parsed TNDS", mo); - - name = xml_node_get_localname(ctx->xml, mo); - if (os_strcasecmp(name, "PerProviderSubscription") != 0) { - wpa_printf(MSG_INFO, "[hs20] Unexpected PPS MO root node name '%s'", - name); - free(fqdn); - return -1; - } - - cert = get_child_node(ctx->xml, mo, - "Credential/DigitalCertificate/" - "CertSHA256Fingerprint"); - if (cert && process_est_cert(ctx, cert, fqdn) < 0) { - xml_node_free(ctx->xml, mo); - free(fqdn); - return -1; - } - free(fqdn); - - if (node_to_file(ctx->xml, fname, mo) < 0) { - wpa_printf(MSG_INFO, "Could not write MO to file"); - xml_node_free(ctx->xml, mo); - return -1; - } - xml_node_free(ctx->xml, mo); - - wpa_printf(MSG_INFO, "A new PPS MO added as '%s'", fname); - write_summary(ctx, "A new PPS MO added as '%s'", fname); - - ret = download_trust_roots(ctx, fname); - if (ret < 0) { - wpa_printf(MSG_INFO, "Remove invalid PPS MO file"); - write_summary(ctx, "Remove invalid PPS MO file"); - unlink(fname); - } - - return ret; -} - - -int update_pps_file(struct hs20_osu_client *ctx, const char *pps_fname, - xml_node_t *pps) -{ - char *str; - FILE *f; - char backup[300]; - - if (ctx->client_cert_present) { - xml_node_t *cert; - cert = get_child_node(ctx->xml, pps, - "Credential/DigitalCertificate/" - "CertSHA256Fingerprint"); - if (cert && os_file_exists("Cert/est_cert.der") && - process_est_cert(ctx, cert, ctx->fqdn) < 0) { - wpa_printf(MSG_INFO, "EST certificate update processing failed on PPS MO update"); - return -1; - } - } - - wpa_printf(MSG_INFO, "Updating PPS MO %s", pps_fname); - - str = xml_node_to_str(ctx->xml, pps); - if (str == NULL) { - wpa_printf(MSG_ERROR, "No node found"); - return -1; - } - wpa_printf(MSG_MSGDUMP, "[hs20] Updated PPS: '%s'", str); - - snprintf(backup, sizeof(backup), "%s.bak", pps_fname); - rename(pps_fname, backup); - f = fopen(pps_fname, "w"); - if (f == NULL) { - wpa_printf(MSG_INFO, "Could not write PPS"); - rename(backup, pps_fname); - free(str); - return -1; - } - fprintf(f, "%s\n", str); - fclose(f); - - free(str); - - return 0; -} - - -void get_user_pw(struct hs20_osu_client *ctx, xml_node_t *pps, - const char *alt_loc, char **user, char **pw) -{ - xml_node_t *node; - - node = get_child_node(ctx->xml, pps, - "Credential/UsernamePassword/Username"); - if (node) - *user = xml_node_get_text(ctx->xml, node); - - node = get_child_node(ctx->xml, pps, - "Credential/UsernamePassword/Password"); - if (node) - *pw = xml_node_get_base64_text(ctx->xml, node, NULL); - - node = get_child_node(ctx->xml, pps, alt_loc); - if (node) { - xml_node_t *a; - a = get_node(ctx->xml, node, "Username"); - if (a) { - xml_node_get_text_free(ctx->xml, *user); - *user = xml_node_get_text(ctx->xml, a); - wpa_printf(MSG_INFO, "Use OSU username '%s'", *user); - } - - a = get_node(ctx->xml, node, "Password"); - if (a) { - free(*pw); - *pw = xml_node_get_base64_text(ctx->xml, a, NULL); - wpa_printf(MSG_INFO, "Use OSU password"); - } - } -} - - -/* Remove old credentials based on HomeSP/FQDN */ -static void remove_sp_creds(struct hs20_osu_client *ctx, const char *fqdn) -{ - char cmd[300]; - os_snprintf(cmd, sizeof(cmd), "REMOVE_CRED provisioning_sp=%s", fqdn); - if (wpa_command(ctx->ifname, cmd) < 0) - wpa_printf(MSG_INFO, "Failed to remove old credential(s)"); -} - - -static void set_pps_cred_policy_spe(struct hs20_osu_client *ctx, int id, - xml_node_t *spe) -{ - xml_node_t *ssid; - char *txt; - - ssid = get_node(ctx->xml, spe, "SSID"); - if (ssid == NULL) - return; - txt = xml_node_get_text(ctx->xml, ssid); - if (txt == NULL) - return; - wpa_printf(MSG_DEBUG, "- Policy/SPExclusionList/<X+>/SSID = %s", txt); - if (set_cred_quoted(ctx->ifname, id, "excluded_ssid", txt) < 0) - wpa_printf(MSG_INFO, "Failed to set cred excluded_ssid"); - xml_node_get_text_free(ctx->xml, txt); -} - - -static void set_pps_cred_policy_spel(struct hs20_osu_client *ctx, int id, - xml_node_t *spel) -{ - xml_node_t *child; - - xml_node_for_each_child(ctx->xml, child, spel) { - xml_node_for_each_check(ctx->xml, child); - set_pps_cred_policy_spe(ctx, id, child); - } -} - - -static void set_pps_cred_policy_prp(struct hs20_osu_client *ctx, int id, - xml_node_t *prp) -{ - xml_node_t *node; - char *txt = NULL, *pos; - char *prio, *country_buf = NULL; - const char *country; - char val[200]; - int priority; - - node = get_node(ctx->xml, prp, "Priority"); - if (node == NULL) - return; - prio = xml_node_get_text(ctx->xml, node); - if (prio == NULL) - return; - wpa_printf(MSG_INFO, "- Policy/PreferredRoamingPartnerList/<X+>/Priority = %s", - prio); - priority = atoi(prio); - xml_node_get_text_free(ctx->xml, prio); - - node = get_node(ctx->xml, prp, "Country"); - if (node) { - country_buf = xml_node_get_text(ctx->xml, node); - if (country_buf == NULL) - return; - country = country_buf; - wpa_printf(MSG_INFO, "- Policy/PreferredRoamingPartnerList/<X+>/Country = %s", - country); - } else { - country = "*"; - } - - node = get_node(ctx->xml, prp, "FQDN_Match"); - if (node == NULL) - goto out; - txt = xml_node_get_text(ctx->xml, node); - if (txt == NULL) - goto out; - wpa_printf(MSG_INFO, "- Policy/PreferredRoamingPartnerList/<X+>/FQDN_Match = %s", - txt); - pos = strrchr(txt, ','); - if (pos == NULL) - goto out; - *pos++ = '\0'; - - snprintf(val, sizeof(val), "%s,%d,%d,%s", txt, - strcmp(pos, "includeSubdomains") != 0, priority, country); - if (set_cred_quoted(ctx->ifname, id, "roaming_partner", val) < 0) - wpa_printf(MSG_INFO, "Failed to set cred roaming_partner"); -out: - xml_node_get_text_free(ctx->xml, country_buf); - xml_node_get_text_free(ctx->xml, txt); -} - - -static void set_pps_cred_policy_prpl(struct hs20_osu_client *ctx, int id, - xml_node_t *prpl) -{ - xml_node_t *child; - - xml_node_for_each_child(ctx->xml, child, prpl) { - xml_node_for_each_check(ctx->xml, child); - set_pps_cred_policy_prp(ctx, id, child); - } -} - - -static void set_pps_cred_policy_min_backhaul(struct hs20_osu_client *ctx, int id, - xml_node_t *min_backhaul) -{ - xml_node_t *node; - char *type, *dl = NULL, *ul = NULL; - int home; - - node = get_node(ctx->xml, min_backhaul, "NetworkType"); - if (node == NULL) { - wpa_printf(MSG_INFO, "Ignore MinBackhaulThreshold without mandatory NetworkType node"); - return; - } - - type = xml_node_get_text(ctx->xml, node); - if (type == NULL) - return; - wpa_printf(MSG_INFO, "- Policy/MinBackhaulThreshold/<X+>/NetworkType = %s", - type); - if (os_strcasecmp(type, "home") == 0) - home = 1; - else if (os_strcasecmp(type, "roaming") == 0) - home = 0; - else { - wpa_printf(MSG_INFO, "Ignore MinBackhaulThreshold with invalid NetworkType"); - xml_node_get_text_free(ctx->xml, type); - return; - } - xml_node_get_text_free(ctx->xml, type); - - node = get_node(ctx->xml, min_backhaul, "DLBandwidth"); - if (node) - dl = xml_node_get_text(ctx->xml, node); - - node = get_node(ctx->xml, min_backhaul, "ULBandwidth"); - if (node) - ul = xml_node_get_text(ctx->xml, node); - - if (dl == NULL && ul == NULL) { - wpa_printf(MSG_INFO, "Ignore MinBackhaulThreshold without either DLBandwidth or ULBandwidth nodes"); - return; - } - - if (dl) - wpa_printf(MSG_INFO, "- Policy/MinBackhaulThreshold/<X+>/DLBandwidth = %s", - dl); - if (ul) - wpa_printf(MSG_INFO, "- Policy/MinBackhaulThreshold/<X+>/ULBandwidth = %s", - ul); - - if (home) { - if (dl && - set_cred(ctx->ifname, id, "min_dl_bandwidth_home", dl) < 0) - wpa_printf(MSG_INFO, "Failed to set cred bandwidth limit"); - if (ul && - set_cred(ctx->ifname, id, "min_ul_bandwidth_home", ul) < 0) - wpa_printf(MSG_INFO, "Failed to set cred bandwidth limit"); - } else { - if (dl && - set_cred(ctx->ifname, id, "min_dl_bandwidth_roaming", dl) < - 0) - wpa_printf(MSG_INFO, "Failed to set cred bandwidth limit"); - if (ul && - set_cred(ctx->ifname, id, "min_ul_bandwidth_roaming", ul) < - 0) - wpa_printf(MSG_INFO, "Failed to set cred bandwidth limit"); - } - - xml_node_get_text_free(ctx->xml, dl); - xml_node_get_text_free(ctx->xml, ul); -} - - -static void set_pps_cred_policy_min_backhaul_list(struct hs20_osu_client *ctx, - int id, xml_node_t *node) -{ - xml_node_t *child; - - wpa_printf(MSG_INFO, "- Policy/MinBackhaulThreshold"); - - xml_node_for_each_child(ctx->xml, child, node) { - xml_node_for_each_check(ctx->xml, child); - set_pps_cred_policy_min_backhaul(ctx, id, child); - } -} - - -static void set_pps_cred_policy_update(struct hs20_osu_client *ctx, int id, - xml_node_t *node) -{ - wpa_printf(MSG_INFO, "- Policy/PolicyUpdate"); - /* Not used in wpa_supplicant */ -} - - -static void set_pps_cred_policy_required_proto_port(struct hs20_osu_client *ctx, - int id, xml_node_t *tuple) -{ - xml_node_t *node; - char *proto, *port; - char *buf; - size_t buflen; - - node = get_node(ctx->xml, tuple, "IPProtocol"); - if (node == NULL) { - wpa_printf(MSG_INFO, "Ignore RequiredProtoPortTuple without mandatory IPProtocol node"); - return; - } - - proto = xml_node_get_text(ctx->xml, node); - if (proto == NULL) - return; - - wpa_printf(MSG_INFO, "- Policy/RequiredProtoPortTuple/<X+>/IPProtocol = %s", - proto); - - node = get_node(ctx->xml, tuple, "PortNumber"); - port = node ? xml_node_get_text(ctx->xml, node) : NULL; - if (port) { - wpa_printf(MSG_INFO, "- Policy/RequiredProtoPortTuple/<X+>/PortNumber = %s", - port); - buflen = os_strlen(proto) + os_strlen(port) + 10; - buf = os_malloc(buflen); - if (buf) - os_snprintf(buf, buflen, "%s:%s", proto, port); - xml_node_get_text_free(ctx->xml, port); - } else { - buflen = os_strlen(proto) + 10; - buf = os_malloc(buflen); - if (buf) - os_snprintf(buf, buflen, "%s", proto); - } - - xml_node_get_text_free(ctx->xml, proto); - - if (buf == NULL) - return; - - if (set_cred(ctx->ifname, id, "req_conn_capab", buf) < 0) - wpa_printf(MSG_INFO, "Could not set req_conn_capab"); - - os_free(buf); -} - - -static void set_pps_cred_policy_required_proto_ports(struct hs20_osu_client *ctx, - int id, xml_node_t *node) -{ - xml_node_t *child; - - wpa_printf(MSG_INFO, "- Policy/RequiredProtoPortTuple"); - - xml_node_for_each_child(ctx->xml, child, node) { - xml_node_for_each_check(ctx->xml, child); - set_pps_cred_policy_required_proto_port(ctx, id, child); - } -} - - -static void set_pps_cred_policy_max_bss_load(struct hs20_osu_client *ctx, int id, - xml_node_t *node) -{ - char *str = xml_node_get_text(ctx->xml, node); - if (str == NULL) - return; - wpa_printf(MSG_INFO, "- Policy/MaximumBSSLoadValue - %s", str); - if (set_cred(ctx->ifname, id, "max_bss_load", str) < 0) - wpa_printf(MSG_INFO, "Failed to set cred max_bss_load limit"); - xml_node_get_text_free(ctx->xml, str); -} - - -static void set_pps_cred_policy(struct hs20_osu_client *ctx, int id, - xml_node_t *node) -{ - xml_node_t *child; - const char *name; - - wpa_printf(MSG_INFO, "- Policy"); - - 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 (os_strcasecmp(name, "PreferredRoamingPartnerList") == 0) - set_pps_cred_policy_prpl(ctx, id, child); - else if (os_strcasecmp(name, "MinBackhaulThreshold") == 0) - set_pps_cred_policy_min_backhaul_list(ctx, id, child); - else if (os_strcasecmp(name, "PolicyUpdate") == 0) - set_pps_cred_policy_update(ctx, id, child); - else if (os_strcasecmp(name, "SPExclusionList") == 0) - set_pps_cred_policy_spel(ctx, id, child); - else if (os_strcasecmp(name, "RequiredProtoPortTuple") == 0) - set_pps_cred_policy_required_proto_ports(ctx, id, child); - else if (os_strcasecmp(name, "MaximumBSSLoadValue") == 0) - set_pps_cred_policy_max_bss_load(ctx, id, child); - else - wpa_printf(MSG_INFO, "Unknown Policy node '%s'", name); - } -} - - -static void set_pps_cred_priority(struct hs20_osu_client *ctx, int id, - xml_node_t *node) -{ - char *str = xml_node_get_text(ctx->xml, node); - if (str == NULL) - return; - wpa_printf(MSG_INFO, "- CredentialPriority = %s", str); - if (set_cred(ctx->ifname, id, "sp_priority", str) < 0) - wpa_printf(MSG_INFO, "Failed to set cred sp_priority"); - xml_node_get_text_free(ctx->xml, str); -} - - -static void set_pps_cred_aaa_server_trust_root(struct hs20_osu_client *ctx, - int id, xml_node_t *node) -{ - wpa_printf(MSG_INFO, "- AAAServerTrustRoot - TODO"); -} - - -static void set_pps_cred_sub_update(struct hs20_osu_client *ctx, int id, - xml_node_t *node) -{ - wpa_printf(MSG_INFO, "- SubscriptionUpdate"); - /* not used within wpa_supplicant */ -} - - -static void set_pps_cred_home_sp_network_id(struct hs20_osu_client *ctx, - int id, xml_node_t *node) -{ - xml_node_t *ssid_node, *hessid_node; - char *ssid, *hessid; - - ssid_node = get_node(ctx->xml, node, "SSID"); - if (ssid_node == NULL) { - wpa_printf(MSG_INFO, "Ignore HomeSP/NetworkID without mandatory SSID node"); - return; - } - - hessid_node = get_node(ctx->xml, node, "HESSID"); - - ssid = xml_node_get_text(ctx->xml, ssid_node); - if (ssid == NULL) - return; - hessid = hessid_node ? xml_node_get_text(ctx->xml, hessid_node) : NULL; - - wpa_printf(MSG_INFO, "- HomeSP/NetworkID/<X+>/SSID = %s", ssid); - if (hessid) - wpa_printf(MSG_INFO, "- HomeSP/NetworkID/<X+>/HESSID = %s", - hessid); - - /* TODO: Configure to wpa_supplicant */ - - xml_node_get_text_free(ctx->xml, ssid); - xml_node_get_text_free(ctx->xml, hessid); -} - - -static void set_pps_cred_home_sp_network_ids(struct hs20_osu_client *ctx, - int id, xml_node_t *node) -{ - xml_node_t *child; - - wpa_printf(MSG_INFO, "- HomeSP/NetworkID"); - - xml_node_for_each_child(ctx->xml, child, node) { - xml_node_for_each_check(ctx->xml, child); - set_pps_cred_home_sp_network_id(ctx, id, child); - } -} - - -static void set_pps_cred_home_sp_friendly_name(struct hs20_osu_client *ctx, - int id, xml_node_t *node) -{ - char *str = xml_node_get_text(ctx->xml, node); - if (str == NULL) - return; - wpa_printf(MSG_INFO, "- HomeSP/FriendlyName = %s", str); - /* not used within wpa_supplicant(?) */ - xml_node_get_text_free(ctx->xml, str); -} - - -static void set_pps_cred_home_sp_icon_url(struct hs20_osu_client *ctx, - int id, xml_node_t *node) -{ - char *str = xml_node_get_text(ctx->xml, node); - if (str == NULL) - return; - wpa_printf(MSG_INFO, "- HomeSP/IconURL = %s", str); - /* not used within wpa_supplicant */ - xml_node_get_text_free(ctx->xml, str); -} - - -static void set_pps_cred_home_sp_fqdn(struct hs20_osu_client *ctx, int id, - xml_node_t *node) -{ - char *str = xml_node_get_text(ctx->xml, node); - if (str == NULL) - return; - wpa_printf(MSG_INFO, "- HomeSP/FQDN = %s", str); - if (set_cred_quoted(ctx->ifname, id, "domain", str) < 0) - wpa_printf(MSG_INFO, "Failed to set cred domain"); - if (set_cred_quoted(ctx->ifname, id, "domain_suffix_match", str) < 0) - wpa_printf(MSG_INFO, "Failed to set cred domain_suffix_match"); - xml_node_get_text_free(ctx->xml, str); -} - - -static void set_pps_cred_home_sp_oi(struct hs20_osu_client *ctx, int id, - xml_node_t *node) -{ - xml_node_t *child; - const char *name; - char *homeoi = NULL; - int required = 0; - char *str; - - 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 (strcasecmp(name, "HomeOI") == 0 && !homeoi) { - homeoi = xml_node_get_text(ctx->xml, child); - wpa_printf(MSG_INFO, "- HomeSP/HomeOIList/<X+>/HomeOI = %s", - homeoi); - } else if (strcasecmp(name, "HomeOIRequired") == 0) { - str = xml_node_get_text(ctx->xml, child); - wpa_printf(MSG_INFO, "- HomeSP/HomeOIList/<X+>/HomeOIRequired = '%s'", - str); - if (str == NULL) - continue; - required = strcasecmp(str, "true") == 0; - xml_node_get_text_free(ctx->xml, str); - } else - wpa_printf(MSG_INFO, "Unknown HomeOIList node '%s'", - name); - } - - if (homeoi == NULL) { - wpa_printf(MSG_INFO, "- HomeSP/HomeOIList/<X+> without HomeOI ignored"); - return; - } - - wpa_printf(MSG_INFO, "- HomeSP/HomeOIList/<X+> '%s' required=%d", - homeoi, required); - - if (required) { - if (set_cred(ctx->ifname, id, "required_roaming_consortium", - homeoi) < 0) - wpa_printf(MSG_INFO, "Failed to set cred required_roaming_consortium"); - } else { - if (set_cred(ctx->ifname, id, "roaming_consortium", homeoi) < 0) - wpa_printf(MSG_INFO, "Failed to set cred roaming_consortium"); - } - - xml_node_get_text_free(ctx->xml, homeoi); -} - - -static void set_pps_cred_home_sp_oi_list(struct hs20_osu_client *ctx, int id, - xml_node_t *node) -{ - xml_node_t *child; - - wpa_printf(MSG_INFO, "- HomeSP/HomeOIList"); - - xml_node_for_each_child(ctx->xml, child, node) { - xml_node_for_each_check(ctx->xml, child); - set_pps_cred_home_sp_oi(ctx, id, child); - } -} - - -static void set_pps_cred_home_sp_other_partner(struct hs20_osu_client *ctx, - int id, xml_node_t *node) -{ - xml_node_t *child; - const char *name; - char *fqdn = 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 (os_strcasecmp(name, "FQDN") == 0 && !fqdn) { - fqdn = xml_node_get_text(ctx->xml, child); - wpa_printf(MSG_INFO, "- HomeSP/OtherHomePartners/<X+>/FQDN = %s", - fqdn); - } else - wpa_printf(MSG_INFO, "Unknown OtherHomePartners node '%s'", - name); - } - - if (fqdn == NULL) { - wpa_printf(MSG_INFO, "- HomeSP/OtherHomePartners/<X+> without FQDN ignored"); - return; - } - - if (set_cred_quoted(ctx->ifname, id, "domain", fqdn) < 0) - wpa_printf(MSG_INFO, "Failed to set cred domain for OtherHomePartners node"); - - xml_node_get_text_free(ctx->xml, fqdn); -} - - -static void set_pps_cred_home_sp_other_partners(struct hs20_osu_client *ctx, - int id, - xml_node_t *node) -{ - xml_node_t *child; - - wpa_printf(MSG_INFO, "- HomeSP/OtherHomePartners"); - - xml_node_for_each_child(ctx->xml, child, node) { - xml_node_for_each_check(ctx->xml, child); - set_pps_cred_home_sp_other_partner(ctx, id, child); - } -} - - -static void set_pps_cred_home_sp_roaming_consortium_oi( - struct hs20_osu_client *ctx, int id, xml_node_t *node) -{ - char *str = xml_node_get_text(ctx->xml, node); - if (str == NULL) - return; - wpa_printf(MSG_INFO, "- HomeSP/RoamingConsortiumOI = %s", str); - if (set_cred_quoted(ctx->ifname, id, "roaming_consortiums", - str) < 0) - wpa_printf(MSG_INFO, "Failed to set cred roaming_consortiums"); - xml_node_get_text_free(ctx->xml, str); -} - - -static void set_pps_cred_home_sp(struct hs20_osu_client *ctx, int id, - xml_node_t *node) -{ - xml_node_t *child; - const char *name; - - wpa_printf(MSG_INFO, "- HomeSP"); - - 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 (os_strcasecmp(name, "NetworkID") == 0) - set_pps_cred_home_sp_network_ids(ctx, id, child); - else if (os_strcasecmp(name, "FriendlyName") == 0) - set_pps_cred_home_sp_friendly_name(ctx, id, child); - else if (os_strcasecmp(name, "IconURL") == 0) - set_pps_cred_home_sp_icon_url(ctx, id, child); - else if (os_strcasecmp(name, "FQDN") == 0) - set_pps_cred_home_sp_fqdn(ctx, id, child); - else if (os_strcasecmp(name, "HomeOIList") == 0) - set_pps_cred_home_sp_oi_list(ctx, id, child); - else if (os_strcasecmp(name, "OtherHomePartners") == 0) - set_pps_cred_home_sp_other_partners(ctx, id, child); - else if (os_strcasecmp(name, "RoamingConsortiumOI") == 0) - set_pps_cred_home_sp_roaming_consortium_oi(ctx, id, - child); - else - wpa_printf(MSG_INFO, "Unknown HomeSP node '%s'", name); - } -} - - -static void set_pps_cred_sub_params(struct hs20_osu_client *ctx, int id, - xml_node_t *node) -{ - wpa_printf(MSG_INFO, "- SubscriptionParameters"); - /* not used within wpa_supplicant */ -} - - -static void set_pps_cred_creation_date(struct hs20_osu_client *ctx, int id, - xml_node_t *node) -{ - char *str = xml_node_get_text(ctx->xml, node); - if (str == NULL) - return; - wpa_printf(MSG_INFO, "- Credential/CreationDate = %s", str); - /* not used within wpa_supplicant */ - xml_node_get_text_free(ctx->xml, str); -} - - -static void set_pps_cred_expiration_date(struct hs20_osu_client *ctx, int id, - xml_node_t *node) -{ - char *str = xml_node_get_text(ctx->xml, node); - if (str == NULL) - return; - wpa_printf(MSG_INFO, "- Credential/ExpirationDate = %s", str); - /* not used within wpa_supplicant */ - xml_node_get_text_free(ctx->xml, str); -} - - -static void set_pps_cred_username(struct hs20_osu_client *ctx, int id, - xml_node_t *node) -{ - char *str = xml_node_get_text(ctx->xml, node); - if (str == NULL) - return; - wpa_printf(MSG_INFO, "- Credential/UsernamePassword/Username = %s", - str); - if (set_cred_quoted(ctx->ifname, id, "username", str) < 0) - wpa_printf(MSG_INFO, "Failed to set cred username"); - xml_node_get_text_free(ctx->xml, str); -} - - -static void set_pps_cred_password(struct hs20_osu_client *ctx, int id, - xml_node_t *node) -{ - int len, i; - char *pw, *hex, *pos, *end; - - pw = xml_node_get_base64_text(ctx->xml, node, &len); - if (pw == NULL) - return; - - wpa_printf(MSG_INFO, "- Credential/UsernamePassword/Password = %s", pw); - - hex = malloc(len * 2 + 1); - if (hex == NULL) { - free(pw); - return; - } - end = hex + len * 2 + 1; - pos = hex; - for (i = 0; i < len; i++) { - snprintf(pos, end - pos, "%02x", pw[i]); - pos += 2; - } - free(pw); - - if (set_cred(ctx->ifname, id, "password", hex) < 0) - wpa_printf(MSG_INFO, "Failed to set cred password"); - free(hex); -} - - -static void set_pps_cred_machine_managed(struct hs20_osu_client *ctx, int id, - xml_node_t *node) -{ - char *str = xml_node_get_text(ctx->xml, node); - if (str == NULL) - return; - wpa_printf(MSG_INFO, "- Credential/UsernamePassword/MachineManaged = %s", - str); - /* not used within wpa_supplicant */ - xml_node_get_text_free(ctx->xml, str); -} - - -static void set_pps_cred_soft_token_app(struct hs20_osu_client *ctx, int id, - xml_node_t *node) -{ - char *str = xml_node_get_text(ctx->xml, node); - if (str == NULL) - return; - wpa_printf(MSG_INFO, "- Credential/UsernamePassword/SoftTokenApp = %s", - str); - /* not used within wpa_supplicant */ - xml_node_get_text_free(ctx->xml, str); -} - - -static void set_pps_cred_able_to_share(struct hs20_osu_client *ctx, int id, - xml_node_t *node) -{ - char *str = xml_node_get_text(ctx->xml, node); - if (str == NULL) - return; - wpa_printf(MSG_INFO, "- Credential/UsernamePassword/AbleToShare = %s", - str); - /* not used within wpa_supplicant */ - xml_node_get_text_free(ctx->xml, str); -} - - -static void set_pps_cred_eap_method_eap_type(struct hs20_osu_client *ctx, - int id, xml_node_t *node) -{ - char *str = xml_node_get_text(ctx->xml, node); - int type; - const char *eap_method = NULL; - - if (!str) - return; - wpa_printf(MSG_INFO, - "- Credential/UsernamePassword/EAPMethod/EAPType = %s", str); - type = atoi(str); - switch (type) { - case EAP_TYPE_TLS: - eap_method = "TLS"; - break; - case EAP_TYPE_TTLS: - eap_method = "TTLS"; - break; - case EAP_TYPE_PEAP: - eap_method = "PEAP"; - break; - case EAP_TYPE_PWD: - eap_method = "PWD"; - break; - } - xml_node_get_text_free(ctx->xml, str); - if (!eap_method) { - wpa_printf(MSG_INFO, "Unknown EAPType value"); - return; - } - - if (set_cred(ctx->ifname, id, "eap", eap_method) < 0) - wpa_printf(MSG_INFO, "Failed to set cred eap"); -} - - -static void set_pps_cred_eap_method_inner_method(struct hs20_osu_client *ctx, - int id, xml_node_t *node) -{ - char *str = xml_node_get_text(ctx->xml, node); - const char *phase2 = NULL; - - if (!str) - return; - wpa_printf(MSG_INFO, - "- Credential/UsernamePassword/EAPMethod/InnerMethod = %s", - str); - if (os_strcmp(str, "PAP") == 0) - phase2 = "auth=PAP"; - else if (os_strcmp(str, "CHAP") == 0) - phase2 = "auth=CHAP"; - else if (os_strcmp(str, "MS-CHAP") == 0) - phase2 = "auth=MSCHAP"; - else if (os_strcmp(str, "MS-CHAP-V2") == 0) - phase2 = "auth=MSCHAPV2"; - xml_node_get_text_free(ctx->xml, str); - if (!phase2) { - wpa_printf(MSG_INFO, "Unknown InnerMethod value"); - return; - } - - if (set_cred_quoted(ctx->ifname, id, "phase2", phase2) < 0) - wpa_printf(MSG_INFO, "Failed to set cred phase2"); -} - - -static void set_pps_cred_eap_method(struct hs20_osu_client *ctx, int id, - xml_node_t *node) -{ - xml_node_t *child; - const char *name; - - wpa_printf(MSG_INFO, "- Credential/UsernamePassword/EAPMethod"); - - 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 (os_strcasecmp(name, "EAPType") == 0) - set_pps_cred_eap_method_eap_type(ctx, id, child); - else if (os_strcasecmp(name, "InnerMethod") == 0) - set_pps_cred_eap_method_inner_method(ctx, id, child); - else - wpa_printf(MSG_INFO, "Unknown Credential/UsernamePassword/EAPMethod node '%s'", - name); - } -} - - -static void set_pps_cred_username_password(struct hs20_osu_client *ctx, int id, - xml_node_t *node) -{ - xml_node_t *child; - const char *name; - - wpa_printf(MSG_INFO, "- Credential/UsernamePassword"); - - 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 (os_strcasecmp(name, "Username") == 0) - set_pps_cred_username(ctx, id, child); - else if (os_strcasecmp(name, "Password") == 0) - set_pps_cred_password(ctx, id, child); - else if (os_strcasecmp(name, "MachineManaged") == 0) - set_pps_cred_machine_managed(ctx, id, child); - else if (os_strcasecmp(name, "SoftTokenApp") == 0) - set_pps_cred_soft_token_app(ctx, id, child); - else if (os_strcasecmp(name, "AbleToShare") == 0) - set_pps_cred_able_to_share(ctx, id, child); - else if (os_strcasecmp(name, "EAPMethod") == 0) - set_pps_cred_eap_method(ctx, id, child); - else - wpa_printf(MSG_INFO, "Unknown Credential/UsernamePassword node '%s'", - name); - } -} - - -static void set_pps_cred_digital_cert(struct hs20_osu_client *ctx, int id, - xml_node_t *node, const char *fqdn) -{ - char buf[200], dir[200]; - int res; - - wpa_printf(MSG_INFO, "- Credential/DigitalCertificate"); - - if (getcwd(dir, sizeof(dir)) == NULL) - return; - - /* TODO: could build username from Subject of Subject AltName */ - if (set_cred_quoted(ctx->ifname, id, "username", "cert") < 0) { - wpa_printf(MSG_INFO, "Failed to set username"); - } - - res = os_snprintf(buf, sizeof(buf), "%s/SP/%s/client-cert.pem", dir, - fqdn); - if (os_snprintf_error(sizeof(buf), res)) - return; - if (os_file_exists(buf)) { - if (set_cred_quoted(ctx->ifname, id, "client_cert", buf) < 0) { - wpa_printf(MSG_INFO, "Failed to set client_cert"); - } - } - - res = os_snprintf(buf, sizeof(buf), "%s/SP/%s/client-key.pem", dir, - fqdn); - if (os_snprintf_error(sizeof(buf), res)) - return; - if (os_file_exists(buf)) { - if (set_cred_quoted(ctx->ifname, id, "private_key", buf) < 0) { - wpa_printf(MSG_INFO, "Failed to set private_key"); - } - } -} - - -static void set_pps_cred_realm(struct hs20_osu_client *ctx, int id, - xml_node_t *node, const char *fqdn, int sim) -{ - char *str = xml_node_get_text(ctx->xml, node); - char buf[200], dir[200]; - int res; - - if (str == NULL) - return; - - wpa_printf(MSG_INFO, "- Credential/Realm = %s", str); - if (set_cred_quoted(ctx->ifname, id, "realm", str) < 0) - wpa_printf(MSG_INFO, "Failed to set cred realm"); - xml_node_get_text_free(ctx->xml, str); - - if (sim) - return; - - if (getcwd(dir, sizeof(dir)) == NULL) - return; - res = os_snprintf(buf, sizeof(buf), "%s/SP/%s/aaa-ca.pem", dir, fqdn); - if (os_snprintf_error(sizeof(buf), res)) - return; - if (os_file_exists(buf)) { - if (set_cred_quoted(ctx->ifname, id, "ca_cert", buf) < 0) { - wpa_printf(MSG_INFO, "Failed to set CA cert"); - } - } -} - - -static void set_pps_cred_check_aaa_cert_status(struct hs20_osu_client *ctx, - int id, xml_node_t *node) -{ - char *str = xml_node_get_text(ctx->xml, node); - - if (str == NULL) - return; - - wpa_printf(MSG_INFO, "- Credential/CheckAAAServerCertStatus = %s", str); - if (os_strcasecmp(str, "true") == 0 && - set_cred(ctx->ifname, id, "ocsp", "2") < 0) - wpa_printf(MSG_INFO, "Failed to set cred ocsp"); - xml_node_get_text_free(ctx->xml, str); -} - - -static void set_pps_cred_sim(struct hs20_osu_client *ctx, int id, - xml_node_t *sim, xml_node_t *realm) -{ - xml_node_t *node; - char *imsi, *eaptype, *str, buf[20]; - int type; - int mnc_len = 3; - size_t imsi_len; - - node = get_node(ctx->xml, sim, "EAPType"); - if (node == NULL) { - wpa_printf(MSG_INFO, "No SIM/EAPType node in credential"); - return; - } - eaptype = xml_node_get_text(ctx->xml, node); - if (eaptype == NULL) { - wpa_printf(MSG_INFO, "Could not extract SIM/EAPType"); - return; - } - wpa_printf(MSG_INFO, " - Credential/SIM/EAPType = %s", eaptype); - type = atoi(eaptype); - xml_node_get_text_free(ctx->xml, eaptype); - - switch (type) { - case EAP_TYPE_SIM: - if (set_cred(ctx->ifname, id, "eap", "SIM") < 0) - wpa_printf(MSG_INFO, "Could not set eap=SIM"); - break; - case EAP_TYPE_AKA: - if (set_cred(ctx->ifname, id, "eap", "AKA") < 0) - wpa_printf(MSG_INFO, "Could not set eap=SIM"); - break; - case EAP_TYPE_AKA_PRIME: - if (set_cred(ctx->ifname, id, "eap", "AKA'") < 0) - wpa_printf(MSG_INFO, "Could not set eap=SIM"); - break; - default: - wpa_printf(MSG_INFO, "Unsupported SIM/EAPType %d", type); - return; - } - - node = get_node(ctx->xml, sim, "IMSI"); - if (node == NULL) { - wpa_printf(MSG_INFO, "No SIM/IMSI node in credential"); - return; - } - imsi = xml_node_get_text(ctx->xml, node); - if (imsi == NULL) { - wpa_printf(MSG_INFO, "Could not extract SIM/IMSI"); - return; - } - wpa_printf(MSG_INFO, " - Credential/SIM/IMSI = %s", imsi); - imsi_len = os_strlen(imsi); - if (imsi_len < 7 || imsi_len + 2 > sizeof(buf)) { - wpa_printf(MSG_INFO, "Invalid IMSI length"); - xml_node_get_text_free(ctx->xml, imsi); - return; - } - - str = xml_node_get_text(ctx->xml, node); - if (str) { - char *pos; - pos = os_strstr(str, "mnc"); - if (pos && os_strlen(pos) >= 6) { - if (os_strncmp(imsi + 3, pos + 3, 3) == 0) - mnc_len = 3; - else if (os_strncmp(imsi + 3, pos + 4, 2) == 0) - mnc_len = 2; - } - xml_node_get_text_free(ctx->xml, str); - } - - os_memcpy(buf, imsi, 3 + mnc_len); - buf[3 + mnc_len] = '-'; - os_strlcpy(buf + 3 + mnc_len + 1, imsi + 3 + mnc_len, - sizeof(buf) - 3 - mnc_len - 1); - - xml_node_get_text_free(ctx->xml, imsi); - - if (set_cred_quoted(ctx->ifname, id, "imsi", buf) < 0) - wpa_printf(MSG_INFO, "Could not set IMSI"); - - if (set_cred_quoted(ctx->ifname, id, "milenage", - "90dca4eda45b53cf0f12d7c9c3bc6a89:" - "cb9cccc4b9258e6dca4760379fb82581:000000000123") < - 0) - wpa_printf(MSG_INFO, "Could not set Milenage parameters"); -} - - -static void set_pps_cred_credential(struct hs20_osu_client *ctx, int id, - xml_node_t *node, const char *fqdn) -{ - xml_node_t *child, *sim, *realm; - const char *name; - - wpa_printf(MSG_INFO, "- Credential"); - - sim = get_node(ctx->xml, node, "SIM"); - realm = get_node(ctx->xml, node, "Realm"); - - 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 (os_strcasecmp(name, "CreationDate") == 0) - set_pps_cred_creation_date(ctx, id, child); - else if (os_strcasecmp(name, "ExpirationDate") == 0) - set_pps_cred_expiration_date(ctx, id, child); - else if (os_strcasecmp(name, "UsernamePassword") == 0) - set_pps_cred_username_password(ctx, id, child); - else if (os_strcasecmp(name, "DigitalCertificate") == 0) - set_pps_cred_digital_cert(ctx, id, child, fqdn); - else if (os_strcasecmp(name, "Realm") == 0) - set_pps_cred_realm(ctx, id, child, fqdn, sim != NULL); - else if (os_strcasecmp(name, "CheckAAAServerCertStatus") == 0) - set_pps_cred_check_aaa_cert_status(ctx, id, child); - else if (os_strcasecmp(name, "SIM") == 0) - set_pps_cred_sim(ctx, id, child, realm); - else - wpa_printf(MSG_INFO, "Unknown Credential node '%s'", - name); - } -} - - -static void set_pps_credential(struct hs20_osu_client *ctx, int id, - xml_node_t *cred, const char *fqdn) -{ - xml_node_t *child; - const char *name; - - xml_node_for_each_child(ctx->xml, child, cred) { - xml_node_for_each_check(ctx->xml, child); - name = xml_node_get_localname(ctx->xml, child); - if (os_strcasecmp(name, "Policy") == 0) - set_pps_cred_policy(ctx, id, child); - else if (os_strcasecmp(name, "CredentialPriority") == 0) - set_pps_cred_priority(ctx, id, child); - else if (os_strcasecmp(name, "AAAServerTrustRoot") == 0) - set_pps_cred_aaa_server_trust_root(ctx, id, child); - else if (os_strcasecmp(name, "SubscriptionUpdate") == 0) - set_pps_cred_sub_update(ctx, id, child); - else if (os_strcasecmp(name, "HomeSP") == 0) - set_pps_cred_home_sp(ctx, id, child); - else if (os_strcasecmp(name, "SubscriptionParameters") == 0) - set_pps_cred_sub_params(ctx, id, child); - else if (os_strcasecmp(name, "Credential") == 0) - set_pps_cred_credential(ctx, id, child, fqdn); - else - wpa_printf(MSG_INFO, "Unknown credential node '%s'", - name); - } -} - - -static void set_pps(struct hs20_osu_client *ctx, xml_node_t *pps, - const char *fqdn) -{ - xml_node_t *child; - const char *name; - int id; - char *update_identifier = NULL; - - /* - * TODO: Could consider more complex mechanism that would remove - * credentials only if there are changes in the information sent to - * wpa_supplicant. - */ - remove_sp_creds(ctx, fqdn); - - xml_node_for_each_child(ctx->xml, child, pps) { - xml_node_for_each_check(ctx->xml, child); - name = xml_node_get_localname(ctx->xml, child); - if (os_strcasecmp(name, "UpdateIdentifier") == 0) { - update_identifier = xml_node_get_text(ctx->xml, child); - if (update_identifier) { - wpa_printf(MSG_INFO, "- UpdateIdentifier = %s", - update_identifier); - break; - } - } - } - - xml_node_for_each_child(ctx->xml, child, pps) { - xml_node_for_each_check(ctx->xml, child); - name = xml_node_get_localname(ctx->xml, child); - if (os_strcasecmp(name, "UpdateIdentifier") == 0) - continue; - id = add_cred(ctx->ifname); - if (id < 0) { - wpa_printf(MSG_INFO, "Failed to add credential to wpa_supplicant"); - write_summary(ctx, "Failed to add credential to wpa_supplicant"); - break; - } - write_summary(ctx, "Add a credential to wpa_supplicant"); - if (update_identifier && - set_cred(ctx->ifname, id, "update_identifier", - update_identifier) < 0) - wpa_printf(MSG_INFO, "Failed to set update_identifier"); - if (set_cred_quoted(ctx->ifname, id, "provisioning_sp", fqdn) < - 0) - wpa_printf(MSG_INFO, "Failed to set provisioning_sp"); - wpa_printf(MSG_INFO, "credential localname: '%s'", name); - set_pps_credential(ctx, id, child, fqdn); - ctx->pps_cred_set = 1; - } - - xml_node_get_text_free(ctx->xml, update_identifier); -} - - -void cmd_set_pps(struct hs20_osu_client *ctx, const char *pps_fname) -{ - xml_node_t *pps; - const char *fqdn; - char *fqdn_buf = NULL, *pos; - - pps = node_from_file(ctx->xml, pps_fname); - if (pps == NULL) { - wpa_printf(MSG_INFO, "Could not read or parse '%s'", pps_fname); - return; - } - - fqdn = os_strstr(pps_fname, "SP/"); - if (fqdn) { - fqdn_buf = os_strdup(fqdn + 3); - if (fqdn_buf == NULL) - return; - pos = os_strchr(fqdn_buf, '/'); - if (pos) - *pos = '\0'; - fqdn = fqdn_buf; - } else - fqdn = "wi-fi.org"; - - wpa_printf(MSG_INFO, "Set PPS MO info to wpa_supplicant - SP FQDN %s", - fqdn); - set_pps(ctx, pps, fqdn); - - os_free(fqdn_buf); - xml_node_free(ctx->xml, pps); -} - - -static int cmd_get_fqdn(struct hs20_osu_client *ctx, const char *pps_fname) -{ - xml_node_t *pps, *node; - char *fqdn = NULL; - - pps = node_from_file(ctx->xml, pps_fname); - if (pps == NULL) { - wpa_printf(MSG_INFO, "Could not read or parse '%s'", pps_fname); - return -1; - } - - node = get_child_node(ctx->xml, pps, "HomeSP/FQDN"); - if (node) - fqdn = xml_node_get_text(ctx->xml, node); - - xml_node_free(ctx->xml, pps); - - if (fqdn) { - FILE *f = fopen("pps-fqdn", "w"); - if (f) { - fprintf(f, "%s", fqdn); - fclose(f); - } - xml_node_get_text_free(ctx->xml, fqdn); - return 0; - } - - xml_node_get_text_free(ctx->xml, fqdn); - return -1; -} - - -static void cmd_to_tnds(struct hs20_osu_client *ctx, const char *in_fname, - const char *out_fname, const char *urn, int use_path) -{ - xml_node_t *mo, *node; - - mo = node_from_file(ctx->xml, in_fname); - if (mo == NULL) { - wpa_printf(MSG_INFO, "Could not read or parse '%s'", in_fname); - return; - } - - node = mo_to_tnds(ctx->xml, mo, use_path, urn, NULL); - if (node) { - node_to_file(ctx->xml, out_fname, node); - xml_node_free(ctx->xml, node); - } - - xml_node_free(ctx->xml, mo); -} - - -static void cmd_from_tnds(struct hs20_osu_client *ctx, const char *in_fname, - const char *out_fname) -{ - xml_node_t *tnds, *mo; - - tnds = node_from_file(ctx->xml, in_fname); - if (tnds == NULL) { - wpa_printf(MSG_INFO, "Could not read or parse '%s'", in_fname); - return; - } - - mo = tnds_to_mo(ctx->xml, tnds); - if (mo) { - node_to_file(ctx->xml, out_fname, mo); - xml_node_free(ctx->xml, mo); - } - - xml_node_free(ctx->xml, tnds); -} - - -struct osu_icon { - int id; - char lang[4]; - char mime_type[256]; - char filename[256]; -}; - -struct osu_data { - char bssid[20]; - char url[256]; - unsigned int methods; - char osu_ssid[33]; - char osu_ssid2[33]; - char osu_nai[256]; - char osu_nai2[256]; - struct osu_lang_text friendly_name[MAX_OSU_VALS]; - size_t friendly_name_count; - struct osu_lang_text serv_desc[MAX_OSU_VALS]; - size_t serv_desc_count; - struct osu_icon icon[MAX_OSU_VALS]; - size_t icon_count; -}; - - -static struct osu_data * parse_osu_providers(const char *fname, size_t *count) -{ - FILE *f; - char buf[1000]; - struct osu_data *osu = NULL, *last = NULL; - size_t osu_count = 0; - char *pos, *end; - - f = fopen(fname, "r"); - if (f == NULL) { - wpa_printf(MSG_ERROR, "Could not open %s", fname); - return NULL; - } - - while (fgets(buf, sizeof(buf), f)) { - pos = strchr(buf, '\n'); - if (pos) - *pos = '\0'; - - if (strncmp(buf, "OSU-PROVIDER ", 13) == 0) { - last = realloc(osu, (osu_count + 1) * sizeof(*osu)); - if (last == NULL) - break; - osu = last; - last = &osu[osu_count++]; - memset(last, 0, sizeof(*last)); - snprintf(last->bssid, sizeof(last->bssid), "%s", - buf + 13); - continue; - } - if (!last) - continue; - - if (strncmp(buf, "uri=", 4) == 0) { - snprintf(last->url, sizeof(last->url), "%s", buf + 4); - continue; - } - - if (strncmp(buf, "methods=", 8) == 0) { - last->methods = strtol(buf + 8, NULL, 16); - continue; - } - - if (strncmp(buf, "osu_ssid=", 9) == 0) { - snprintf(last->osu_ssid, sizeof(last->osu_ssid), - "%s", buf + 9); - continue; - } - - if (strncmp(buf, "osu_ssid2=", 10) == 0) { - snprintf(last->osu_ssid2, sizeof(last->osu_ssid2), - "%s", buf + 10); - continue; - } - - if (os_strncmp(buf, "osu_nai=", 8) == 0) { - os_snprintf(last->osu_nai, sizeof(last->osu_nai), - "%s", buf + 8); - continue; - } - - if (os_strncmp(buf, "osu_nai2=", 9) == 0) { - os_snprintf(last->osu_nai2, sizeof(last->osu_nai2), - "%s", buf + 9); - continue; - } - - if (strncmp(buf, "friendly_name=", 14) == 0) { - struct osu_lang_text *txt; - if (last->friendly_name_count == MAX_OSU_VALS) - continue; - pos = strchr(buf + 14, ':'); - if (pos == NULL) - continue; - *pos++ = '\0'; - txt = &last->friendly_name[last->friendly_name_count++]; - snprintf(txt->lang, sizeof(txt->lang), "%s", buf + 14); - snprintf(txt->text, sizeof(txt->text), "%s", pos); - } - - if (strncmp(buf, "desc=", 5) == 0) { - struct osu_lang_text *txt; - if (last->serv_desc_count == MAX_OSU_VALS) - continue; - pos = strchr(buf + 5, ':'); - if (pos == NULL) - continue; - *pos++ = '\0'; - txt = &last->serv_desc[last->serv_desc_count++]; - snprintf(txt->lang, sizeof(txt->lang), "%s", buf + 5); - snprintf(txt->text, sizeof(txt->text), "%s", pos); - } - - if (strncmp(buf, "icon=", 5) == 0) { - struct osu_icon *icon; - if (last->icon_count == MAX_OSU_VALS) - continue; - icon = &last->icon[last->icon_count++]; - icon->id = atoi(buf + 5); - pos = strchr(buf, ':'); - if (pos == NULL) - continue; - pos = strchr(pos + 1, ':'); - if (pos == NULL) - continue; - pos = strchr(pos + 1, ':'); - if (pos == NULL) - continue; - pos++; - end = strchr(pos, ':'); - if (!end) - continue; - *end = '\0'; - snprintf(icon->lang, sizeof(icon->lang), "%s", pos); - pos = end + 1; - - end = strchr(pos, ':'); - if (end) - *end = '\0'; - snprintf(icon->mime_type, sizeof(icon->mime_type), - "%s", pos); - if (!pos) - continue; - pos = end + 1; - - end = strchr(pos, ':'); - if (end) - *end = '\0'; - snprintf(icon->filename, sizeof(icon->filename), - "%s", pos); - continue; - } - } - - fclose(f); - - *count = osu_count; - return osu; -} - - -static int osu_connect(struct hs20_osu_client *ctx, const char *bssid, - const char *ssid, const char *ssid2, const char *url, - unsigned int methods, int no_prod_assoc, - const char *osu_nai, const char *osu_nai2) -{ - int id; - const char *ifname = ctx->ifname; - char buf[200]; - struct wpa_ctrl *mon; - int res; - - if (ssid2 && ssid2[0] == '\0') - ssid2 = NULL; - - if (ctx->osu_ssid) { - if (os_strcmp(ssid, ctx->osu_ssid) == 0) { - wpa_printf(MSG_DEBUG, - "Enforced OSU SSID matches ANQP info"); - ssid2 = NULL; - } else if (ssid2 && os_strcmp(ssid2, ctx->osu_ssid) == 0) { - wpa_printf(MSG_DEBUG, - "Enforced OSU SSID matches RSN[OSEN] info"); - ssid = ssid2; - } else { - wpa_printf(MSG_INFO, "Enforced OSU SSID did not match"); - write_summary(ctx, "Enforced OSU SSID did not match"); - return -1; - } - } - - id = add_network(ifname); - if (id < 0) - return -1; - if (set_network_quoted(ifname, id, "ssid", ssid) < 0) - return -1; - if (ssid2) - osu_nai = osu_nai2; - if (osu_nai && os_strlen(osu_nai) > 0) { - char dir[255], fname[300]; - if (getcwd(dir, sizeof(dir)) == NULL) - return -1; - os_snprintf(fname, sizeof(fname), "%s/osu-ca.pem", dir); - - if (ssid2 && set_network_quoted(ifname, id, "ssid", ssid2) < 0) - return -1; - - if (set_network(ifname, id, "proto", "OSEN") < 0 || - set_network(ifname, id, "key_mgmt", "OSEN") < 0 || - set_network(ifname, id, "pairwise", "CCMP") < 0 || - set_network(ifname, id, "group", "GTK_NOT_USED CCMP") < 0 || - set_network(ifname, id, "eap", "WFA-UNAUTH-TLS") < 0 || - set_network(ifname, id, "ocsp", "2") < 0 || - set_network_quoted(ifname, id, "identity", osu_nai) < 0 || - set_network_quoted(ifname, id, "ca_cert", fname) < 0) - return -1; - } else if (ssid2) { - wpa_printf(MSG_INFO, "No OSU_NAI set for RSN[OSEN]"); - write_summary(ctx, "No OSU_NAI set for RSN[OSEN]"); - return -1; - } else { - if (set_network(ifname, id, "key_mgmt", "NONE") < 0) - return -1; - } - - mon = open_wpa_mon(ifname); - if (mon == NULL) - return -1; - - wpa_printf(MSG_INFO, "Associate with OSU SSID"); - write_summary(ctx, "Associate with OSU SSID"); - snprintf(buf, sizeof(buf), "SELECT_NETWORK %d", id); - if (wpa_command(ifname, buf) < 0) - return -1; - - res = get_wpa_cli_event(mon, "CTRL-EVENT-CONNECTED", - buf, sizeof(buf)); - - wpa_ctrl_detach(mon); - wpa_ctrl_close(mon); - - if (res < 0) { - wpa_printf(MSG_INFO, "Could not connect to OSU network"); - write_summary(ctx, "Could not connect to OSU network"); - wpa_printf(MSG_INFO, "Remove OSU network connection"); - snprintf(buf, sizeof(buf), "REMOVE_NETWORK %d", id); - wpa_command(ifname, buf); - return -1; - } - - write_summary(ctx, "Waiting for IP address for subscription registration"); - if (wait_ip_addr(ifname, 15) < 0) { - wpa_printf(MSG_INFO, "Could not get IP address for WLAN - try connection anyway"); - } - - if (no_prod_assoc) { - if (res < 0) - return -1; - wpa_printf(MSG_INFO, "No production connection used for testing purposes"); - write_summary(ctx, "No production connection used for testing purposes"); - return 0; - } - - ctx->no_reconnect = 1; - if (methods & 0x02) { - wpa_printf(MSG_DEBUG, "Calling cmd_prov from osu_connect"); - res = cmd_prov(ctx, url); - } else if (methods & 0x01) { - wpa_printf(MSG_DEBUG, - "Calling cmd_oma_dm_prov from osu_connect"); - res = cmd_oma_dm_prov(ctx, url); - } - - wpa_printf(MSG_INFO, "Remove OSU network connection"); - write_summary(ctx, "Remove OSU network connection"); - snprintf(buf, sizeof(buf), "REMOVE_NETWORK %d", id); - wpa_command(ifname, buf); - - if (res < 0) - return -1; - - wpa_printf(MSG_INFO, "Requesting reconnection with updated configuration"); - write_summary(ctx, "Requesting reconnection with updated configuration"); - if (wpa_command(ctx->ifname, "INTERWORKING_SELECT auto") < 0) { - wpa_printf(MSG_INFO, "Failed to request wpa_supplicant to reconnect"); - write_summary(ctx, "Failed to request wpa_supplicant to reconnect"); - return -1; - } - - return 0; -} - - -static int cmd_osu_select(struct hs20_osu_client *ctx, const char *dir, - int connect, int no_prod_assoc, - const char *friendly_name) -{ - char fname[255]; - FILE *f; - struct osu_data *osu = NULL, *last = NULL; - size_t osu_count = 0, i, j; - int ret; - - write_summary(ctx, "OSU provider selection"); - - if (dir == NULL) { - wpa_printf(MSG_INFO, "Missing dir parameter to osu_select"); - return -1; - } - - snprintf(fname, sizeof(fname), "%s/osu-providers.txt", dir); - osu = parse_osu_providers(fname, &osu_count); - if (osu == NULL) { - wpa_printf(MSG_INFO, "Could not find any OSU providers from %s", - fname); - write_result(ctx, "No OSU providers available"); - return -1; - } - - if (friendly_name) { - for (i = 0; i < osu_count; i++) { - last = &osu[i]; - for (j = 0; j < last->friendly_name_count; j++) { - if (os_strcmp(last->friendly_name[j].text, - friendly_name) == 0) - break; - } - if (j < last->friendly_name_count) - break; - } - if (i == osu_count) { - wpa_printf(MSG_INFO, "Requested operator friendly name '%s' not found in the list of available providers", - friendly_name); - write_summary(ctx, "Requested operator friendly name '%s' not found in the list of available providers", - friendly_name); - free(osu); - return -1; - } - - wpa_printf(MSG_INFO, "OSU Provider selected based on requested operator friendly name '%s'", - friendly_name); - write_summary(ctx, "OSU Provider selected based on requested operator friendly name '%s'", - friendly_name); - ret = i + 1; - goto selected; - } - - snprintf(fname, sizeof(fname), "%s/osu-providers.html", dir); - f = fopen(fname, "w"); - if (f == NULL) { - wpa_printf(MSG_INFO, "Could not open %s", fname); - free(osu); - return -1; - } - - fprintf(f, "<html><head>" - "<meta http-equiv=\"Content-type\" content=\"text/html; " - "charset=utf-8\"<title>Select service operator</title>" - "</head><body><h1>Select service operator</h1>\n"); - - if (osu_count == 0) - fprintf(f, "No online signup available\n"); - - for (i = 0; i < osu_count; i++) { - last = &osu[i]; -#ifdef ANDROID - fprintf(f, "<p>\n" - "<a href=\"http://localhost:12345/osu/%d\">" - "<table><tr><td>", (int) i + 1); -#else /* ANDROID */ - fprintf(f, "<p>\n" - "<a href=\"osu://%d\">" - "<table><tr><td>", (int) i + 1); -#endif /* ANDROID */ - for (j = 0; j < last->icon_count; j++) { - fprintf(f, "<img src=\"osu-icon-%d.%s\">\n", - last->icon[j].id, - strcasecmp(last->icon[j].mime_type, - "image/png") == 0 ? "png" : "icon"); - } - fprintf(f, "<td>"); - for (j = 0; j < last->friendly_name_count; j++) { - fprintf(f, "<small>[%s]</small> %s<br>\n", - last->friendly_name[j].lang, - last->friendly_name[j].text); - } - fprintf(f, "<tr><td colspan=2>"); - for (j = 0; j < last->serv_desc_count; j++) { - fprintf(f, "<small>[%s]</small> %s<br>\n", - last->serv_desc[j].lang, - last->serv_desc[j].text); - } - fprintf(f, "</table></a><br><small>BSSID: %s<br>\n" - "SSID: %s<br>\n", - last->bssid, last->osu_ssid); - if (last->osu_ssid2[0]) - fprintf(f, "SSID2: %s<br>\n", last->osu_ssid2); - if (last->osu_nai[0]) - fprintf(f, "NAI: %s<br>\n", last->osu_nai); - if (last->osu_nai2[0]) - fprintf(f, "NAI2: %s<br>\n", last->osu_nai2); - fprintf(f, "URL: %s<br>\n" - "methods:%s%s<br>\n" - "</small></p>\n", - last->url, - last->methods & 0x01 ? " OMA-DM" : "", - last->methods & 0x02 ? " SOAP-XML-SPP" : ""); - } - - fprintf(f, "</body></html>\n"); - - fclose(f); - - snprintf(fname, sizeof(fname), "file://%s/osu-providers.html", dir); - write_summary(ctx, "Start web browser with OSU provider selection page"); - ret = hs20_web_browser(fname, 0); - -selected: - if (ret > 0 && (size_t) ret <= osu_count) { - char *data; - size_t data_len; - - wpa_printf(MSG_INFO, "Selected OSU id=%d", ret); - last = &osu[ret - 1]; - ret = 0; - wpa_printf(MSG_INFO, "BSSID: %s", last->bssid); - wpa_printf(MSG_INFO, "SSID: %s", last->osu_ssid); - if (last->osu_ssid2[0]) - wpa_printf(MSG_INFO, "SSID2: %s", last->osu_ssid2); - wpa_printf(MSG_INFO, "URL: %s", last->url); - write_summary(ctx, "Selected OSU provider id=%d BSSID=%s SSID=%s URL=%s", - ret, last->bssid, last->osu_ssid, last->url); - - ctx->friendly_name_count = last->friendly_name_count; - for (j = 0; j < last->friendly_name_count; j++) { - wpa_printf(MSG_INFO, "FRIENDLY_NAME: [%s]%s", - last->friendly_name[j].lang, - last->friendly_name[j].text); - os_strlcpy(ctx->friendly_name[j].lang, - last->friendly_name[j].lang, - sizeof(ctx->friendly_name[j].lang)); - os_strlcpy(ctx->friendly_name[j].text, - last->friendly_name[j].text, - sizeof(ctx->friendly_name[j].text)); - } - - ctx->icon_count = last->icon_count; - for (j = 0; j < last->icon_count; j++) { - char fname[256]; - - os_snprintf(fname, sizeof(fname), "%s/osu-icon-%d.%s", - dir, last->icon[j].id, - strcasecmp(last->icon[j].mime_type, - "image/png") == 0 ? - "png" : "icon"); - wpa_printf(MSG_INFO, "ICON: %s (%s)", - fname, last->icon[j].filename); - os_strlcpy(ctx->icon_filename[j], - last->icon[j].filename, - sizeof(ctx->icon_filename[j])); - - data = os_readfile(fname, &data_len); - if (data) { - sha256_vector(1, (const u8 **) &data, &data_len, - ctx->icon_hash[j]); - os_free(data); - } - } - - if (connect == 2) { - if (last->methods & 0x02) { - wpa_printf(MSG_DEBUG, - "Calling cmd_prov from cmd_osu_select"); - ret = cmd_prov(ctx, last->url); - } else if (last->methods & 0x01) { - wpa_printf(MSG_DEBUG, - "Calling cmd_oma_dm_prov from cmd_osu_select"); - ret = cmd_oma_dm_prov(ctx, last->url); - } else { - wpa_printf(MSG_DEBUG, - "No supported OSU provisioning method"); - ret = -1; - } - } else if (connect) { - ret = osu_connect(ctx, last->bssid, last->osu_ssid, - last->osu_ssid2, - last->url, last->methods, - no_prod_assoc, last->osu_nai, - last->osu_nai2); - } - } else - ret = -1; - - free(osu); - - return ret; -} - - -static int cmd_signup(struct hs20_osu_client *ctx, int no_prod_assoc, - const char *friendly_name) -{ - char dir[255]; - char fname[300], buf[400]; - struct wpa_ctrl *mon; - const char *ifname; - int res; - - ifname = ctx->ifname; - - if (getcwd(dir, sizeof(dir)) == NULL) - return -1; - - snprintf(fname, sizeof(fname), "%s/osu-info", dir); - if (mkdir(fname, S_IRWXU | S_IRWXG | S_IROTH | S_IXOTH) < 0 && - errno != EEXIST) { - wpa_printf(MSG_INFO, "mkdir(%s) failed: %s", - fname, strerror(errno)); - return -1; - } - - android_update_permission(fname, S_IRWXU | S_IRWXG | S_IROTH | S_IXOTH); - - snprintf(buf, sizeof(buf), "SET osu_dir %s", fname); - if (wpa_command(ifname, buf) < 0) { - wpa_printf(MSG_INFO, "Failed to configure osu_dir to wpa_supplicant"); - return -1; - } - - mon = open_wpa_mon(ifname); - if (mon == NULL) - return -1; - - wpa_printf(MSG_INFO, "Starting OSU fetch"); - write_summary(ctx, "Starting OSU provider information fetch"); - if (wpa_command(ifname, "FETCH_OSU") < 0) { - wpa_printf(MSG_INFO, "Could not start OSU fetch"); - wpa_ctrl_detach(mon); - wpa_ctrl_close(mon); - return -1; - } - res = get_wpa_cli_event(mon, "OSU provider fetch completed", - buf, sizeof(buf)); - - wpa_ctrl_detach(mon); - wpa_ctrl_close(mon); - - if (res < 0) { - wpa_printf(MSG_INFO, "OSU fetch did not complete"); - write_summary(ctx, "OSU fetch did not complete"); - return -1; - } - wpa_printf(MSG_INFO, "OSU provider fetch completed"); - - return cmd_osu_select(ctx, fname, 1, no_prod_assoc, friendly_name); -} - - -static int cmd_sub_rem(struct hs20_osu_client *ctx, const char *address, - const char *pps_fname, const char *ca_fname) -{ - xml_node_t *pps, *node; - char pps_fname_buf[300]; - char ca_fname_buf[200]; - char *cred_username = NULL; - char *cred_password = NULL; - char *sub_rem_uri = NULL; - char client_cert_buf[200]; - char *client_cert = NULL; - char client_key_buf[200]; - char *client_key = NULL; - int spp; - - wpa_printf(MSG_INFO, "Subscription remediation requested with Server URL: %s", - address); - - if (!pps_fname) { - char buf[256]; - wpa_printf(MSG_INFO, "Determining PPS file based on Home SP information"); - if (os_strncmp(address, "fqdn=", 5) == 0) { - wpa_printf(MSG_INFO, "Use requested FQDN from command line"); - os_snprintf(buf, sizeof(buf), "%s", address + 5); - address = NULL; - } else if (get_wpa_status(ctx->ifname, "provisioning_sp", buf, - sizeof(buf)) < 0) { - wpa_printf(MSG_INFO, "Could not get provisioning Home SP FQDN from wpa_supplicant"); - return -1; - } - os_free(ctx->fqdn); - ctx->fqdn = os_strdup(buf); - if (ctx->fqdn == NULL) - return -1; - wpa_printf(MSG_INFO, "Home SP FQDN for current credential: %s", - buf); - os_snprintf(pps_fname_buf, sizeof(pps_fname_buf), - "SP/%s/pps.xml", ctx->fqdn); - pps_fname = pps_fname_buf; - - os_snprintf(ca_fname_buf, sizeof(ca_fname_buf), "SP/%s/ca.pem", - ctx->fqdn); - ca_fname = ca_fname_buf; - } - - if (!os_file_exists(pps_fname)) { - wpa_printf(MSG_INFO, "PPS file '%s' does not exist or is not accessible", - pps_fname); - return -1; - } - wpa_printf(MSG_INFO, "Using PPS file: %s", pps_fname); - - if (ca_fname && !os_file_exists(ca_fname)) { - wpa_printf(MSG_INFO, "CA file '%s' does not exist or is not accessible", - ca_fname); - return -1; - } - wpa_printf(MSG_INFO, "Using server trust root: %s", ca_fname); - ctx->ca_fname = ca_fname; - - pps = node_from_file(ctx->xml, pps_fname); - if (pps == NULL) { - wpa_printf(MSG_INFO, "Could not read PPS MO"); - return -1; - } - - if (!ctx->fqdn) { - char *tmp; - node = get_child_node(ctx->xml, pps, "HomeSP/FQDN"); - if (node == NULL) { - wpa_printf(MSG_INFO, "No HomeSP/FQDN found from PPS"); - return -1; - } - tmp = xml_node_get_text(ctx->xml, node); - if (tmp == NULL) { - wpa_printf(MSG_INFO, "No HomeSP/FQDN text found from PPS"); - return -1; - } - ctx->fqdn = os_strdup(tmp); - xml_node_get_text_free(ctx->xml, tmp); - if (!ctx->fqdn) { - wpa_printf(MSG_INFO, "No FQDN known"); - return -1; - } - } - - node = get_child_node(ctx->xml, pps, - "SubscriptionUpdate/UpdateMethod"); - if (node) { - char *tmp; - tmp = xml_node_get_text(ctx->xml, node); - if (tmp && os_strcasecmp(tmp, "OMA-DM-ClientInitiated") == 0) - spp = 0; - else - spp = 1; - } else { - wpa_printf(MSG_INFO, "No UpdateMethod specified - assume SPP"); - spp = 1; - } - - get_user_pw(ctx, pps, "SubscriptionUpdate/UsernamePassword", - &cred_username, &cred_password); - if (cred_username) - wpa_printf(MSG_INFO, "Using username: %s", cred_username); - if (cred_password) - wpa_printf(MSG_DEBUG, "Using password: %s", cred_password); - - if (cred_username == NULL && cred_password == NULL && - get_child_node(ctx->xml, pps, "Credential/DigitalCertificate")) { - wpa_printf(MSG_INFO, "Using client certificate"); - os_snprintf(client_cert_buf, sizeof(client_cert_buf), - "SP/%s/client-cert.pem", ctx->fqdn); - client_cert = client_cert_buf; - os_snprintf(client_key_buf, sizeof(client_key_buf), - "SP/%s/client-key.pem", ctx->fqdn); - client_key = client_key_buf; - ctx->client_cert_present = 1; - } - - node = get_child_node(ctx->xml, pps, "SubscriptionUpdate/URI"); - if (node) { - sub_rem_uri = xml_node_get_text(ctx->xml, node); - if (sub_rem_uri && - (!address || os_strcmp(address, sub_rem_uri) != 0)) { - wpa_printf(MSG_INFO, "Override sub rem URI based on PPS: %s", - sub_rem_uri); - address = sub_rem_uri; - } - } - if (!address) { - wpa_printf(MSG_INFO, "Server URL not known"); - return -1; - } - - write_summary(ctx, "Wait for IP address for subscriptiom remediation"); - wpa_printf(MSG_INFO, "Wait for IP address before starting subscription remediation"); - - if (wait_ip_addr(ctx->ifname, 15) < 0) { - wpa_printf(MSG_INFO, "Could not get IP address for WLAN - try connection anyway"); - } - - if (spp) - spp_sub_rem(ctx, address, pps_fname, - client_cert, client_key, - cred_username, cred_password, pps); - else - oma_dm_sub_rem(ctx, address, pps_fname, - client_cert, client_key, - cred_username, cred_password, pps); - - xml_node_get_text_free(ctx->xml, sub_rem_uri); - xml_node_get_text_free(ctx->xml, cred_username); - str_clear_free(cred_password); - xml_node_free(ctx->xml, pps); - return 0; -} - - -static int cmd_pol_upd(struct hs20_osu_client *ctx, const char *address, - const char *pps_fname, const char *ca_fname) -{ - xml_node_t *pps; - xml_node_t *node; - char pps_fname_buf[300]; - char ca_fname_buf[200]; - char *uri = NULL; - char *cred_username = NULL; - char *cred_password = NULL; - char client_cert_buf[200]; - char *client_cert = NULL; - char client_key_buf[200]; - char *client_key = NULL; - int spp; - - wpa_printf(MSG_INFO, "Policy update requested"); - - if (!pps_fname) { - char buf[256]; - int res; - - wpa_printf(MSG_INFO, "Determining PPS file based on Home SP information"); - if (address && os_strncmp(address, "fqdn=", 5) == 0) { - wpa_printf(MSG_INFO, "Use requested FQDN from command line"); - os_snprintf(buf, sizeof(buf), "%s", address + 5); - address = NULL; - } else if (get_wpa_status(ctx->ifname, "provisioning_sp", buf, - sizeof(buf)) < 0) { - wpa_printf(MSG_INFO, "Could not get provisioning Home SP FQDN from wpa_supplicant"); - return -1; - } - os_free(ctx->fqdn); - ctx->fqdn = os_strdup(buf); - if (ctx->fqdn == NULL) - return -1; - wpa_printf(MSG_INFO, "Home SP FQDN for current credential: %s", - buf); - os_snprintf(pps_fname_buf, sizeof(pps_fname_buf), - "SP/%s/pps.xml", ctx->fqdn); - pps_fname = pps_fname_buf; - - res = os_snprintf(ca_fname_buf, sizeof(ca_fname_buf), - "SP/%s/ca.pem", buf); - if (os_snprintf_error(sizeof(ca_fname_buf), res)) { - os_free(ctx->fqdn); - ctx->fqdn = NULL; - return -1; - } - ca_fname = ca_fname_buf; - } - - if (!os_file_exists(pps_fname)) { - wpa_printf(MSG_INFO, "PPS file '%s' does not exist or is not accessible", - pps_fname); - return -1; - } - wpa_printf(MSG_INFO, "Using PPS file: %s", pps_fname); - - if (ca_fname && !os_file_exists(ca_fname)) { - wpa_printf(MSG_INFO, "CA file '%s' does not exist or is not accessible", - ca_fname); - return -1; - } - wpa_printf(MSG_INFO, "Using server trust root: %s", ca_fname); - ctx->ca_fname = ca_fname; - - pps = node_from_file(ctx->xml, pps_fname); - if (pps == NULL) { - wpa_printf(MSG_INFO, "Could not read PPS MO"); - return -1; - } - - if (!ctx->fqdn) { - char *tmp; - node = get_child_node(ctx->xml, pps, "HomeSP/FQDN"); - if (node == NULL) { - wpa_printf(MSG_INFO, "No HomeSP/FQDN found from PPS"); - return -1; - } - tmp = xml_node_get_text(ctx->xml, node); - if (tmp == NULL) { - wpa_printf(MSG_INFO, "No HomeSP/FQDN text found from PPS"); - return -1; - } - ctx->fqdn = os_strdup(tmp); - xml_node_get_text_free(ctx->xml, tmp); - if (!ctx->fqdn) { - wpa_printf(MSG_INFO, "No FQDN known"); - return -1; - } - } - - node = get_child_node(ctx->xml, pps, - "Policy/PolicyUpdate/UpdateMethod"); - if (node) { - char *tmp; - tmp = xml_node_get_text(ctx->xml, node); - if (tmp && os_strcasecmp(tmp, "OMA-DM-ClientInitiated") == 0) - spp = 0; - else - spp = 1; - } else { - wpa_printf(MSG_INFO, "No UpdateMethod specified - assume SPP"); - spp = 1; - } - - get_user_pw(ctx, pps, "Policy/PolicyUpdate/UsernamePassword", - &cred_username, &cred_password); - if (cred_username) - wpa_printf(MSG_INFO, "Using username: %s", cred_username); - if (cred_password) - wpa_printf(MSG_DEBUG, "Using password: %s", cred_password); - - if (cred_username == NULL && cred_password == NULL && - get_child_node(ctx->xml, pps, "Credential/DigitalCertificate")) { - wpa_printf(MSG_INFO, "Using client certificate"); - os_snprintf(client_cert_buf, sizeof(client_cert_buf), - "SP/%s/client-cert.pem", ctx->fqdn); - client_cert = client_cert_buf; - os_snprintf(client_key_buf, sizeof(client_key_buf), - "SP/%s/client-key.pem", ctx->fqdn); - client_key = client_key_buf; - } - - if (!address) { - node = get_child_node(ctx->xml, pps, "Policy/PolicyUpdate/URI"); - if (node) { - uri = xml_node_get_text(ctx->xml, node); - wpa_printf(MSG_INFO, "URI based on PPS: %s", uri); - address = uri; - } - } - if (!address) { - wpa_printf(MSG_INFO, "Server URL not known"); - return -1; - } - - if (spp) - spp_pol_upd(ctx, address, pps_fname, - client_cert, client_key, - cred_username, cred_password, pps); - else - oma_dm_pol_upd(ctx, address, pps_fname, - client_cert, client_key, - cred_username, cred_password, pps); - - xml_node_get_text_free(ctx->xml, uri); - xml_node_get_text_free(ctx->xml, cred_username); - str_clear_free(cred_password); - xml_node_free(ctx->xml, pps); - - return 0; -} - - -static char * get_hostname(const char *url) -{ - const char *pos, *end, *end2; - char *ret; - - if (url == NULL) - return NULL; - - pos = os_strchr(url, '/'); - if (pos == NULL) - return NULL; - pos++; - if (*pos != '/') - return NULL; - pos++; - - end = os_strchr(pos, '/'); - end2 = os_strchr(pos, ':'); - if ((end && end2 && end2 < end) || (!end && end2)) - end = end2; - if (end) - end--; - else { - end = pos; - while (*end) - end++; - if (end > pos) - end--; - } - - ret = os_malloc(end - pos + 2); - if (ret == NULL) - return NULL; - - os_memcpy(ret, pos, end - pos + 1); - ret[end - pos + 1] = '\0'; - - return ret; -} - - -static int osu_cert_cb(void *_ctx, struct http_cert *cert) -{ - struct hs20_osu_client *ctx = _ctx; - size_t i, j; - int found; - char *host = NULL; - - wpa_printf(MSG_INFO, "osu_cert_cb(osu_cert_validation=%d, url=%s)", - !ctx->no_osu_cert_validation, ctx->server_url); - - host = get_hostname(ctx->server_url); - - for (i = 0; i < ctx->server_dnsname_count; i++) - os_free(ctx->server_dnsname[i]); - os_free(ctx->server_dnsname); - ctx->server_dnsname = os_calloc(cert->num_dnsname, sizeof(char *)); - ctx->server_dnsname_count = 0; - - found = 0; - for (i = 0; i < cert->num_dnsname; i++) { - if (ctx->server_dnsname) { - ctx->server_dnsname[ctx->server_dnsname_count] = - os_strdup(cert->dnsname[i]); - if (ctx->server_dnsname[ctx->server_dnsname_count]) - ctx->server_dnsname_count++; - } - if (host && os_strcasecmp(host, cert->dnsname[i]) == 0) - found = 1; - wpa_printf(MSG_INFO, "dNSName '%s'", cert->dnsname[i]); - } - - if (host && !found) { - wpa_printf(MSG_INFO, "Server name from URL (%s) did not match any dNSName - abort connection", - host); - write_result(ctx, "Server name from URL (%s) did not match any dNSName - abort connection", - host); - os_free(host); - return -1; - } - - os_free(host); - - for (i = 0; i < cert->num_othername; i++) { - if (os_strcmp(cert->othername[i].oid, - "1.3.6.1.4.1.40808.1.1.1") == 0) { - wpa_hexdump_ascii(MSG_INFO, - "id-wfa-hotspot-friendlyName", - cert->othername[i].data, - cert->othername[i].len); - } - } - - for (j = 0; !ctx->no_osu_cert_validation && - j < ctx->friendly_name_count; j++) { - int found = 0; - for (i = 0; i < cert->num_othername; i++) { - if (os_strcmp(cert->othername[i].oid, - "1.3.6.1.4.1.40808.1.1.1") != 0) - continue; - if (cert->othername[i].len < 3) - continue; - if (os_strncasecmp((char *) cert->othername[i].data, - ctx->friendly_name[j].lang, 3) != 0) - continue; - if (os_strncmp((char *) cert->othername[i].data + 3, - ctx->friendly_name[j].text, - cert->othername[i].len - 3) == 0) { - found = 1; - break; - } - } - - if (!found) { - wpa_printf(MSG_INFO, "No friendly name match found for '[%s]%s'", - ctx->friendly_name[j].lang, - ctx->friendly_name[j].text); - write_result(ctx, "No friendly name match found for '[%s]%s'", - ctx->friendly_name[j].lang, - ctx->friendly_name[j].text); - return -1; - } - } - - for (i = 0; i < cert->num_logo; i++) { - struct http_logo *logo = &cert->logo[i]; - - wpa_printf(MSG_INFO, "logo hash alg %s uri '%s'", - logo->alg_oid, logo->uri); - wpa_hexdump_ascii(MSG_INFO, "hashValue", - logo->hash, logo->hash_len); - } - - for (j = 0; !ctx->no_osu_cert_validation && j < ctx->icon_count; j++) { - int found = 0; - char *name = ctx->icon_filename[j]; - size_t name_len = os_strlen(name); - - wpa_printf(MSG_INFO, - "[%zu] Looking for icon file name '%s' match", - j, name); - for (i = 0; i < cert->num_logo; i++) { - struct http_logo *logo = &cert->logo[i]; - size_t uri_len = os_strlen(logo->uri); - char *pos; - - wpa_printf(MSG_INFO, - "[%zu] Comparing to '%s' uri_len=%d name_len=%d", - i, logo->uri, (int) uri_len, (int) name_len); - if (uri_len < 1 + name_len) { - wpa_printf(MSG_INFO, "URI Length is too short"); - continue; - } - pos = &logo->uri[uri_len - name_len - 1]; - if (*pos != '/') - continue; - pos++; - if (os_strcmp(pos, name) == 0) { - found = 1; - break; - } - } - - if (!found) { - wpa_printf(MSG_INFO, "No icon filename match found for '%s'", - name); - write_result(ctx, - "No icon filename match found for '%s'", - name); - return -1; - } - } - - for (j = 0; !ctx->no_osu_cert_validation && j < ctx->icon_count; j++) { - int found = 0; - - for (i = 0; i < cert->num_logo; i++) { - struct http_logo *logo = &cert->logo[i]; - - if (logo->hash_len != 32) { - wpa_printf(MSG_INFO, - "[%zu][%zu] Icon hash length invalid (should be 32): %d", - j, i, (int) logo->hash_len); - continue; - } - if (os_memcmp(logo->hash, ctx->icon_hash[j], 32) == 0) { - found = 1; - break; - } - - wpa_printf(MSG_DEBUG, - "[%zu][%zu] Icon hash did not match", j, i); - wpa_hexdump_ascii(MSG_DEBUG, "logo->hash", - logo->hash, 32); - wpa_hexdump_ascii(MSG_DEBUG, "ctx->icon_hash[j]", - ctx->icon_hash[j], 32); - } - - if (!found) { - wpa_printf(MSG_INFO, - "No icon hash match (by hash) found"); - write_result(ctx, - "No icon hash match (by hash) found"); - return -1; - } - } - - return 0; -} - - -static int init_ctx(struct hs20_osu_client *ctx) -{ - xml_node_t *devinfo, *devid; - - os_memset(ctx, 0, sizeof(*ctx)); - ctx->ifname = "wlan0"; - ctx->xml = xml_node_init_ctx(ctx, NULL); - if (ctx->xml == NULL) - return -1; - - devinfo = node_from_file(ctx->xml, "devinfo.xml"); - if (devinfo) { - devid = get_node(ctx->xml, devinfo, "DevId"); - if (devid) { - char *tmp = xml_node_get_text(ctx->xml, devid); - - if (tmp) { - ctx->devid = os_strdup(tmp); - xml_node_get_text_free(ctx->xml, tmp); - } - } - xml_node_free(ctx->xml, devinfo); - } - - ctx->http = http_init_ctx(ctx, ctx->xml); - if (ctx->http == NULL) { - xml_node_deinit_ctx(ctx->xml); - return -1; - } - http_ocsp_set(ctx->http, 2); - http_set_cert_cb(ctx->http, osu_cert_cb, ctx); - - return 0; -} - - -static void deinit_ctx(struct hs20_osu_client *ctx) -{ - size_t i; - - http_deinit_ctx(ctx->http); - xml_node_deinit_ctx(ctx->xml); - os_free(ctx->fqdn); - os_free(ctx->server_url); - os_free(ctx->devid); - - for (i = 0; i < ctx->server_dnsname_count; i++) - os_free(ctx->server_dnsname[i]); - os_free(ctx->server_dnsname); -} - - -static void check_workarounds(struct hs20_osu_client *ctx) -{ - FILE *f; - char buf[100]; - unsigned long int val = 0; - - f = fopen("hs20-osu-client.workarounds", "r"); - if (f == NULL) - return; - - if (fgets(buf, sizeof(buf), f)) - val = strtoul(buf, NULL, 16); - - fclose(f); - - if (val) { - wpa_printf(MSG_INFO, "Workarounds enabled: 0x%lx", val); - ctx->workarounds = val; - if (ctx->workarounds & WORKAROUND_OCSP_OPTIONAL) - http_ocsp_set(ctx->http, 1); - } -} - - -static void usage(void) -{ - printf("usage: hs20-osu-client [-dddqqKtT] [-S<station ifname>] \\\n" - " [-w<wpa_supplicant ctrl_iface dir>] " - "[-r<result file>] [-f<debug file>] \\\n" - " [-s<summary file>] \\\n" - " [-x<spp.xsd file name>] \\\n" - " <command> [arguments..]\n" - "commands:\n" - "- to_tnds <XML MO> <XML MO in TNDS format> [URN]\n" - "- to_tnds2 <XML MO> <XML MO in TNDS format (Path) " - "[URN]>\n" - "- from_tnds <XML MO in TNDS format> <XML MO>\n" - "- set_pps <PerProviderSubscription XML file name>\n" - "- get_fqdn <PerProviderSubscription XML file name>\n" - "- pol_upd [Server URL] [PPS] [CA cert]\n" - "- sub_rem <Server URL> [PPS] [CA cert]\n" - "- prov <Server URL> [CA cert]\n" - "- oma_dm_prov <Server URL> [CA cert]\n" - "- sim_prov <Server URL> [CA cert]\n" - "- oma_dm_sim_prov <Server URL> [CA cert]\n" - "- signup [CA cert]\n" - "- dl_osu_ca <PPS> <CA file>\n" - "- dl_polupd_ca <PPS> <CA file>\n" - "- dl_aaa_ca <PPS> <CA file>\n" - "- browser <URL>\n" - "- parse_cert <X.509 certificate (DER)>\n" - "- osu_select <OSU info directory> [CA cert]\n"); -} - - -int main(int argc, char *argv[]) -{ - struct hs20_osu_client ctx; - int c; - int ret = 0; - int no_prod_assoc = 0; - const char *friendly_name = NULL; - const char *wpa_debug_file_path = NULL; - extern char *wpas_ctrl_path; - extern int wpa_debug_level; - extern int wpa_debug_show_keys; - extern int wpa_debug_timestamp; - - if (init_ctx(&ctx) < 0) - return -1; - - for (;;) { - c = getopt(argc, argv, "df:hKNo:O:qr:s:S:tTw:x:"); - if (c < 0) - break; - switch (c) { - case 'd': - if (wpa_debug_level > 0) - wpa_debug_level--; - break; - case 'f': - wpa_debug_file_path = optarg; - break; - case 'K': - wpa_debug_show_keys++; - break; - case 'N': - no_prod_assoc = 1; - break; - case 'o': - ctx.osu_ssid = optarg; - break; - case 'O': - friendly_name = optarg; - break; - case 'q': - wpa_debug_level++; - break; - case 'r': - ctx.result_file = optarg; - break; - case 's': - ctx.summary_file = optarg; - break; - case 'S': - ctx.ifname = optarg; - break; - case 't': - wpa_debug_timestamp++; - break; - case 'T': - ctx.ignore_tls = 1; - break; - case 'w': - wpas_ctrl_path = optarg; - break; - case 'x': - spp_xsd_fname = optarg; - break; - case 'h': - default: - usage(); - exit(0); - break; - } - } - - if (argc - optind < 1) { - usage(); - exit(0); - } - - wpa_debug_open_file(wpa_debug_file_path); - -#ifdef __linux__ - setlinebuf(stdout); -#endif /* __linux__ */ - - if (ctx.result_file) - unlink(ctx.result_file); - wpa_printf(MSG_DEBUG, "===[hs20-osu-client START - command: %s ]======" - "================", argv[optind]); - check_workarounds(&ctx); - - if (strcmp(argv[optind], "to_tnds") == 0) { - if (argc - optind < 2) { - usage(); - exit(0); - } - cmd_to_tnds(&ctx, argv[optind + 1], argv[optind + 2], - argc > optind + 3 ? argv[optind + 3] : NULL, - 0); - } else if (strcmp(argv[optind], "to_tnds2") == 0) { - if (argc - optind < 2) { - usage(); - exit(0); - } - cmd_to_tnds(&ctx, argv[optind + 1], argv[optind + 2], - argc > optind + 3 ? argv[optind + 3] : NULL, - 1); - } else if (strcmp(argv[optind], "from_tnds") == 0) { - if (argc - optind < 2) { - usage(); - exit(0); - } - cmd_from_tnds(&ctx, argv[optind + 1], argv[optind + 2]); - } else if (strcmp(argv[optind], "sub_rem") == 0) { - if (argc - optind < 2) { - usage(); - exit(0); - } - ret = cmd_sub_rem(&ctx, argv[optind + 1], - argc > optind + 2 ? argv[optind + 2] : NULL, - argc > optind + 3 ? argv[optind + 3] : NULL); - } else if (strcmp(argv[optind], "pol_upd") == 0) { - ret = cmd_pol_upd(&ctx, - argc > optind + 1 ? argv[optind + 1] : NULL, - argc > optind + 2 ? argv[optind + 2] : NULL, - argc > optind + 3 ? argv[optind + 3] : NULL); - } else if (strcmp(argv[optind], "prov") == 0) { - if (argc - optind < 2) { - usage(); - exit(0); - } - ctx.ca_fname = argv[optind + 2]; - wpa_printf(MSG_DEBUG, "Calling cmd_prov from main"); - cmd_prov(&ctx, argv[optind + 1]); - } else if (strcmp(argv[optind], "sim_prov") == 0) { - if (argc - optind < 2) { - usage(); - exit(0); - } - ctx.ca_fname = argv[optind + 2]; - cmd_sim_prov(&ctx, argv[optind + 1]); - } else if (strcmp(argv[optind], "dl_osu_ca") == 0) { - if (argc - optind < 2) { - usage(); - exit(0); - } - cmd_dl_osu_ca(&ctx, argv[optind + 1], argv[optind + 2]); - } else if (strcmp(argv[optind], "dl_polupd_ca") == 0) { - if (argc - optind < 2) { - usage(); - exit(0); - } - cmd_dl_polupd_ca(&ctx, argv[optind + 1], argv[optind + 2]); - } else if (strcmp(argv[optind], "dl_aaa_ca") == 0) { - if (argc - optind < 2) { - usage(); - exit(0); - } - cmd_dl_aaa_ca(&ctx, argv[optind + 1], argv[optind + 2]); - } else if (strcmp(argv[optind], "osu_select") == 0) { - if (argc - optind < 2) { - usage(); - exit(0); - } - ctx.ca_fname = argc > optind + 2 ? argv[optind + 2] : NULL; - cmd_osu_select(&ctx, argv[optind + 1], 2, 1, NULL); - } else if (strcmp(argv[optind], "signup") == 0) { - ctx.ca_fname = argc > optind + 1 ? argv[optind + 1] : NULL; - ret = cmd_signup(&ctx, no_prod_assoc, friendly_name); - } else if (strcmp(argv[optind], "set_pps") == 0) { - if (argc - optind < 2) { - usage(); - exit(0); - } - cmd_set_pps(&ctx, argv[optind + 1]); - } else if (strcmp(argv[optind], "get_fqdn") == 0) { - if (argc - optind < 1) { - usage(); - exit(0); - } - ret = cmd_get_fqdn(&ctx, argv[optind + 1]); - } else if (strcmp(argv[optind], "oma_dm_prov") == 0) { - if (argc - optind < 2) { - usage(); - exit(0); - } - ctx.ca_fname = argv[optind + 2]; - cmd_oma_dm_prov(&ctx, argv[optind + 1]); - } else if (strcmp(argv[optind], "oma_dm_sim_prov") == 0) { - if (argc - optind < 2) { - usage(); - exit(0); - } - ctx.ca_fname = argv[optind + 2]; - if (cmd_oma_dm_sim_prov(&ctx, argv[optind + 1]) < 0) { - write_summary(&ctx, "Failed to complete OMA DM SIM provisioning"); - return -1; - } - } else if (strcmp(argv[optind], "oma_dm_add") == 0) { - if (argc - optind < 2) { - usage(); - exit(0); - } - cmd_oma_dm_add(&ctx, argv[optind + 1], argv[optind + 2]); - } else if (strcmp(argv[optind], "oma_dm_replace") == 0) { - if (argc - optind < 2) { - usage(); - exit(0); - } - cmd_oma_dm_replace(&ctx, argv[optind + 1], argv[optind + 2]); - } else if (strcmp(argv[optind], "est_csr") == 0) { - if (argc - optind < 2) { - usage(); - exit(0); - } - mkdir("Cert", S_IRWXU); - est_build_csr(&ctx, argv[optind + 1]); - } else if (strcmp(argv[optind], "browser") == 0) { - int ret; - - if (argc - optind < 2) { - usage(); - exit(0); - } - - wpa_printf(MSG_INFO, "Launch web browser to URL %s", - argv[optind + 1]); - ret = hs20_web_browser(argv[optind + 1], ctx.ignore_tls); - wpa_printf(MSG_INFO, "Web browser result: %d", ret); - } else if (strcmp(argv[optind], "parse_cert") == 0) { - if (argc - optind < 2) { - usage(); - exit(0); - } - - wpa_debug_level = MSG_MSGDUMP; - http_parse_x509_certificate(ctx.http, argv[optind + 1]); - wpa_debug_level = MSG_INFO; - } else { - wpa_printf(MSG_INFO, "Unknown command '%s'", argv[optind]); - } - - deinit_ctx(&ctx); - wpa_printf(MSG_DEBUG, - "===[hs20-osu-client END ]======================"); - - wpa_debug_close_file(); - - return ret; -} diff --git a/hs20/client/osu_client.h b/hs20/client/osu_client.h deleted file mode 100644 index 9b45b03febe2..000000000000 --- a/hs20/client/osu_client.h +++ /dev/null @@ -1,121 +0,0 @@ -/* - * Hotspot 2.0 - OSU client - * Copyright (c) 2013-2014, Qualcomm Atheros, Inc. - * - * This software may be distributed under the terms of the BSD license. - * See README for more details. - */ - -#ifndef OSU_CLIENT_H -#define OSU_CLIENT_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_HS20_DEVDETAIL_EXT "urn:wfa:mo-ext:hotspot2dot0-devdetail-ext:1.0" -#define URN_HS20_PPS "urn:wfa:mo:hotspot2dot0-perprovidersubscription:1.0" - - -#define MAX_OSU_VALS 10 - -struct osu_lang_text { - char lang[4]; - char text[253]; -}; - -struct hs20_osu_client { - struct xml_node_ctx *xml; - struct http_ctx *http; - int no_reconnect; - char pps_fname[300]; - char *devid; - const char *result_file; - const char *summary_file; - const char *ifname; - const char *ca_fname; - int no_osu_cert_validation; /* for EST operations */ - char *fqdn; - char *server_url; - struct osu_lang_text friendly_name[MAX_OSU_VALS]; - size_t friendly_name_count; - size_t icon_count; - char icon_filename[MAX_OSU_VALS][256]; - u8 icon_hash[MAX_OSU_VALS][32]; - int pps_cred_set; - int pps_updated; - int client_cert_present; - char **server_dnsname; - size_t server_dnsname_count; - const char *osu_ssid; /* Enforced OSU_SSID for testing purposes */ -#define WORKAROUND_OCSP_OPTIONAL 0x00000001 - unsigned long int workarounds; - int ignore_tls; /* whether to ignore TLS validation issues with HTTPS - * server certificate */ -}; - - -/* osu_client.c */ - -void write_result(struct hs20_osu_client *ctx, const char *fmt, ...) - __attribute__ ((format (printf, 2, 3))); -void write_summary(struct hs20_osu_client *ctx, const char *fmt, ...) - __attribute__ ((format (printf, 2, 3))); - -void debug_dump_node(struct hs20_osu_client *ctx, const char *title, - xml_node_t *node); -int osu_get_certificate(struct hs20_osu_client *ctx, xml_node_t *getcert); -int hs20_add_pps_mo(struct hs20_osu_client *ctx, const char *uri, - xml_node_t *add_mo, char *fname, size_t fname_len); -void get_user_pw(struct hs20_osu_client *ctx, xml_node_t *pps, - const char *alt_loc, char **user, char **pw); -int update_pps_file(struct hs20_osu_client *ctx, const char *pps_fname, - xml_node_t *pps); -void cmd_set_pps(struct hs20_osu_client *ctx, const char *pps_fname); - - -/* spp_client.c */ - -void spp_sub_rem(struct hs20_osu_client *ctx, const char *address, - const char *pps_fname, - const char *client_cert, const char *client_key, - const char *cred_username, const char *cred_password, - xml_node_t *pps); -void spp_pol_upd(struct hs20_osu_client *ctx, const char *address, - const char *pps_fname, - const char *client_cert, const char *client_key, - const char *cred_username, const char *cred_password, - xml_node_t *pps); -int cmd_prov(struct hs20_osu_client *ctx, const char *url); -int cmd_sim_prov(struct hs20_osu_client *ctx, const char *url); - - -/* oma_dm_client.c */ - -int cmd_oma_dm_prov(struct hs20_osu_client *ctx, const char *url); -int cmd_oma_dm_sim_prov(struct hs20_osu_client *ctx, const char *url); -void oma_dm_sub_rem(struct hs20_osu_client *ctx, const char *address, - const char *pps_fname, - const char *client_cert, const char *client_key, - const char *cred_username, const char *cred_password, - xml_node_t *pps); -void oma_dm_pol_upd(struct hs20_osu_client *ctx, const char *address, - const char *pps_fname, - const char *client_cert, const char *client_key, - const char *cred_username, const char *cred_password, - xml_node_t *pps); -void cmd_oma_dm_sub_rem(struct hs20_osu_client *ctx, const char *address, - const char *pps_fname); -void cmd_oma_dm_add(struct hs20_osu_client *ctx, const char *pps_fname, - const char *add_fname); -void cmd_oma_dm_replace(struct hs20_osu_client *ctx, const char *pps_fname, - const char *replace_fname); - -/* est.c */ - -int est_load_cacerts(struct hs20_osu_client *ctx, const char *url); -int est_build_csr(struct hs20_osu_client *ctx, const char *url); -int est_simple_enroll(struct hs20_osu_client *ctx, const char *url, - const char *user, const char *pw); - -#endif /* OSU_CLIENT_H */ diff --git a/hs20/client/spp_client.c b/hs20/client/spp_client.c deleted file mode 100644 index 39d10e0362f6..000000000000 --- a/hs20/client/spp_client.c +++ /dev/null @@ -1,1004 +0,0 @@ -/* - * Hotspot 2.0 SPP client - * Copyright (c) 2012-2014, Qualcomm Atheros, Inc. - * - * This software may be distributed under the terms of the BSD license. - * See README for more details. - */ - -#include "includes.h" -#include <sys/stat.h> - -#include "common.h" -#include "browser.h" -#include "wpa_ctrl.h" -#include "wpa_helpers.h" -#include "xml-utils.h" -#include "http-utils.h" -#include "utils/base64.h" -#include "crypto/crypto.h" -#include "crypto/sha256.h" -#include "osu_client.h" - - -extern const char *spp_xsd_fname; - -static int hs20_spp_update_response(struct hs20_osu_client *ctx, - const char *session_id, - const char *spp_status, - const char *error_code); -static void hs20_policy_update_complete( - struct hs20_osu_client *ctx, const char *pps_fname); - - -static char * get_spp_attr_value(struct xml_node_ctx *ctx, xml_node_t *node, - char *attr_name) -{ - return xml_node_get_attr_value_ns(ctx, node, SPP_NS_URI, attr_name); -} - - -static int hs20_spp_validate(struct hs20_osu_client *ctx, xml_node_t *node, - const char *expected_name) -{ - struct xml_node_ctx *xctx = ctx->xml; - const char *name; - char *err; - int ret; - - if (!xml_node_is_element(xctx, node)) - return -1; - - name = xml_node_get_localname(xctx, node); - if (name == NULL) - return -1; - - if (strcmp(expected_name, name) != 0) { - wpa_printf(MSG_INFO, "Unexpected SOAP method name '%s' (expected '%s')", - name, expected_name); - write_summary(ctx, "Unexpected SOAP method name '%s' (expected '%s')", - name, expected_name); - return -1; - } - - ret = xml_validate(xctx, node, spp_xsd_fname, &err); - if (ret < 0) { - wpa_printf(MSG_INFO, "XML schema validation error(s)\n%s", err); - write_summary(ctx, "SPP XML schema validation failed"); - os_free(err); - } - return ret; -} - - -static void add_mo_container(struct xml_node_ctx *ctx, xml_namespace_t *ns, - xml_node_t *parent, const char *urn, - const char *fname) -{ - xml_node_t *node; - xml_node_t *fnode, *tnds; - char *str; - - errno = 0; - fnode = node_from_file(ctx, fname); - if (!fnode) { - wpa_printf(MSG_ERROR, - "Failed to create XML node from file: %s, possible error: %s", - fname, strerror(errno)); - return; - } - tnds = mo_to_tnds(ctx, fnode, 0, urn, "syncml:dmddf1.2"); - xml_node_free(ctx, fnode); - if (!tnds) - return; - - str = xml_node_to_str(ctx, tnds); - xml_node_free(ctx, tnds); - if (str == NULL) - return; - - node = xml_node_create_text(ctx, parent, ns, "moContainer", str); - if (node) - xml_node_add_attr(ctx, node, ns, "moURN", urn); - os_free(str); -} - - -static xml_node_t * build_spp_post_dev_data(struct hs20_osu_client *ctx, - xml_namespace_t **ret_ns, - const char *session_id, - const char *reason) -{ - xml_namespace_t *ns; - xml_node_t *spp_node; - - write_summary(ctx, "Building sppPostDevData requestReason='%s'", - reason); - spp_node = xml_node_create_root(ctx->xml, SPP_NS_URI, "spp", &ns, - "sppPostDevData"); - 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, NULL, "requestReason", reason); - if (session_id) - xml_node_add_attr(ctx->xml, spp_node, ns, "sessionID", - session_id); - xml_node_add_attr(ctx->xml, spp_node, NULL, "redirectURI", - "http://localhost:12345/"); - - xml_node_create_text(ctx->xml, spp_node, ns, "supportedSPPVersions", - "1.0"); - xml_node_create_text(ctx->xml, spp_node, ns, "supportedMOList", - URN_HS20_PPS " " URN_OMA_DM_DEVINFO " " - URN_OMA_DM_DEVDETAIL " " URN_HS20_DEVDETAIL_EXT); - - add_mo_container(ctx->xml, ns, spp_node, URN_OMA_DM_DEVINFO, - "devinfo.xml"); - add_mo_container(ctx->xml, ns, spp_node, URN_OMA_DM_DEVDETAIL, - "devdetail.xml"); - - return spp_node; -} - - -static int process_update_node(struct hs20_osu_client *ctx, xml_node_t *pps, - xml_node_t *update) -{ - xml_node_t *node, *parent, *tnds, *unode; - char *str; - const char *name; - char *uri, *pos; - char *cdata, *cdata_end; - size_t fqdn_len; - - wpa_printf(MSG_INFO, "Processing updateNode"); - debug_dump_node(ctx, "updateNode", update); - - uri = get_spp_attr_value(ctx->xml, update, "managementTreeURI"); - if (uri == NULL) { - wpa_printf(MSG_INFO, "No managementTreeURI present"); - return -1; - } - wpa_printf(MSG_INFO, "managementTreeUri: '%s'", uri); - - name = os_strrchr(uri, '/'); - if (name == NULL) { - wpa_printf(MSG_INFO, "Unexpected URI"); - xml_node_get_attr_value_free(ctx->xml, uri); - return -1; - } - name++; - wpa_printf(MSG_INFO, "Update interior node: '%s'", name); - - str = xml_node_get_text(ctx->xml, update); - if (str == NULL) { - wpa_printf(MSG_INFO, "Could not extract MO text"); - xml_node_get_attr_value_free(ctx->xml, uri); - return -1; - } - wpa_printf(MSG_DEBUG, "[hs20] nodeContainer text: '%s'", str); - cdata = strstr(str, "<![CDATA["); - cdata_end = strstr(str, "]]>"); - if (cdata && cdata_end && cdata_end > cdata && - cdata < strstr(str, "MgmtTree") && - cdata_end > strstr(str, "/MgmtTree")) { - char *tmp; - wpa_printf(MSG_DEBUG, "[hs20] Removing extra CDATA container"); - tmp = strdup(cdata + 9); - if (tmp) { - cdata_end = strstr(tmp, "]]>"); - if (cdata_end) - *cdata_end = '\0'; - wpa_printf(MSG_DEBUG, "[hs20] nodeContainer text with CDATA container removed: '%s'", - tmp); - tnds = xml_node_from_buf(ctx->xml, tmp); - free(tmp); - } else - tnds = NULL; - } else - tnds = xml_node_from_buf(ctx->xml, str); - xml_node_get_text_free(ctx->xml, str); - if (tnds == NULL) { - wpa_printf(MSG_INFO, "[hs20] Could not parse nodeContainer text"); - xml_node_get_attr_value_free(ctx->xml, uri); - return -1; - } - - unode = tnds_to_mo(ctx->xml, tnds); - xml_node_free(ctx->xml, tnds); - if (unode == NULL) { - wpa_printf(MSG_INFO, "[hs20] Could not parse nodeContainer TNDS text"); - xml_node_get_attr_value_free(ctx->xml, uri); - return -1; - } - - debug_dump_node(ctx, "Parsed TNDS", unode); - - if (get_node_uri(ctx->xml, unode, name) == NULL) { - wpa_printf(MSG_INFO, "[hs20] %s node not found", name); - xml_node_free(ctx->xml, unode); - xml_node_get_attr_value_free(ctx->xml, uri); - return -1; - } - - if (os_strncasecmp(uri, "./Wi-Fi/", 8) != 0) { - wpa_printf(MSG_INFO, "Do not allow update outside ./Wi-Fi"); - xml_node_free(ctx->xml, unode); - xml_node_get_attr_value_free(ctx->xml, uri); - return -1; - } - pos = uri + 8; - - if (ctx->fqdn == NULL) { - wpa_printf(MSG_INFO, "FQDN not known"); - xml_node_free(ctx->xml, unode); - xml_node_get_attr_value_free(ctx->xml, uri); - return -1; - } - fqdn_len = os_strlen(ctx->fqdn); - if (os_strncasecmp(pos, ctx->fqdn, fqdn_len) != 0 || - pos[fqdn_len] != '/') { - wpa_printf(MSG_INFO, "Do not allow update outside ./Wi-Fi/%s", - ctx->fqdn); - xml_node_free(ctx->xml, unode); - xml_node_get_attr_value_free(ctx->xml, uri); - return -1; - } - pos += fqdn_len + 1; - - if (os_strncasecmp(pos, "PerProviderSubscription/", 24) != 0) { - wpa_printf(MSG_INFO, "Do not allow update outside ./Wi-Fi/%s/PerProviderSubscription", - ctx->fqdn); - xml_node_free(ctx->xml, unode); - xml_node_get_attr_value_free(ctx->xml, uri); - return -1; - } - pos += 24; - - wpa_printf(MSG_INFO, "Update command for PPS node %s", pos); - - node = get_node(ctx->xml, pps, pos); - if (node) { - parent = xml_node_get_parent(ctx->xml, node); - xml_node_detach(ctx->xml, node); - wpa_printf(MSG_INFO, "Replace '%s' node", name); - } else { - char *pos2; - pos2 = os_strrchr(pos, '/'); - if (pos2 == NULL) { - parent = pps; - } else { - *pos2 = '\0'; - parent = get_node(ctx->xml, pps, pos); - } - if (parent == NULL) { - wpa_printf(MSG_INFO, "Could not find parent %s", pos); - xml_node_free(ctx->xml, unode); - xml_node_get_attr_value_free(ctx->xml, uri); - return -1; - } - wpa_printf(MSG_INFO, "Add '%s' node", name); - } - xml_node_add_child(ctx->xml, parent, unode); - - xml_node_get_attr_value_free(ctx->xml, uri); - - return 0; -} - - -static int update_pps(struct hs20_osu_client *ctx, xml_node_t *update, - const char *pps_fname, xml_node_t *pps) -{ - wpa_printf(MSG_INFO, "Updating PPS based on updateNode element(s)"); - xml_node_for_each_sibling(ctx->xml, update) { - xml_node_for_each_check(ctx->xml, update); - if (process_update_node(ctx, pps, update) < 0) - return -1; - } - - return update_pps_file(ctx, pps_fname, pps); -} - - -static void hs20_sub_rem_complete(struct hs20_osu_client *ctx, - const char *pps_fname) -{ - /* - * Update wpa_supplicant credentials and reconnect using updated - * information. - */ - wpa_printf(MSG_INFO, "Updating wpa_supplicant credentials"); - cmd_set_pps(ctx, pps_fname); - - if (ctx->no_reconnect) - return; - - wpa_printf(MSG_INFO, "Requesting reconnection with updated configuration"); - if (wpa_command(ctx->ifname, "INTERWORKING_SELECT auto") < 0) - wpa_printf(MSG_ERROR, "Failed to request wpa_supplicant to reconnect"); -} - - -static xml_node_t * hs20_spp_upload_mo(struct hs20_osu_client *ctx, - xml_node_t *cmd, - const char *session_id, - const char *pps_fname) -{ - xml_namespace_t *ns; - xml_node_t *node, *ret_node; - char *urn; - - urn = get_spp_attr_value(ctx->xml, cmd, "moURN"); - if (!urn) { - wpa_printf(MSG_INFO, "No URN included"); - return NULL; - } - wpa_printf(MSG_INFO, "Upload MO request - URN=%s", urn); - if (strcasecmp(urn, URN_HS20_PPS) != 0) { - wpa_printf(MSG_INFO, "Unsupported moURN"); - xml_node_get_attr_value_free(ctx->xml, urn); - return NULL; - } - xml_node_get_attr_value_free(ctx->xml, urn); - - if (!pps_fname) { - wpa_printf(MSG_INFO, "PPS file name no known"); - return NULL; - } - - node = build_spp_post_dev_data(ctx, &ns, session_id, - "MO upload"); - if (node == NULL) - return NULL; - add_mo_container(ctx->xml, ns, node, URN_HS20_PPS, pps_fname); - - ret_node = soap_send_receive(ctx->http, node); - if (ret_node == NULL) - return NULL; - - debug_dump_node(ctx, "Received response to MO upload", ret_node); - - if (hs20_spp_validate(ctx, ret_node, "sppPostDevDataResponse") < 0) { - wpa_printf(MSG_INFO, "SPP validation failed"); - xml_node_free(ctx->xml, ret_node); - return NULL; - } - - return ret_node; -} - - -static int hs20_add_mo(struct hs20_osu_client *ctx, xml_node_t *add_mo, - char *fname, size_t fname_len) -{ - char *uri, *urn; - int ret; - - debug_dump_node(ctx, "Received addMO", add_mo); - - urn = get_spp_attr_value(ctx->xml, add_mo, "moURN"); - if (urn == NULL) { - wpa_printf(MSG_INFO, "[hs20] No moURN in addMO"); - return -1; - } - wpa_printf(MSG_INFO, "addMO - moURN: '%s'", urn); - if (strcasecmp(urn, URN_HS20_PPS) != 0) { - wpa_printf(MSG_INFO, "[hs20] Unsupported MO in addMO"); - xml_node_get_attr_value_free(ctx->xml, urn); - return -1; - } - xml_node_get_attr_value_free(ctx->xml, urn); - - uri = get_spp_attr_value(ctx->xml, add_mo, "managementTreeURI"); - if (uri == NULL) { - wpa_printf(MSG_INFO, "[hs20] No managementTreeURI in addMO"); - return -1; - } - wpa_printf(MSG_INFO, "addMO - managementTreeURI: '%s'", uri); - - ret = hs20_add_pps_mo(ctx, uri, add_mo, fname, fname_len); - xml_node_get_attr_value_free(ctx->xml, uri); - return ret; -} - - -static int process_spp_user_input_response(struct hs20_osu_client *ctx, - const char *session_id, - xml_node_t *add_mo) -{ - int ret; - char fname[300]; - - debug_dump_node(ctx, "addMO", add_mo); - - wpa_printf(MSG_INFO, "Subscription registration completed"); - - if (hs20_add_mo(ctx, add_mo, fname, sizeof(fname)) < 0) { - wpa_printf(MSG_INFO, "Could not add MO"); - ret = hs20_spp_update_response( - ctx, session_id, - "Error occurred", - "MO addition or update failed"); - return 0; - } - - ret = hs20_spp_update_response(ctx, session_id, "OK", NULL); - if (ret == 0) - hs20_sub_rem_complete(ctx, fname); - - return 0; -} - - -static xml_node_t * hs20_spp_user_input_completed(struct hs20_osu_client *ctx, - const char *session_id) -{ - xml_node_t *node, *ret_node; - - node = build_spp_post_dev_data(ctx, NULL, session_id, - "User input completed"); - if (node == NULL) - return NULL; - - ret_node = soap_send_receive(ctx->http, node); - if (!ret_node) { - if (soap_reinit_client(ctx->http) < 0) - return NULL; - wpa_printf(MSG_INFO, "Try to finish with re-opened connection"); - node = build_spp_post_dev_data(ctx, NULL, session_id, - "User input completed"); - if (node == NULL) - return NULL; - ret_node = soap_send_receive(ctx->http, node); - if (ret_node == NULL) - return NULL; - wpa_printf(MSG_INFO, "Continue with new connection"); - } - - if (hs20_spp_validate(ctx, ret_node, "sppPostDevDataResponse") < 0) { - wpa_printf(MSG_INFO, "SPP validation failed"); - xml_node_free(ctx->xml, ret_node); - return NULL; - } - - return ret_node; -} - - -static xml_node_t * hs20_spp_get_certificate(struct hs20_osu_client *ctx, - xml_node_t *cmd, - const char *session_id, - const char *pps_fname) -{ - xml_namespace_t *ns; - xml_node_t *node, *ret_node; - int res; - - wpa_printf(MSG_INFO, "Client certificate enrollment"); - - res = osu_get_certificate(ctx, cmd); - if (res < 0) - wpa_printf(MSG_INFO, "EST simpleEnroll failed"); - - node = build_spp_post_dev_data(ctx, &ns, session_id, - res == 0 ? - "Certificate enrollment completed" : - "Certificate enrollment failed"); - if (node == NULL) - return NULL; - - ret_node = soap_send_receive(ctx->http, node); - if (ret_node == NULL) - return NULL; - - debug_dump_node(ctx, "Received response to certificate enrollment " - "completed", ret_node); - - if (hs20_spp_validate(ctx, ret_node, "sppPostDevDataResponse") < 0) { - wpa_printf(MSG_INFO, "SPP validation failed"); - xml_node_free(ctx->xml, ret_node); - return NULL; - } - - return ret_node; -} - - -static int hs20_spp_exec(struct hs20_osu_client *ctx, xml_node_t *exec, - const char *session_id, const char *pps_fname, - xml_node_t *pps, xml_node_t **ret_node) -{ - xml_node_t *cmd; - const char *name; - char *uri; - char *id = strdup(session_id); - - if (id == NULL) - return -1; - - *ret_node = NULL; - - debug_dump_node(ctx, "exec", exec); - - xml_node_for_each_child(ctx->xml, cmd, exec) { - xml_node_for_each_check(ctx->xml, cmd); - break; - } - if (!cmd) { - wpa_printf(MSG_INFO, "exec command element not found (cmd=%p)", - cmd); - free(id); - return -1; - } - - name = xml_node_get_localname(ctx->xml, cmd); - - if (strcasecmp(name, "launchBrowserToURI") == 0) { - int res; - uri = xml_node_get_text(ctx->xml, cmd); - if (!uri) { - wpa_printf(MSG_INFO, "No URI found"); - free(id); - return -1; - } - wpa_printf(MSG_INFO, "Launch browser to URI '%s'", uri); - write_summary(ctx, "Launch browser to URI '%s'", uri); - res = hs20_web_browser(uri, 1); - xml_node_get_text_free(ctx->xml, uri); - if (res > 0) { - wpa_printf(MSG_INFO, "User response in browser completed successfully - sessionid='%s'", - id); - write_summary(ctx, "User response in browser completed successfully"); - *ret_node = hs20_spp_user_input_completed(ctx, id); - free(id); - return *ret_node ? 0 : -1; - } else { - wpa_printf(MSG_INFO, "Failed to receive user response"); - write_summary(ctx, "Failed to receive user response"); - hs20_spp_update_response( - ctx, id, "Error occurred", "Other"); - free(id); - return -1; - } - return 0; - } - - if (strcasecmp(name, "uploadMO") == 0) { - if (pps_fname == NULL) - return -1; - *ret_node = hs20_spp_upload_mo(ctx, cmd, id, - pps_fname); - free(id); - return *ret_node ? 0 : -1; - } - - if (strcasecmp(name, "getCertificate") == 0) { - *ret_node = hs20_spp_get_certificate(ctx, cmd, id, - pps_fname); - free(id); - return *ret_node ? 0 : -1; - } - - wpa_printf(MSG_INFO, "Unsupported exec command: '%s'", name); - free(id); - return -1; -} - - -enum spp_post_dev_data_use { - SPP_SUBSCRIPTION_REMEDIATION, - SPP_POLICY_UPDATE, - SPP_SUBSCRIPTION_REGISTRATION, -}; - -static void process_spp_post_dev_data_response( - struct hs20_osu_client *ctx, - enum spp_post_dev_data_use use, xml_node_t *node, - const char *pps_fname, xml_node_t *pps) -{ - xml_node_t *child; - char *status = NULL; - xml_node_t *update = NULL, *exec = NULL, *add_mo = NULL, *no_mo = NULL; - char *session_id = NULL; - - debug_dump_node(ctx, "sppPostDevDataResponse node", node); - - status = get_spp_attr_value(ctx->xml, node, "sppStatus"); - if (status == NULL) { - wpa_printf(MSG_INFO, "No sppStatus attribute"); - goto out; - } - write_summary(ctx, "Received sppPostDevDataResponse sppStatus='%s'", - status); - - session_id = get_spp_attr_value(ctx->xml, node, "sessionID"); - if (session_id == NULL) { - wpa_printf(MSG_INFO, "No sessionID attribute"); - goto out; - } - - wpa_printf(MSG_INFO, "[hs20] sppPostDevDataResponse - sppStatus: '%s' sessionID: '%s'", - status, session_id); - - xml_node_for_each_child(ctx->xml, child, node) { - const char *name; - xml_node_for_each_check(ctx->xml, child); - debug_dump_node(ctx, "child", child); - name = xml_node_get_localname(ctx->xml, child); - wpa_printf(MSG_INFO, "localname: '%s'", name); - if (!update && strcasecmp(name, "updateNode") == 0) - update = child; - if (!exec && strcasecmp(name, "exec") == 0) - exec = child; - if (!add_mo && strcasecmp(name, "addMO") == 0) - add_mo = child; - if (!no_mo && strcasecmp(name, "noMOUpdate") == 0) - no_mo = child; - } - - if (use == SPP_SUBSCRIPTION_REMEDIATION && - strcasecmp(status, - "Remediation complete, request sppUpdateResponse") == 0) - { - int res, ret; - if (!update && !no_mo) { - wpa_printf(MSG_INFO, "No updateNode or noMOUpdate element"); - goto out; - } - wpa_printf(MSG_INFO, "Subscription remediation completed"); - res = update_pps(ctx, update, pps_fname, pps); - if (res < 0) - wpa_printf(MSG_INFO, "Failed to update PPS MO"); - ret = hs20_spp_update_response( - ctx, session_id, - res < 0 ? "Error occurred" : "OK", - res < 0 ? "MO addition or update failed" : NULL); - if (res == 0 && ret == 0) - hs20_sub_rem_complete(ctx, pps_fname); - goto out; - } - - if (use == SPP_SUBSCRIPTION_REMEDIATION && - strcasecmp(status, "Exchange complete, release TLS connection") == - 0) { - if (!no_mo) { - wpa_printf(MSG_INFO, "No noMOUpdate element"); - goto out; - } - wpa_printf(MSG_INFO, "Subscription remediation completed (no MO update)"); - goto out; - } - - if (use == SPP_POLICY_UPDATE && - strcasecmp(status, "Update complete, request sppUpdateResponse") == - 0) { - int res, ret; - wpa_printf(MSG_INFO, "Policy update received - update PPS"); - res = update_pps(ctx, update, pps_fname, pps); - ret = hs20_spp_update_response( - ctx, session_id, - res < 0 ? "Error occurred" : "OK", - res < 0 ? "MO addition or update failed" : NULL); - if (res == 0 && ret == 0) - hs20_policy_update_complete(ctx, pps_fname); - goto out; - } - - if (use == SPP_SUBSCRIPTION_REGISTRATION && - strcasecmp(status, "Provisioning complete, request " - "sppUpdateResponse") == 0) { - if (!add_mo) { - wpa_printf(MSG_INFO, "No addMO element - not sure what to do next"); - goto out; - } - process_spp_user_input_response(ctx, session_id, add_mo); - node = NULL; - goto out; - } - - if (strcasecmp(status, "No update available at this time") == 0) { - wpa_printf(MSG_INFO, "No update available at this time"); - goto out; - } - - if (strcasecmp(status, "OK") == 0) { - int res; - xml_node_t *ret; - - if (!exec) { - wpa_printf(MSG_INFO, "No exec element - not sure what to do next"); - goto out; - } - res = hs20_spp_exec(ctx, exec, session_id, - pps_fname, pps, &ret); - /* xml_node_free(ctx->xml, node); */ - node = NULL; - if (res == 0 && ret) - process_spp_post_dev_data_response(ctx, use, - ret, pps_fname, pps); - goto out; - } - - if (strcasecmp(status, "Error occurred") == 0) { - xml_node_t *err; - char *code = NULL; - err = get_node(ctx->xml, node, "sppError"); - if (err) - code = xml_node_get_attr_value(ctx->xml, err, - "errorCode"); - wpa_printf(MSG_INFO, "Error occurred - errorCode=%s", - code ? code : "N/A"); - xml_node_get_attr_value_free(ctx->xml, code); - goto out; - } - - wpa_printf(MSG_INFO, - "[hs20] Unsupported sppPostDevDataResponse sppStatus '%s'", - status); -out: - xml_node_get_attr_value_free(ctx->xml, status); - xml_node_get_attr_value_free(ctx->xml, session_id); - xml_node_free(ctx->xml, node); -} - - -static int spp_post_dev_data(struct hs20_osu_client *ctx, - enum spp_post_dev_data_use use, - const char *reason, - const char *pps_fname, xml_node_t *pps) -{ - xml_node_t *payload; - xml_node_t *ret_node; - - payload = build_spp_post_dev_data(ctx, NULL, NULL, reason); - if (payload == NULL) - return -1; - - ret_node = soap_send_receive(ctx->http, payload); - if (!ret_node) { - const char *err = http_get_err(ctx->http); - if (err) { - wpa_printf(MSG_INFO, "HTTP error: %s", err); - write_result(ctx, "HTTP error: %s", err); - } else { - write_summary(ctx, "Failed to send SOAP message"); - } - return -1; - } - - if (hs20_spp_validate(ctx, ret_node, "sppPostDevDataResponse") < 0) { - wpa_printf(MSG_INFO, "SPP validation failed"); - xml_node_free(ctx->xml, ret_node); - return -1; - } - - process_spp_post_dev_data_response(ctx, use, ret_node, - pps_fname, pps); - return 0; -} - - -void spp_sub_rem(struct hs20_osu_client *ctx, const char *address, - const char *pps_fname, - const char *client_cert, const char *client_key, - const char *cred_username, const char *cred_password, - xml_node_t *pps) -{ - wpa_printf(MSG_INFO, "SPP subscription remediation"); - write_summary(ctx, "SPP subscription remediation"); - - os_free(ctx->server_url); - ctx->server_url = os_strdup(address); - - if (soap_init_client(ctx->http, address, ctx->ca_fname, - cred_username, cred_password, client_cert, - client_key) == 0) { - spp_post_dev_data(ctx, SPP_SUBSCRIPTION_REMEDIATION, - "Subscription remediation", pps_fname, pps); - } -} - - -static void hs20_policy_update_complete(struct hs20_osu_client *ctx, - const char *pps_fname) -{ - wpa_printf(MSG_INFO, "Policy update completed"); - - /* - * Update wpa_supplicant credentials and reconnect using updated - * information. - */ - wpa_printf(MSG_INFO, "Updating wpa_supplicant credentials"); - cmd_set_pps(ctx, pps_fname); - - wpa_printf(MSG_INFO, "Requesting reconnection with updated configuration"); - if (wpa_command(ctx->ifname, "INTERWORKING_SELECT auto") < 0) - wpa_printf(MSG_ERROR, "Failed to request wpa_supplicant to reconnect"); -} - - -static int process_spp_exchange_complete(struct hs20_osu_client *ctx, - xml_node_t *node) -{ - char *status, *session_id; - - debug_dump_node(ctx, "sppExchangeComplete", node); - - status = get_spp_attr_value(ctx->xml, node, "sppStatus"); - if (status == NULL) { - wpa_printf(MSG_INFO, "No sppStatus attribute"); - return -1; - } - write_summary(ctx, "Received sppExchangeComplete sppStatus='%s'", - status); - - session_id = get_spp_attr_value(ctx->xml, node, "sessionID"); - if (session_id == NULL) { - wpa_printf(MSG_INFO, "No sessionID attribute"); - xml_node_get_attr_value_free(ctx->xml, status); - return -1; - } - - wpa_printf(MSG_INFO, "[hs20] sppStatus: '%s' sessionID: '%s'", - status, session_id); - xml_node_get_attr_value_free(ctx->xml, session_id); - - if (strcasecmp(status, "Exchange complete, release TLS connection") == - 0) { - xml_node_get_attr_value_free(ctx->xml, status); - return 0; - } - - wpa_printf(MSG_INFO, "Unexpected sppStatus '%s'", status); - write_summary(ctx, "Unexpected sppStatus '%s'", status); - xml_node_get_attr_value_free(ctx->xml, status); - return -1; -} - - -static xml_node_t * build_spp_update_response(struct hs20_osu_client *ctx, - const char *session_id, - const char *spp_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, - "sppUpdateResponse"); - if (spp_node == NULL) - return NULL; - - 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", spp_status); - - if (error_code) { - 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 hs20_spp_update_response(struct hs20_osu_client *ctx, - const char *session_id, - const char *spp_status, - const char *error_code) -{ - xml_node_t *node, *ret_node; - int ret; - - write_summary(ctx, "Building sppUpdateResponse sppStatus='%s' error_code='%s'", - spp_status, error_code); - node = build_spp_update_response(ctx, session_id, spp_status, - error_code); - if (node == NULL) - return -1; - ret_node = soap_send_receive(ctx->http, node); - if (!ret_node) { - if (soap_reinit_client(ctx->http) < 0) - return -1; - wpa_printf(MSG_INFO, "Try to finish with re-opened connection"); - node = build_spp_update_response(ctx, session_id, spp_status, - error_code); - if (node == NULL) - return -1; - ret_node = soap_send_receive(ctx->http, node); - if (ret_node == NULL) - return -1; - wpa_printf(MSG_INFO, "Continue with new connection"); - } - - if (hs20_spp_validate(ctx, ret_node, "sppExchangeComplete") < 0) { - wpa_printf(MSG_INFO, "SPP validation failed"); - xml_node_free(ctx->xml, ret_node); - return -1; - } - - ret = process_spp_exchange_complete(ctx, ret_node); - xml_node_free(ctx->xml, ret_node); - return ret; -} - - -void spp_pol_upd(struct hs20_osu_client *ctx, const char *address, - const char *pps_fname, - const char *client_cert, const char *client_key, - const char *cred_username, const char *cred_password, - xml_node_t *pps) -{ - wpa_printf(MSG_INFO, "SPP policy update"); - write_summary(ctx, "SPP policy update"); - - os_free(ctx->server_url); - ctx->server_url = os_strdup(address); - - if (soap_init_client(ctx->http, address, ctx->ca_fname, cred_username, - cred_password, client_cert, client_key) == 0) { - spp_post_dev_data(ctx, SPP_POLICY_UPDATE, "Policy update", - pps_fname, pps); - } -} - - -int cmd_prov(struct hs20_osu_client *ctx, const char *url) -{ - unlink("Cert/est_cert.der"); - unlink("Cert/est_cert.pem"); - - if (url == NULL) { - wpa_printf(MSG_INFO, "Invalid prov command (missing URL)"); - return -1; - } - - wpa_printf(MSG_INFO, - "Credential provisioning requested - URL: %s ca_fname: %s", - url, ctx->ca_fname ? ctx->ca_fname : "N/A"); - - os_free(ctx->server_url); - ctx->server_url = os_strdup(url); - - if (soap_init_client(ctx->http, url, ctx->ca_fname, NULL, NULL, NULL, - NULL) < 0) - return -1; - spp_post_dev_data(ctx, SPP_SUBSCRIPTION_REGISTRATION, - "Subscription registration", NULL, NULL); - - return ctx->pps_cred_set ? 0 : -1; -} - - -int cmd_sim_prov(struct hs20_osu_client *ctx, const char *url) -{ - if (url == NULL) { - wpa_printf(MSG_INFO, "Invalid prov command (missing URL)"); - return -1; - } - - wpa_printf(MSG_INFO, "SIM provisioning requested"); - - os_free(ctx->server_url); - ctx->server_url = os_strdup(url); - - wpa_printf(MSG_INFO, "Wait for IP address before starting SIM provisioning"); - - if (wait_ip_addr(ctx->ifname, 15) < 0) { - wpa_printf(MSG_INFO, "Could not get IP address for WLAN - try connection anyway"); - } - - if (soap_init_client(ctx->http, url, ctx->ca_fname, NULL, NULL, NULL, - NULL) < 0) - return -1; - spp_post_dev_data(ctx, SPP_SUBSCRIPTION_REGISTRATION, - "Subscription provisioning", NULL, NULL); - - return ctx->pps_cred_set ? 0 : -1; -} diff --git a/hs20/server/.gitignore b/hs20/server/.gitignore deleted file mode 100644 index fecb096c128a..000000000000 --- a/hs20/server/.gitignore +++ /dev/null @@ -1 +0,0 @@ -hs20_spp_server diff --git a/hs20/server/Makefile b/hs20/server/Makefile deleted file mode 100644 index 0cab6d6b010a..000000000000 --- a/hs20/server/Makefile +++ /dev/null @@ -1,42 +0,0 @@ -ALL=hs20_spp_server - -include ../../src/build.rules - -CFLAGS += -I../../src -CFLAGS += -I../../src/utils -CFLAGS += -I../../src/crypto - -LIBS += -lsqlite3 - -# Using glibc < 2.17 requires -lrt for clock_gettime() -LIBS += -lrt - -ifndef CONFIG_NO_GITVER -# Add VERSION_STR postfix for builds from a git repository -ifeq ($(wildcard ../../.git),../../.git) -GITVER := $(shell git describe --dirty=+) -ifneq ($(GITVER),) -CFLAGS += -DGIT_VERSION_STR_POSTFIX=\"-$(GITVER)\" -endif -endif -endif - -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 - -_OBJS_VAR := OBJS -include ../../src/objs.mk -hs20_spp_server: $(OBJS) - $(LDO) $(LDFLAGS) -o hs20_spp_server $(OBJS) $(LIBS) - -clean: common-clean - rm -f core *~ diff --git a/hs20/server/ca/clean.sh b/hs20/server/ca/clean.sh deleted file mode 100755 index c72dcbda45e9..000000000000 --- a/hs20/server/ca/clean.sh +++ /dev/null @@ -1,13 +0,0 @@ -#!/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 --git a/hs20/server/ca/est-csrattrs.cnf b/hs20/server/ca/est-csrattrs.cnf deleted file mode 100644 index b50ea00d0b77..000000000000 --- a/hs20/server/ca/est-csrattrs.cnf +++ /dev/null @@ -1,17 +0,0 @@ -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 --git a/hs20/server/ca/est-csrattrs.sh b/hs20/server/ca/est-csrattrs.sh deleted file mode 100755 index 0b73a0408284..000000000000 --- a/hs20/server/ca/est-csrattrs.sh +++ /dev/null @@ -1,4 +0,0 @@ -#!/bin/sh - -openssl asn1parse -genconf est-csrattrs.cnf -out est-csrattrs.der -oid hs20.oid -base64 est-csrattrs.der > est-attrs.b64 diff --git a/hs20/server/ca/hs20.oid b/hs20/server/ca/hs20.oid deleted file mode 100644 index a829ff29bf44..000000000000 --- a/hs20/server/ca/hs20.oid +++ /dev/null @@ -1,7 +0,0 @@ -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 --git a/hs20/server/ca/ocsp-req.sh b/hs20/server/ca/ocsp-req.sh deleted file mode 100755 index 931a20696d02..000000000000 --- a/hs20/server/ca/ocsp-req.sh +++ /dev/null @@ -1,11 +0,0 @@ -#!/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 --git a/hs20/server/ca/ocsp-responder-ica.sh b/hs20/server/ca/ocsp-responder-ica.sh deleted file mode 100755 index 116c6e1c3d01..000000000000 --- a/hs20/server/ca/ocsp-responder-ica.sh +++ /dev/null @@ -1,3 +0,0 @@ -#!/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 --git a/hs20/server/ca/ocsp-responder.sh b/hs20/server/ca/ocsp-responder.sh deleted file mode 100755 index 620947d01af0..000000000000 --- a/hs20/server/ca/ocsp-responder.sh +++ /dev/null @@ -1,3 +0,0 @@ -#!/bin/sh - -openssl ocsp -index demoCA/index.txt -port 8888 -nmin 5 -rsigner ocsp.pem -rkey ocsp.key -CA demoCA/cacert.pem -text -ignore_err diff --git a/hs20/server/ca/ocsp-update-cache.sh b/hs20/server/ca/ocsp-update-cache.sh deleted file mode 100755 index f2b23250cadd..000000000000 --- a/hs20/server/ca/ocsp-update-cache.sh +++ /dev/null @@ -1,11 +0,0 @@ -#!/bin/sh - -# NOTE: You may need to replace 'localhost' with your OCSP server hostname. -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 --git a/hs20/server/ca/openssl-root.cnf b/hs20/server/ca/openssl-root.cnf deleted file mode 100644 index 5bc50be1dbc9..000000000000 --- a/hs20/server/ca/openssl-root.cnf +++ /dev/null @@ -1,125 +0,0 @@ -# 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 --git a/hs20/server/ca/openssl.cnf b/hs20/server/ca/openssl.cnf deleted file mode 100644 index 61410138340f..000000000000 --- a/hs20/server/ca/openssl.cnf +++ /dev/null @@ -1,200 +0,0 @@ -# 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:engExample OSU -#nameConstraints=permitted;DNS:.@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 --git a/hs20/server/ca/setup.sh b/hs20/server/ca/setup.sh deleted file mode 100755 index 78abcccff455..000000000000 --- a/hs20/server/ca/setup.sh +++ /dev/null @@ -1,209 +0,0 @@ -#!/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="4532f7ec36424381617c03c6ce87b55a51d6e7177ffafda243cebf280a68954d" -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,@OCSP_URI@,$OCSP_URI," | -sed "s,@LOGO_URI@,$LOGO_URI," | -sed "s,@LOGO_HASH1@,$LOGO_HASH1," | -sed "s,@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 diff --git a/hs20/server/ca/w1fi_logo.png b/hs20/server/ca/w1fi_logo.png Binary files differdeleted file mode 100644 index ac7c259fff2e..000000000000 --- a/hs20/server/ca/w1fi_logo.png +++ /dev/null diff --git a/hs20/server/hs20-osu-server.txt b/hs20/server/hs20-osu-server.txt deleted file mode 100644 index 22478ad9d2cb..000000000000 --- a/hs20/server/hs20-osu-server.txt +++ /dev/null @@ -1,262 +0,0 @@ -Hotspot 2.0 OSU server -====================== - -The information in this document is based on the assumption that Ubuntu -16.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. - - -Build dependencies ------------------- - -Ubuntu 16.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 php-sqlite3 php-xml libapache2-mod-php - -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 - -# Create /home/user/hs20-server/terms-and-conditions file (HTML segment to be -# inserted within the BODY section of the page). -cat > /home/user/hs20-server/terms-and-conditions <<EOF -<P>Terms and conditions..</P> -EOF - -# Build local keys and certs -cd ca -# Display help options. -./setup.sh -h - -# Remove old keys, fill in appropriate values, and generate your keys. -# For instance: -./clean.sh -rm -fr rootCA" -old_hostname=myserver.local -./setup.sh -C "Hotspot 2.0 Trust Root CA - CT" \ - -o $old_hostname-osu-client \ - -O $old_hostname-oscp -p lanforge -S $old_hostname \ - -V $old_hostname-osu-revoked \ - -m local -u http://$old_hostname:8888/ - -# Configure subscription policies -mkdir -p /home/user/hs20-server/spp/policy -cat > /home/user/hs20-server/spp/policy/default.xml <<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@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 - Require all granted - SSLOptions +StdEnvVars - </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. - -To support subscription remediation using client certificates, set -"SSLVerifyClient optional" and configure the trust root CA(s) for the -client certificates with SSLCACertificateFile. - -Enable default-ssl site and restart Apache2: - sudo a2ensite default-ssl - sudo a2enmod ssl - sudo service apache2 restart - - -Management UI -------------- - -The sample PHP scripts include a management UI for testing -purposes. That is available at https://<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 --git a/hs20/server/hs20_spp_server.c b/hs20/server/hs20_spp_server.c deleted file mode 100644 index 347c40a73d6a..000000000000 --- a/hs20/server/hs20_spp_server.c +++ /dev/null @@ -1,207 +0,0 @@ -/* - * 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 "common/version.h" -#include "xml-utils.h" -#include "spp_server.h" - - -static void write_timestamp(FILE *f) -{ - time_t t; - struct tm *tm; - - time(&t); - tm = localtime(&t); - - fprintf(f, "%04u-%02u-%02u %02u:%02u:%02u ", - tm->tm_year + 1900, tm->tm_mon + 1, tm->tm_mday, - tm->tm_hour, tm->tm_min, tm->tm_sec); -} - - -void debug_print(struct hs20_svc *ctx, int print, const char *fmt, ...) -{ - va_list ap; - - if (ctx->debug_log == NULL) - return; - - write_timestamp(ctx->debug_log); - va_start(ap, fmt); - vfprintf(ctx->debug_log, fmt, ap); - va_end(ap); - - fprintf(ctx->debug_log, "\n"); -} - - -void debug_dump_node(struct hs20_svc *ctx, const char *title, xml_node_t *node) -{ - char *str; - - if (ctx->debug_log == NULL) - return; - str = xml_node_to_str(ctx->xml, node); - if (str == NULL) - return; - - write_timestamp(ctx->debug_log); - fprintf(ctx->debug_log, "%s: '%s'\n", title, str); - os_free(str); -} - - -static int process(struct hs20_svc *ctx) -{ - int dmacc = 0; - xml_node_t *soap, *spp, *resp; - char *user, *realm, *post, *str; - - ctx->addr = getenv("HS20ADDR"); - if (ctx->addr) - debug_print(ctx, 1, "Connection from %s", ctx->addr); - ctx->test = getenv("HS20TEST"); - if (ctx->test) - debug_print(ctx, 1, "Requested test functionality: %s", - ctx->test); - - user = getenv("HS20USER"); - if (user && strlen(user) == 0) - user = NULL; - realm = getenv("HS20REALM"); - if (realm == NULL) { - debug_print(ctx, 1, "HS20REALM not set"); - return -1; - } - post = getenv("HS20POST"); - if (post == NULL) { - debug_print(ctx, 1, "HS20POST not set"); - return -1; - } - - ctx->imsi = getenv("HS20IMSI"); - if (ctx->imsi) - debug_print(ctx, 1, "IMSI %s", ctx->imsi); - - ctx->eap_method = getenv("HS20EAPMETHOD"); - if (ctx->eap_method) - debug_print(ctx, 1, "EAP method %s", ctx->eap_method); - - ctx->id_hash = getenv("HS20IDHASH"); - if (ctx->id_hash) - debug_print(ctx, 1, "ID-HASH %s", ctx->id_hash); - - soap = xml_node_from_buf(ctx->xml, post); - if (soap == NULL) { - debug_print(ctx, 1, "Could not parse SOAP data"); - return -1; - } - debug_dump_node(ctx, "Received SOAP message", soap); - spp = soap_get_body(ctx->xml, soap); - if (spp == NULL) { - debug_print(ctx, 1, "Could not get SPP message"); - xml_node_free(ctx->xml, soap); - return -1; - } - debug_dump_node(ctx, "Received SPP message", spp); - - resp = hs20_spp_server_process(ctx, spp, user, realm, dmacc); - xml_node_free(ctx->xml, soap); - if (resp == NULL && user == NULL) { - debug_print(ctx, 1, "Request HTTP authentication"); - return 2; /* Request authentication */ - } - if (resp == NULL) { - debug_print(ctx, 1, "No response"); - return -1; - } - - soap = soap_build_envelope(ctx->xml, resp); - if (soap == NULL) { - debug_print(ctx, 1, "SOAP envelope building failed"); - return -1; - } - str = xml_node_to_str(ctx->xml, soap); - xml_node_free(ctx->xml, soap); - if (str == NULL) { - debug_print(ctx, 1, "Could not get node string"); - return -1; - } - printf("%s", str); - free(str); - - return 0; -} - - -static void usage(void) -{ - printf("usage:\n" - "hs20_spp_server -r<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:v"); - if (c < 0) - break; - switch (c) { - case 'f': - if (ctx.debug_log) - break; - ctx.debug_log = fopen(optarg, "a"); - if (ctx.debug_log == NULL) { - printf("Could not write to %s\n", optarg); - return -1; - } - break; - case 'r': - ctx.root_dir = optarg; - break; - case 'v': - printf("hs20_spp_server v%s\n", VERSION_STR); - return 0; - default: - usage(); - return -1; - } - } - if (ctx.root_dir == NULL) { - usage(); - return -1; - } - ctx.xml = xml_node_init_ctx(&ctx, NULL); - if (ctx.xml == NULL) - return -1; - if (hs20_spp_server_init(&ctx) < 0) { - xml_node_deinit_ctx(ctx.xml); - return -1; - } - - ret = process(&ctx); - debug_print(&ctx, 1, "process() --> %d", ret); - - xml_node_deinit_ctx(ctx.xml); - hs20_spp_server_deinit(&ctx); - if (ctx.debug_log) - fclose(ctx.debug_log); - - return ret; -} diff --git a/hs20/server/spp_server.c b/hs20/server/spp_server.c deleted file mode 100644 index a50e9074f7b4..000000000000 --- a/hs20/server/spp_server.c +++ /dev/null @@ -1,2933 +0,0 @@ -/* - * 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, - CLEAR_REMEDIATION, - CERT_REENROLL, -}; - - -static char * db_get_session_val(struct hs20_svc *ctx, const char *user, - const char *realm, const char *session_id, - const char *field); -static char * db_get_osu_config_val(struct hs20_svc *ctx, const char *realm, - const char *field); -static xml_node_t * build_policy(struct hs20_svc *ctx, const char *user, - const char *realm, int use_dmacc); -static xml_node_t * spp_exec_get_certificate(struct hs20_svc *ctx, - const char *session_id, - const char *user, - const char *realm, - int add_est_user); - - -static int db_add_session(struct hs20_svc *ctx, - const char *user, const char *realm, - const char *sessionid, const char *pw, - const char *redirect_uri, - enum hs20_session_operation operation, - const u8 *mac_addr) -{ - char *sql; - int ret = 0; - char addr[20]; - - if (mac_addr) - snprintf(addr, sizeof(addr), MACSTR, MAC2STR(mac_addr)); - else - addr[0] = '\0'; - sql = sqlite3_mprintf("INSERT INTO sessions(timestamp,id,user,realm," - "operation,password,redirect_uri,mac_addr,test) " - "VALUES " - "(strftime('%%Y-%%m-%%d %%H:%%M:%%f','now')," - "%Q,%Q,%Q,%d,%Q,%Q,%Q,%Q)", - sessionid, user ? user : "", realm ? realm : "", - operation, pw ? pw : "", - redirect_uri ? redirect_uri : "", - addr, ctx->test); - if (sql == NULL) - return -1; - debug_print(ctx, 1, "DB: %s", sql); - if (sqlite3_exec(ctx->db, sql, NULL, NULL, NULL) != SQLITE_OK) { - debug_print(ctx, 1, "Failed to add session entry into sqlite " - "database: %s", sqlite3_errmsg(ctx->db)); - ret = -1; - } - sqlite3_free(sql); - return ret; -} - - -static void db_update_session_password(struct hs20_svc *ctx, const char *user, - const char *realm, const char *sessionid, - const char *pw) -{ - char *sql; - - sql = sqlite3_mprintf("UPDATE sessions SET password=%Q WHERE id=%Q AND " - "user=%Q AND realm=%Q", - pw, sessionid, user, realm); - if (sql == NULL) - return; - debug_print(ctx, 1, "DB: %s", sql); - if (sqlite3_exec(ctx->db, sql, NULL, NULL, NULL) != SQLITE_OK) { - debug_print(ctx, 1, "Failed to update session password: %s", - sqlite3_errmsg(ctx->db)); - } - sqlite3_free(sql); -} - - -static void db_update_session_machine_managed(struct hs20_svc *ctx, - const char *user, - const char *realm, - const char *sessionid, - const int pw_mm) -{ - char *sql; - - sql = sqlite3_mprintf("UPDATE sessions SET machine_managed=%Q WHERE id=%Q AND user=%Q AND realm=%Q", - pw_mm ? "1" : "0", sessionid, user, realm); - if (sql == NULL) - return; - debug_print(ctx, 1, "DB: %s", sql); - if (sqlite3_exec(ctx->db, sql, NULL, NULL, NULL) != SQLITE_OK) { - debug_print(ctx, 1, - "Failed to update session machine_managed: %s", - sqlite3_errmsg(ctx->db)); - } - sqlite3_free(sql); -} - - -static void db_add_session_pps(struct hs20_svc *ctx, const char *user, - const char *realm, const char *sessionid, - xml_node_t *node) -{ - char *str; - char *sql; - - str = xml_node_to_str(ctx->xml, node); - if (str == NULL) - return; - sql = sqlite3_mprintf("UPDATE sessions SET pps=%Q WHERE id=%Q AND " - "user=%Q AND realm=%Q", - str, sessionid, user, realm); - free(str); - if (sql == NULL) - return; - debug_print(ctx, 1, "DB: %s", sql); - if (sqlite3_exec(ctx->db, sql, NULL, NULL, NULL) != SQLITE_OK) { - debug_print(ctx, 1, "Failed to add session pps: %s", - sqlite3_errmsg(ctx->db)); - } - sqlite3_free(sql); -} - - -static void db_add_session_devinfo(struct hs20_svc *ctx, const char *sessionid, - xml_node_t *node) -{ - char *str; - char *sql; - - str = xml_node_to_str(ctx->xml, node); - if (str == NULL) - return; - sql = sqlite3_mprintf("UPDATE sessions SET devinfo=%Q WHERE id=%Q", - str, sessionid); - free(str); - if (sql == NULL) - return; - debug_print(ctx, 1, "DB: %s", sql); - if (sqlite3_exec(ctx->db, sql, NULL, NULL, NULL) != SQLITE_OK) { - debug_print(ctx, 1, "Failed to add session devinfo: %s", - sqlite3_errmsg(ctx->db)); - } - sqlite3_free(sql); -} - - -static void db_add_session_devdetail(struct hs20_svc *ctx, - const char *sessionid, - xml_node_t *node) -{ - char *str; - char *sql; - - str = xml_node_to_str(ctx->xml, node); - if (str == NULL) - return; - sql = sqlite3_mprintf("UPDATE sessions SET devdetail=%Q WHERE id=%Q", - str, sessionid); - free(str); - if (sql == NULL) - return; - debug_print(ctx, 1, "DB: %s", sql); - if (sqlite3_exec(ctx->db, sql, NULL, NULL, NULL) != SQLITE_OK) { - debug_print(ctx, 1, "Failed to add session devdetail: %s", - sqlite3_errmsg(ctx->db)); - } - sqlite3_free(sql); -} - - -static void db_add_session_dmacc(struct hs20_svc *ctx, const char *sessionid, - const char *username, const char *password) -{ - char *sql; - - sql = sqlite3_mprintf("UPDATE sessions SET osu_user=%Q, osu_password=%Q WHERE id=%Q", - username, password, sessionid); - if (!sql) - return; - debug_print(ctx, 1, "DB: %s", sql); - if (sqlite3_exec(ctx->db, sql, NULL, NULL, NULL) != SQLITE_OK) { - debug_print(ctx, 1, "Failed to add session DMAcc: %s", - sqlite3_errmsg(ctx->db)); - } - sqlite3_free(sql); -} - - -static void db_add_session_eap_method(struct hs20_svc *ctx, - const char *sessionid, - const char *method) -{ - char *sql; - - sql = sqlite3_mprintf("UPDATE sessions SET eap_method=%Q WHERE id=%Q", - method, sessionid); - if (!sql) - return; - debug_print(ctx, 1, "DB: %s", sql); - if (sqlite3_exec(ctx->db, sql, NULL, NULL, NULL) != SQLITE_OK) { - debug_print(ctx, 1, "Failed to add session EAP method: %s", - sqlite3_errmsg(ctx->db)); - } - sqlite3_free(sql); -} - - -static void db_add_session_id_hash(struct hs20_svc *ctx, const char *sessionid, - const char *id_hash) -{ - char *sql; - - sql = sqlite3_mprintf("UPDATE sessions SET mobile_identifier_hash=%Q WHERE id=%Q", - id_hash, sessionid); - if (!sql) - return; - debug_print(ctx, 1, "DB: %s", sql); - if (sqlite3_exec(ctx->db, sql, NULL, NULL, NULL) != SQLITE_OK) { - debug_print(ctx, 1, "Failed to add session ID hash: %s", - sqlite3_errmsg(ctx->db)); - } - sqlite3_free(sql); -} - - -static void db_remove_session(struct hs20_svc *ctx, - const char *user, const char *realm, - const char *sessionid) -{ - char *sql; - - if (user == NULL || realm == NULL) { - sql = sqlite3_mprintf("DELETE FROM sessions WHERE " - "id=%Q", sessionid); - } else { - sql = sqlite3_mprintf("DELETE FROM sessions WHERE " - "user=%Q AND realm=%Q AND id=%Q", - user, realm, sessionid); - } - if (sql == NULL) - return; - debug_print(ctx, 1, "DB: %s", sql); - if (sqlite3_exec(ctx->db, sql, NULL, NULL, NULL) != SQLITE_OK) { - debug_print(ctx, 1, "Failed to delete session entry from " - "sqlite database: %s", sqlite3_errmsg(ctx->db)); - } - sqlite3_free(sql); -} - - -static void hs20_eventlog(struct hs20_svc *ctx, - const char *user, const char *realm, - const char *sessionid, const char *notes, - const char *dump) -{ - char *sql; - char *user_buf = NULL, *realm_buf = NULL; - - debug_print(ctx, 1, "eventlog: %s", notes); - - if (user == NULL) { - user_buf = db_get_session_val(ctx, NULL, NULL, sessionid, - "user"); - user = user_buf; - realm_buf = db_get_session_val(ctx, NULL, NULL, sessionid, - "realm"); - realm = realm_buf; - } - - sql = sqlite3_mprintf("INSERT INTO eventlog" - "(user,realm,sessionid,timestamp,notes,dump,addr)" - " VALUES (%Q,%Q,%Q," - "strftime('%%Y-%%m-%%d %%H:%%M:%%f','now')," - "%Q,%Q,%Q)", - user, realm, sessionid, notes, - dump ? dump : "", ctx->addr ? ctx->addr : ""); - free(user_buf); - free(realm_buf); - if (sql == NULL) - return; - if (sqlite3_exec(ctx->db, sql, NULL, NULL, NULL) != SQLITE_OK) { - debug_print(ctx, 1, "Failed to add eventlog entry into sqlite " - "database: %s", sqlite3_errmsg(ctx->db)); - } - sqlite3_free(sql); -} - - -static void hs20_eventlog_node(struct hs20_svc *ctx, - const char *user, const char *realm, - const char *sessionid, const char *notes, - xml_node_t *node) -{ - char *str; - - if (node) - str = xml_node_to_str(ctx->xml, node); - else - str = NULL; - hs20_eventlog(ctx, user, realm, sessionid, notes, str); - free(str); -} - - -static void db_update_mo_str(struct hs20_svc *ctx, const char *user, - const char *realm, const char *name, - const char *str) -{ - char *sql; - if (user == NULL || realm == NULL || name == NULL) - return; - sql = sqlite3_mprintf("UPDATE users SET %s=%Q WHERE identity=%Q AND realm=%Q AND (phase2=1 OR methods='TLS')", - name, str, user, realm); - if (sql == NULL) - return; - debug_print(ctx, 1, "DB: %s", sql); - if (sqlite3_exec(ctx->db, sql, NULL, NULL, NULL) != SQLITE_OK) { - debug_print(ctx, 1, "Failed to update user MO entry in sqlite " - "database: %s", sqlite3_errmsg(ctx->db)); - } - sqlite3_free(sql); -} - - -static void db_update_mo(struct hs20_svc *ctx, const char *user, - const char *realm, const char *name, xml_node_t *mo) -{ - char *str; - - str = xml_node_to_str(ctx->xml, mo); - if (str == NULL) - return; - - db_update_mo_str(ctx, user, realm, name, str); - free(str); -} - - -static void add_text_node(struct hs20_svc *ctx, xml_node_t *parent, - const char *name, const char *value) -{ - xml_node_create_text(ctx->xml, parent, NULL, name, value ? value : ""); -} - - -static void add_text_node_conf(struct hs20_svc *ctx, const char *realm, - xml_node_t *parent, const char *name, - const char *field) -{ - char *val; - val = db_get_osu_config_val(ctx, realm, field); - xml_node_create_text(ctx->xml, parent, NULL, name, val ? val : ""); - os_free(val); -} - - -static void add_text_node_conf_corrupt(struct hs20_svc *ctx, const char *realm, - xml_node_t *parent, const char *name, - const char *field) -{ - char *val; - - val = db_get_osu_config_val(ctx, realm, field); - if (val) { - size_t len; - - len = os_strlen(val); - if (len > 0) { - if (val[len - 1] == '0') - val[len - 1] = '1'; - else - val[len - 1] = '0'; - } - } - xml_node_create_text(ctx->xml, parent, NULL, name, val ? val : ""); - os_free(val); -} - - -static int new_password(char *buf, int buflen) -{ - int i; - - if (buflen < 1) - return -1; - buf[buflen - 1] = '\0'; - if (os_get_random((unsigned char *) buf, buflen - 1) < 0) - return -1; - - for (i = 0; i < buflen - 1; i++) { - unsigned char val = buf[i]; - val %= 2 * 26 + 10; - if (val < 26) - buf[i] = 'a' + val; - else if (val < 2 * 26) - buf[i] = 'A' + val - 26; - else - buf[i] = '0' + val - 2 * 26; - } - - return 0; -} - - -struct get_db_field_data { - const char *field; - char *value; -}; - - -static int get_db_field(void *ctx, int argc, char *argv[], char *col[]) -{ - struct get_db_field_data *data = ctx; - int i; - - for (i = 0; i < argc; i++) { - if (os_strcmp(col[i], data->field) == 0 && argv[i]) { - os_free(data->value); - data->value = os_strdup(argv[i]); - break; - } - } - - return 0; -} - - -static char * db_get_val(struct hs20_svc *ctx, const char *user, - const char *realm, const char *field, int dmacc) -{ - char *cmd; - struct get_db_field_data data; - - cmd = sqlite3_mprintf("SELECT %s FROM users WHERE %s=%Q AND realm=%Q AND (phase2=1 OR methods='TLS')", - field, dmacc ? "osu_user" : "identity", - user, realm); - if (cmd == NULL) - return NULL; - memset(&data, 0, sizeof(data)); - data.field = field; - if (sqlite3_exec(ctx->db, cmd, get_db_field, &data, NULL) != SQLITE_OK) - { - debug_print(ctx, 1, "Could not find user '%s'", user); - sqlite3_free(cmd); - return NULL; - } - sqlite3_free(cmd); - - debug_print(ctx, 1, "DB: user='%s' realm='%s' field='%s' dmacc=%d --> " - "value='%s'", user, realm, field, dmacc, data.value); - - return data.value; -} - - -static int db_update_val(struct hs20_svc *ctx, const char *user, - const char *realm, const char *field, - const char *val, int dmacc) -{ - char *cmd; - int ret; - - cmd = sqlite3_mprintf("UPDATE users SET %s=%Q WHERE %s=%Q AND realm=%Q AND (phase2=1 OR methods='TLS')", - field, val, dmacc ? "osu_user" : "identity", user, - realm); - if (cmd == NULL) - return -1; - debug_print(ctx, 1, "DB: %s", cmd); - if (sqlite3_exec(ctx->db, cmd, NULL, NULL, NULL) != SQLITE_OK) { - debug_print(ctx, 1, - "Failed to update user in sqlite database: %s", - sqlite3_errmsg(ctx->db)); - ret = -1; - } else { - debug_print(ctx, 1, - "DB: user='%s' realm='%s' field='%s' set to '%s'", - user, realm, field, val); - ret = 0; - } - sqlite3_free(cmd); - - return ret; -} - - -static char * db_get_session_val(struct hs20_svc *ctx, const char *user, - const char *realm, const char *session_id, - const char *field) -{ - char *cmd; - struct get_db_field_data data; - - if (user == NULL || realm == NULL) { - cmd = sqlite3_mprintf("SELECT %s FROM sessions WHERE " - "id=%Q", field, session_id); - } else { - cmd = sqlite3_mprintf("SELECT %s FROM sessions WHERE " - "user=%Q AND realm=%Q AND id=%Q", - field, user, realm, session_id); - } - if (cmd == NULL) - return NULL; - debug_print(ctx, 1, "DB: %s", cmd); - memset(&data, 0, sizeof(data)); - data.field = field; - if (sqlite3_exec(ctx->db, cmd, get_db_field, &data, NULL) != SQLITE_OK) - { - debug_print(ctx, 1, "DB: Could not find session %s: %s", - session_id, sqlite3_errmsg(ctx->db)); - sqlite3_free(cmd); - return NULL; - } - sqlite3_free(cmd); - - debug_print(ctx, 1, "DB: return '%s'", data.value); - return data.value; -} - - -static int update_password(struct hs20_svc *ctx, const char *user, - const char *realm, const char *pw, int dmacc) -{ - char *cmd; - - cmd = sqlite3_mprintf("UPDATE users SET password=%Q, " - "remediation='' " - "WHERE %s=%Q AND phase2=1", - pw, dmacc ? "osu_user" : "identity", - user); - if (cmd == NULL) - return -1; - debug_print(ctx, 1, "DB: %s", cmd); - if (sqlite3_exec(ctx->db, cmd, NULL, NULL, NULL) != SQLITE_OK) { - debug_print(ctx, 1, "Failed to update database for user '%s'", - user); - } - sqlite3_free(cmd); - - return 0; -} - - -static int clear_remediation(struct hs20_svc *ctx, const char *user, - const char *realm, int dmacc) -{ - char *cmd; - - cmd = sqlite3_mprintf("UPDATE users SET remediation='' WHERE %s=%Q", - dmacc ? "osu_user" : "identity", - user); - if (cmd == NULL) - return -1; - debug_print(ctx, 1, "DB: %s", cmd); - if (sqlite3_exec(ctx->db, cmd, NULL, NULL, NULL) != SQLITE_OK) { - debug_print(ctx, 1, "Failed to update database for user '%s'", - user); - } - sqlite3_free(cmd); - - return 0; -} - - -static int add_eap_ttls(struct hs20_svc *ctx, xml_node_t *parent) -{ - xml_node_t *node; - - node = xml_node_create(ctx->xml, parent, NULL, "EAPMethod"); - if (node == NULL) - return -1; - - add_text_node(ctx, node, "EAPType", "21"); - add_text_node(ctx, node, "InnerMethod", "MS-CHAP-V2"); - - return 0; -} - - -static xml_node_t * build_username_password(struct hs20_svc *ctx, - xml_node_t *parent, - const char *user, const char *pw) -{ - xml_node_t *node; - char *b64; - size_t len; - - node = xml_node_create(ctx->xml, parent, NULL, "UsernamePassword"); - if (node == NULL) - return NULL; - - add_text_node(ctx, node, "Username", user); - - b64 = base64_encode(pw, strlen(pw), NULL); - if (b64 == NULL) - return NULL; - len = os_strlen(b64); - if (len > 0 && b64[len - 1] == '\n') - b64[len - 1] = '\0'; - add_text_node(ctx, node, "Password", b64); - free(b64); - - return node; -} - - -static int add_username_password(struct hs20_svc *ctx, xml_node_t *cred, - const char *user, const char *pw, - int machine_managed) -{ - xml_node_t *node; - - node = build_username_password(ctx, cred, user, pw); - if (node == NULL) - return -1; - - add_text_node(ctx, node, "MachineManaged", - machine_managed ? "TRUE" : "FALSE"); - add_text_node(ctx, node, "SoftTokenApp", ""); - add_eap_ttls(ctx, node); - - return 0; -} - - -static void add_creation_date(struct hs20_svc *ctx, xml_node_t *cred) -{ - char str[30]; - time_t now; - struct tm tm; - - time(&now); - gmtime_r(&now, &tm); - snprintf(str, sizeof(str), "%04u-%02u-%02uT%02u:%02u:%02uZ", - tm.tm_year + 1900, tm.tm_mon + 1, tm.tm_mday, - tm.tm_hour, tm.tm_min, tm.tm_sec); - xml_node_create_text(ctx->xml, cred, NULL, "CreationDate", str); -} - - -static xml_node_t * build_credential_pw(struct hs20_svc *ctx, - const char *user, const char *realm, - const char *pw, int machine_managed) -{ - xml_node_t *cred; - - cred = xml_node_create_root(ctx->xml, NULL, NULL, NULL, "Credential"); - if (cred == NULL) { - debug_print(ctx, 1, "Failed to create Credential node"); - return NULL; - } - add_creation_date(ctx, cred); - if (add_username_password(ctx, cred, user, pw, machine_managed) < 0) { - xml_node_free(ctx->xml, cred); - return NULL; - } - add_text_node(ctx, cred, "Realm", realm); - - return cred; -} - - -static xml_node_t * build_credential(struct hs20_svc *ctx, - const char *user, const char *realm, - char *new_pw, size_t new_pw_len) -{ - if (new_password(new_pw, new_pw_len) < 0) - return NULL; - debug_print(ctx, 1, "Update password to '%s'", new_pw); - return build_credential_pw(ctx, user, realm, new_pw, 1); -} - - -static xml_node_t * build_credential_cert(struct hs20_svc *ctx, - const char *user, const char *realm, - const char *cert_fingerprint) -{ - xml_node_t *cred, *cert; - - cred = xml_node_create_root(ctx->xml, NULL, NULL, NULL, "Credential"); - if (cred == NULL) { - debug_print(ctx, 1, "Failed to create Credential node"); - return NULL; - } - add_creation_date(ctx, cred); - cert = xml_node_create(ctx->xml, cred, NULL, "DigitalCertificate"); - add_text_node(ctx, cert, "CertificateType", "x509v3"); - add_text_node(ctx, cert, "CertSHA256Fingerprint", cert_fingerprint); - add_text_node(ctx, cred, "Realm", realm); - - return cred; -} - - -static xml_node_t * build_post_dev_data_response(struct hs20_svc *ctx, - xml_namespace_t **ret_ns, - const char *session_id, - const char *status, - const char *error_code) -{ - xml_node_t *spp_node = NULL; - xml_namespace_t *ns; - - spp_node = xml_node_create_root(ctx->xml, SPP_NS_URI, "spp", &ns, - "sppPostDevDataResponse"); - if (spp_node == NULL) - return NULL; - if (ret_ns) - *ret_ns = ns; - - xml_node_add_attr(ctx->xml, spp_node, ns, "sppVersion", "1.0"); - xml_node_add_attr(ctx->xml, spp_node, ns, "sessionID", session_id); - xml_node_add_attr(ctx->xml, spp_node, ns, "sppStatus", status); - - if (error_code) { - xml_node_t *node; - node = xml_node_create(ctx->xml, spp_node, ns, "sppError"); - if (node) - xml_node_add_attr(ctx->xml, node, NULL, "errorCode", - error_code); - } - - return spp_node; -} - - -static int add_update_node(struct hs20_svc *ctx, xml_node_t *spp_node, - xml_namespace_t *ns, const char *uri, - xml_node_t *upd_node) -{ - xml_node_t *node, *tnds; - char *str; - - tnds = mo_to_tnds(ctx->xml, upd_node, 0, NULL, NULL); - if (!tnds) - return -1; - - str = xml_node_to_str(ctx->xml, tnds); - xml_node_free(ctx->xml, tnds); - if (str == NULL) - return -1; - node = xml_node_create_text(ctx->xml, spp_node, ns, "updateNode", str); - free(str); - - xml_node_add_attr(ctx->xml, node, ns, "managementTreeURI", uri); - - return 0; -} - - -static xml_node_t * read_subrem_file(struct hs20_svc *ctx, - const char *subrem_id, - char *uri, size_t uri_size) -{ - char fname[200]; - char *buf, *buf2, *pos; - size_t len; - xml_node_t *node; - - os_snprintf(fname, sizeof(fname), "%s/spp/subrem/%s", - ctx->root_dir, subrem_id); - debug_print(ctx, 1, "Use subrem file %s", fname); - - buf = os_readfile(fname, &len); - if (!buf) - return NULL; - buf2 = os_realloc(buf, len + 1); - if (!buf2) { - os_free(buf); - return NULL; - } - buf = buf2; - buf[len] = '\0'; - - pos = os_strchr(buf, '\n'); - if (!pos) { - os_free(buf); - return NULL; - } - *pos++ = '\0'; - os_strlcpy(uri, buf, uri_size); - - node = xml_node_from_buf(ctx->xml, pos); - os_free(buf); - - return node; -} - - -static xml_node_t * build_sub_rem_resp(struct hs20_svc *ctx, - const char *user, const char *realm, - const char *session_id, - int machine_rem, int dmacc) -{ - xml_namespace_t *ns; - xml_node_t *spp_node, *cred; - char buf[400]; - char new_pw[33]; - char *status; - char *cert; - - cert = db_get_val(ctx, user, realm, "cert", dmacc); - if (cert && cert[0] == '\0') { - os_free(cert); - cert = NULL; - } - if (cert) { - char *subrem; - - /* No change needed in PPS MO unless specifically asked to */ - cred = NULL; - buf[0] = '\0'; - - subrem = db_get_val(ctx, user, realm, "subrem", dmacc); - if (subrem && subrem[0]) { - cred = read_subrem_file(ctx, subrem, buf, sizeof(buf)); - if (!cred) { - debug_print(ctx, 1, - "Could not create updateNode from subrem file"); - os_free(subrem); - os_free(cert); - return NULL; - } - } - os_free(subrem); - } else { - char *real_user = NULL; - char *pw; - - if (dmacc) { - real_user = db_get_val(ctx, user, realm, "identity", - dmacc); - if (!real_user) { - debug_print(ctx, 1, - "Could not find user identity for dmacc user '%s'", - user); - return NULL; - } - } - - pw = db_get_session_val(ctx, user, realm, session_id, - "password"); - if (pw && pw[0]) { - debug_print(ctx, 1, "New password from the user: '%s'", - pw); - snprintf(new_pw, sizeof(new_pw), "%s", pw); - free(pw); - cred = build_credential_pw(ctx, - real_user ? real_user : user, - realm, new_pw, 0); - } else { - cred = build_credential(ctx, - real_user ? real_user : user, - realm, new_pw, sizeof(new_pw)); - } - - free(real_user); - if (!cred) { - debug_print(ctx, 1, "Could not build credential"); - os_free(cert); - return NULL; - } - - snprintf(buf, sizeof(buf), - "./Wi-Fi/%s/PerProviderSubscription/Cred01/Credential", - realm); - } - - status = "Remediation complete, request sppUpdateResponse"; - spp_node = build_post_dev_data_response(ctx, &ns, session_id, status, - NULL); - if (spp_node == NULL) { - debug_print(ctx, 1, "Could not build sppPostDevDataResponse"); - os_free(cert); - return NULL; - } - - if ((cred && add_update_node(ctx, spp_node, ns, buf, cred) < 0) || - (!cred && !xml_node_create(ctx->xml, spp_node, ns, "noMOUpdate"))) { - debug_print(ctx, 1, "Could not add update node"); - xml_node_free(ctx->xml, spp_node); - os_free(cert); - return NULL; - } - - hs20_eventlog_node(ctx, user, realm, session_id, - machine_rem ? "machine remediation" : - "user remediation", cred); - xml_node_free(ctx->xml, cred); - - if (cert) { - debug_print(ctx, 1, "Request DB remediation clearing on success notification (certificate credential)"); - db_add_session(ctx, user, realm, session_id, NULL, NULL, - CLEAR_REMEDIATION, NULL); - } else { - debug_print(ctx, 1, "Request DB password update on success " - "notification"); - db_add_session(ctx, user, realm, session_id, new_pw, NULL, - UPDATE_PASSWORD, NULL); - } - os_free(cert); - - return spp_node; -} - - -static xml_node_t * machine_remediation(struct hs20_svc *ctx, - const char *user, - const char *realm, - const char *session_id, int dmacc) -{ - return build_sub_rem_resp(ctx, user, realm, session_id, 1, dmacc); -} - - -static xml_node_t * cert_reenroll(struct hs20_svc *ctx, - const char *user, - const char *realm, - const char *session_id) -{ - db_add_session(ctx, user, realm, session_id, NULL, NULL, - CERT_REENROLL, NULL); - return spp_exec_get_certificate(ctx, session_id, user, realm, 0); -} - - -static xml_node_t * policy_remediation(struct hs20_svc *ctx, - const char *user, const char *realm, - const char *session_id, int dmacc) -{ - xml_namespace_t *ns; - xml_node_t *spp_node, *policy; - char buf[400]; - const char *status; - - hs20_eventlog(ctx, user, realm, session_id, - "requires policy remediation", NULL); - - db_add_session(ctx, user, realm, session_id, NULL, NULL, - POLICY_REMEDIATION, NULL); - - policy = build_policy(ctx, user, realm, dmacc); - if (!policy) { - return build_post_dev_data_response( - ctx, NULL, session_id, - "No update available at this time", NULL); - } - - status = "Remediation complete, request sppUpdateResponse"; - spp_node = build_post_dev_data_response(ctx, &ns, session_id, status, - NULL); - if (spp_node == NULL) - return NULL; - - snprintf(buf, sizeof(buf), - "./Wi-Fi/%s/PerProviderSubscription/Cred01/Policy", - realm); - - if (add_update_node(ctx, spp_node, ns, buf, policy) < 0) { - xml_node_free(ctx->xml, spp_node); - xml_node_free(ctx->xml, policy); - return NULL; - } - - hs20_eventlog_node(ctx, user, realm, session_id, - "policy update (sub rem)", policy); - xml_node_free(ctx->xml, policy); - - return spp_node; -} - - -static xml_node_t * browser_remediation(struct hs20_svc *ctx, - const char *session_id, - const char *redirect_uri, - const char *uri) -{ - xml_namespace_t *ns; - xml_node_t *spp_node, *exec_node; - - if (redirect_uri == NULL) { - debug_print(ctx, 1, "Missing redirectURI attribute for user " - "remediation"); - return NULL; - } - debug_print(ctx, 1, "redirectURI %s", redirect_uri); - - spp_node = build_post_dev_data_response(ctx, &ns, session_id, "OK", - NULL); - if (spp_node == NULL) - return NULL; - - exec_node = xml_node_create(ctx->xml, spp_node, ns, "exec"); - xml_node_create_text(ctx->xml, exec_node, ns, "launchBrowserToURI", - uri); - return spp_node; -} - - -static xml_node_t * user_remediation(struct hs20_svc *ctx, const char *user, - const char *realm, const char *session_id, - const char *redirect_uri) -{ - char uri[300], *val; - - hs20_eventlog(ctx, user, realm, session_id, - "requires user remediation", NULL); - val = db_get_osu_config_val(ctx, realm, "remediation_url"); - if (val == NULL) - return NULL; - - db_add_session(ctx, user, realm, session_id, NULL, redirect_uri, - USER_REMEDIATION, NULL); - - snprintf(uri, sizeof(uri), "%s%s", val, session_id); - os_free(val); - return browser_remediation(ctx, session_id, redirect_uri, uri); -} - - -static xml_node_t * free_remediation(struct hs20_svc *ctx, - const char *user, const char *realm, - const char *session_id, - const char *redirect_uri) -{ - char uri[300], *val; - - hs20_eventlog(ctx, user, realm, session_id, - "requires free/public account remediation", NULL); - val = db_get_osu_config_val(ctx, realm, "free_remediation_url"); - if (val == NULL) - return NULL; - - db_add_session(ctx, user, realm, session_id, NULL, redirect_uri, - FREE_REMEDIATION, NULL); - - snprintf(uri, sizeof(uri), "%s%s", val, session_id); - os_free(val); - return browser_remediation(ctx, session_id, redirect_uri, uri); -} - - -static xml_node_t * no_sub_rem(struct hs20_svc *ctx, - const char *user, const char *realm, - const char *session_id) -{ - const char *status; - - hs20_eventlog(ctx, user, realm, session_id, - "no subscription mediation available", NULL); - - status = "No update available at this time"; - return build_post_dev_data_response(ctx, NULL, session_id, status, - NULL); -} - - -static xml_node_t * hs20_subscription_remediation(struct hs20_svc *ctx, - const char *user, - const char *realm, - const char *session_id, - int dmacc, - const char *redirect_uri) -{ - char *type, *identity; - xml_node_t *ret; - char *free_account; - - identity = db_get_val(ctx, user, realm, "identity", dmacc); - if (identity == NULL || strlen(identity) == 0) { - hs20_eventlog(ctx, user, realm, session_id, - "user not found in database for remediation", - NULL); - os_free(identity); - return build_post_dev_data_response(ctx, NULL, session_id, - "Error occurred", - "Not found"); - } - os_free(identity); - - free_account = db_get_osu_config_val(ctx, realm, "free_account"); - if (free_account && strcmp(free_account, user) == 0) { - free(free_account); - return no_sub_rem(ctx, user, realm, session_id); - } - free(free_account); - - type = db_get_val(ctx, user, realm, "remediation", dmacc); - if (type && strcmp(type, "free") != 0) { - char *val; - int shared = 0; - val = db_get_val(ctx, user, realm, "shared", dmacc); - if (val) - shared = atoi(val); - free(val); - if (shared) { - free(type); - return no_sub_rem(ctx, user, realm, session_id); - } - } - if (type && strcmp(type, "user") == 0) - ret = user_remediation(ctx, user, realm, session_id, - redirect_uri); - else if (type && strcmp(type, "free") == 0) - ret = free_remediation(ctx, user, realm, session_id, - redirect_uri); - else if (type && strcmp(type, "policy") == 0) - ret = policy_remediation(ctx, user, realm, session_id, dmacc); - else if (type && strcmp(type, "machine") == 0) - ret = machine_remediation(ctx, user, realm, session_id, dmacc); - else if (type && strcmp(type, "reenroll") == 0) - ret = cert_reenroll(ctx, user, realm, session_id); - else - ret = no_sub_rem(ctx, user, realm, session_id); - free(type); - - return ret; -} - - -static xml_node_t * read_policy_file(struct hs20_svc *ctx, - const char *policy_id) -{ - char fname[200]; - - snprintf(fname, sizeof(fname), "%s/spp/policy/%s.xml", - ctx->root_dir, policy_id); - debug_print(ctx, 1, "Use policy file %s", fname); - - return node_from_file(ctx->xml, fname); -} - - -static void update_policy_update_uri(struct hs20_svc *ctx, const char *realm, - xml_node_t *policy) -{ - xml_node_t *node; - char *url; - - node = get_node_uri(ctx->xml, policy, "Policy/PolicyUpdate/URI"); - if (!node) - return; - - url = db_get_osu_config_val(ctx, realm, "policy_url"); - if (!url) - return; - xml_node_set_text(ctx->xml, node, url); - free(url); -} - - -static xml_node_t * build_policy(struct hs20_svc *ctx, const char *user, - const char *realm, int use_dmacc) -{ - char *policy_id; - xml_node_t *policy, *node; - - policy_id = db_get_val(ctx, user, realm, "policy", use_dmacc); - if (policy_id == NULL || strlen(policy_id) == 0) { - free(policy_id); - policy_id = strdup("default"); - if (policy_id == NULL) - return NULL; - } - policy = read_policy_file(ctx, policy_id); - free(policy_id); - if (policy == NULL) - return NULL; - - update_policy_update_uri(ctx, realm, policy); - - node = get_node_uri(ctx->xml, policy, "Policy/PolicyUpdate"); - if (node && use_dmacc) { - char *pw; - pw = db_get_val(ctx, user, realm, "osu_password", use_dmacc); - if (pw == NULL || - build_username_password(ctx, node, user, pw) == NULL) { - debug_print(ctx, 1, "Failed to add Policy/PolicyUpdate/" - "UsernamePassword"); - free(pw); - xml_node_free(ctx->xml, policy); - return NULL; - } - free(pw); - } - - return policy; -} - - -static xml_node_t * hs20_policy_update(struct hs20_svc *ctx, - const char *user, const char *realm, - const char *session_id, int dmacc) -{ - xml_namespace_t *ns; - xml_node_t *spp_node; - xml_node_t *policy; - char buf[400]; - const char *status; - char *identity; - - identity = db_get_val(ctx, user, realm, "identity", dmacc); - if (identity == NULL || strlen(identity) == 0) { - hs20_eventlog(ctx, user, realm, session_id, - "user not found in database for policy update", - NULL); - os_free(identity); - return build_post_dev_data_response(ctx, NULL, session_id, - "Error occurred", - "Not found"); - } - os_free(identity); - - policy = build_policy(ctx, user, realm, dmacc); - if (!policy) { - return build_post_dev_data_response( - ctx, NULL, session_id, - "No update available at this time", NULL); - } - - db_add_session(ctx, user, realm, session_id, NULL, NULL, POLICY_UPDATE, - NULL); - - status = "Update complete, request sppUpdateResponse"; - spp_node = build_post_dev_data_response(ctx, &ns, session_id, status, - NULL); - if (spp_node == NULL) - return NULL; - - snprintf(buf, sizeof(buf), - "./Wi-Fi/%s/PerProviderSubscription/Cred01/Policy", - realm); - - if (add_update_node(ctx, spp_node, ns, buf, policy) < 0) { - xml_node_free(ctx->xml, spp_node); - xml_node_free(ctx->xml, policy); - return NULL; - } - - hs20_eventlog_node(ctx, user, realm, session_id, "policy update", - policy); - xml_node_free(ctx->xml, policy); - - return spp_node; -} - - -static xml_node_t * spp_get_mo(struct hs20_svc *ctx, xml_node_t *node, - const char *urn, int *valid, char **ret_err) -{ - xml_node_t *child, *tnds, *mo; - const char *name; - char *mo_urn; - char *str; - char fname[200]; - - *valid = -1; - if (ret_err) - *ret_err = NULL; - - xml_node_for_each_child(ctx->xml, child, node) { - xml_node_for_each_check(ctx->xml, child); - name = xml_node_get_localname(ctx->xml, child); - if (strcmp(name, "moContainer") != 0) - continue; - mo_urn = xml_node_get_attr_value_ns(ctx->xml, child, SPP_NS_URI, - "moURN"); - if (strcasecmp(urn, mo_urn) == 0) { - xml_node_get_attr_value_free(ctx->xml, mo_urn); - break; - } - xml_node_get_attr_value_free(ctx->xml, mo_urn); - } - - if (child == NULL) - return NULL; - - debug_print(ctx, 1, "moContainer text for %s", urn); - debug_dump_node(ctx, "moContainer", child); - - str = xml_node_get_text(ctx->xml, child); - debug_print(ctx, 1, "moContainer payload: '%s'", str); - tnds = xml_node_from_buf(ctx->xml, str); - xml_node_get_text_free(ctx->xml, str); - if (tnds == NULL) { - debug_print(ctx, 1, "could not parse moContainer text"); - return NULL; - } - - snprintf(fname, sizeof(fname), "%s/spp/dm_ddf-v1_2.dtd", ctx->root_dir); - if (xml_validate_dtd(ctx->xml, tnds, fname, ret_err) == 0) - *valid = 1; - else if (ret_err && *ret_err && - os_strcmp(*ret_err, "No declaration for attribute xmlns of element MgmtTree\n") == 0) { - free(*ret_err); - debug_print(ctx, 1, "Ignore OMA-DM DDF DTD validation error for MgmtTree namespace declaration with xmlns attribute"); - *ret_err = NULL; - *valid = 1; - } else - *valid = 0; - - mo = tnds_to_mo(ctx->xml, tnds); - xml_node_free(ctx->xml, tnds); - if (mo == NULL) { - debug_print(ctx, 1, "invalid moContainer for %s", urn); - } - - return mo; -} - - -static xml_node_t * spp_exec_upload_mo(struct hs20_svc *ctx, - const char *session_id, const char *urn) -{ - xml_namespace_t *ns; - xml_node_t *spp_node, *node, *exec_node; - - spp_node = build_post_dev_data_response(ctx, &ns, session_id, "OK", - NULL); - if (spp_node == NULL) - return NULL; - - exec_node = xml_node_create(ctx->xml, spp_node, ns, "exec"); - - node = xml_node_create(ctx->xml, exec_node, ns, "uploadMO"); - xml_node_add_attr(ctx->xml, node, ns, "moURN", urn); - - return spp_node; -} - - -static xml_node_t * hs20_subscription_registration(struct hs20_svc *ctx, - const char *realm, - const char *session_id, - const char *redirect_uri, - const u8 *mac_addr) -{ - xml_namespace_t *ns; - xml_node_t *spp_node, *exec_node; - char uri[300], *val; - - if (db_add_session(ctx, NULL, realm, session_id, NULL, redirect_uri, - SUBSCRIPTION_REGISTRATION, mac_addr) < 0) - return NULL; - val = db_get_osu_config_val(ctx, realm, "signup_url"); - if (val == NULL) - return NULL; - - spp_node = build_post_dev_data_response(ctx, &ns, session_id, "OK", - NULL); - if (spp_node == NULL) - return NULL; - - exec_node = xml_node_create(ctx->xml, spp_node, ns, "exec"); - - snprintf(uri, sizeof(uri), "%s%s", val, session_id); - os_free(val); - xml_node_create_text(ctx->xml, exec_node, ns, "launchBrowserToURI", - uri); - return spp_node; -} - - -static xml_node_t * hs20_user_input_remediation(struct hs20_svc *ctx, - const char *user, - const char *realm, int dmacc, - const char *session_id) -{ - return build_sub_rem_resp(ctx, user, realm, session_id, 0, dmacc); -} - - -static char * db_get_osu_config_val(struct hs20_svc *ctx, const char *realm, - const char *field) -{ - char *cmd; - struct get_db_field_data data; - - cmd = sqlite3_mprintf("SELECT value FROM osu_config WHERE realm=%Q AND " - "field=%Q", realm, field); - if (cmd == NULL) - return NULL; - debug_print(ctx, 1, "DB: %s", cmd); - memset(&data, 0, sizeof(data)); - data.field = "value"; - if (sqlite3_exec(ctx->db, cmd, get_db_field, &data, NULL) != SQLITE_OK) - { - debug_print(ctx, 1, "DB: Could not find osu_config %s: %s", - realm, sqlite3_errmsg(ctx->db)); - sqlite3_free(cmd); - return NULL; - } - sqlite3_free(cmd); - - debug_print(ctx, 1, "DB: return '%s'", data.value); - return data.value; -} - - -static xml_node_t * build_pps(struct hs20_svc *ctx, - const char *user, const char *realm, - const char *pw, const char *cert, - int machine_managed, const char *test, - const char *imsi, const char *dmacc_username, - const char *dmacc_password, - xml_node_t *policy_node) -{ - xml_node_t *pps, *c, *trust, *aaa, *aaa1, *upd, *homesp, *p; - xml_node_t *cred, *eap, *userpw; - - pps = xml_node_create_root(ctx->xml, NULL, NULL, NULL, - "PerProviderSubscription"); - if (!pps) { - xml_node_free(ctx->xml, policy_node); - return NULL; - } - - add_text_node(ctx, pps, "UpdateIdentifier", "1"); - - c = xml_node_create(ctx->xml, pps, NULL, "Cred01"); - - add_text_node(ctx, c, "CredentialPriority", "1"); - - if (imsi) - goto skip_aaa_trust_root; - aaa = xml_node_create(ctx->xml, c, NULL, "AAAServerTrustRoot"); - aaa1 = xml_node_create(ctx->xml, aaa, NULL, "AAA1"); - add_text_node_conf(ctx, realm, aaa1, "CertURL", - "aaa_trust_root_cert_url"); - if (test && os_strcmp(test, "corrupt_aaa_hash") == 0) { - debug_print(ctx, 1, - "TEST: Corrupt PPS/Cred*/AAAServerTrustRoot/Root*/CertSHA256FingerPrint"); - add_text_node_conf_corrupt(ctx, realm, aaa1, - "CertSHA256Fingerprint", - "aaa_trust_root_cert_fingerprint"); - } else { - add_text_node_conf(ctx, realm, aaa1, "CertSHA256Fingerprint", - "aaa_trust_root_cert_fingerprint"); - } - - if (test && os_strcmp(test, "corrupt_polupd_hash") == 0) { - debug_print(ctx, 1, - "TEST: Corrupt PPS/Cred*/Policy/PolicyUpdate/Trustroot/CertSHA256FingerPrint"); - p = xml_node_create(ctx->xml, c, NULL, "Policy"); - upd = xml_node_create(ctx->xml, p, NULL, "PolicyUpdate"); - add_text_node(ctx, upd, "UpdateInterval", "30"); - add_text_node(ctx, upd, "UpdateMethod", "SPP-ClientInitiated"); - add_text_node(ctx, upd, "Restriction", "Unrestricted"); - add_text_node_conf(ctx, realm, upd, "URI", "policy_url"); - trust = xml_node_create(ctx->xml, upd, NULL, "TrustRoot"); - add_text_node_conf(ctx, realm, trust, "CertURL", - "policy_trust_root_cert_url"); - add_text_node_conf_corrupt(ctx, realm, trust, - "CertSHA256Fingerprint", - "policy_trust_root_cert_fingerprint"); - } -skip_aaa_trust_root: - - upd = xml_node_create(ctx->xml, c, NULL, "SubscriptionUpdate"); - add_text_node(ctx, upd, "UpdateInterval", "4294967295"); - add_text_node(ctx, upd, "UpdateMethod", "SPP-ClientInitiated"); - add_text_node(ctx, upd, "Restriction", "HomeSP"); - add_text_node_conf(ctx, realm, upd, "URI", "spp_http_auth_url"); - trust = xml_node_create(ctx->xml, upd, NULL, "TrustRoot"); - add_text_node_conf(ctx, realm, trust, "CertURL", "trust_root_cert_url"); - if (test && os_strcmp(test, "corrupt_subrem_hash") == 0) { - debug_print(ctx, 1, - "TEST: Corrupt PPS/Cred*/SubscriptionUpdate/Trustroot/CertSHA256FingerPrint"); - add_text_node_conf_corrupt(ctx, realm, trust, - "CertSHA256Fingerprint", - "trust_root_cert_fingerprint"); - } else { - add_text_node_conf(ctx, realm, trust, "CertSHA256Fingerprint", - "trust_root_cert_fingerprint"); - } - - if (dmacc_username && - !build_username_password(ctx, upd, dmacc_username, - dmacc_password)) { - xml_node_free(ctx->xml, pps); - xml_node_free(ctx->xml, policy_node); - return NULL; - } - - if (policy_node) - xml_node_add_child(ctx->xml, c, policy_node); - - homesp = xml_node_create(ctx->xml, c, NULL, "HomeSP"); - add_text_node_conf(ctx, realm, homesp, "FriendlyName", "friendly_name"); - add_text_node_conf(ctx, realm, homesp, "FQDN", "fqdn"); - - xml_node_create(ctx->xml, c, NULL, "SubscriptionParameters"); - - cred = xml_node_create(ctx->xml, c, NULL, "Credential"); - add_creation_date(ctx, cred); - if (imsi) { - xml_node_t *sim; - const char *type = "18"; /* default to EAP-SIM */ - - sim = xml_node_create(ctx->xml, cred, NULL, "SIM"); - add_text_node(ctx, sim, "IMSI", imsi); - if (ctx->eap_method && os_strcmp(ctx->eap_method, "AKA") == 0) - type = "23"; - else if (ctx->eap_method && - os_strcmp(ctx->eap_method, "AKA'") == 0) - type = "50"; - add_text_node(ctx, sim, "EAPType", type); - } else if (cert) { - xml_node_t *dc; - dc = xml_node_create(ctx->xml, cred, NULL, - "DigitalCertificate"); - add_text_node(ctx, dc, "CertificateType", "x509v3"); - add_text_node(ctx, dc, "CertSHA256Fingerprint", cert); - } else { - userpw = build_username_password(ctx, cred, user, pw); - add_text_node(ctx, userpw, "MachineManaged", - machine_managed ? "TRUE" : "FALSE"); - eap = xml_node_create(ctx->xml, userpw, NULL, "EAPMethod"); - add_text_node(ctx, eap, "EAPType", "21"); - add_text_node(ctx, eap, "InnerMethod", "MS-CHAP-V2"); - } - add_text_node(ctx, cred, "Realm", realm); - - return pps; -} - - -static xml_node_t * spp_exec_get_certificate(struct hs20_svc *ctx, - const char *session_id, - const char *user, - const char *realm, - int add_est_user) -{ - xml_namespace_t *ns; - xml_node_t *spp_node, *enroll, *exec_node; - char *val; - char password[11]; - char *b64; - - if (add_est_user && new_password(password, sizeof(password)) < 0) - return NULL; - - spp_node = build_post_dev_data_response(ctx, &ns, session_id, "OK", - NULL); - if (spp_node == NULL) - return NULL; - - exec_node = xml_node_create(ctx->xml, spp_node, ns, "exec"); - - enroll = xml_node_create(ctx->xml, exec_node, ns, "getCertificate"); - xml_node_add_attr(ctx->xml, enroll, NULL, "enrollmentProtocol", "EST"); - - val = db_get_osu_config_val(ctx, realm, "est_url"); - xml_node_create_text(ctx->xml, enroll, ns, "enrollmentServerURI", - val ? val : ""); - os_free(val); - - if (!add_est_user) - return spp_node; - - xml_node_create_text(ctx->xml, enroll, ns, "estUserID", user); - - b64 = base64_encode(password, strlen(password), NULL); - if (b64 == NULL) { - xml_node_free(ctx->xml, spp_node); - return NULL; - } - xml_node_create_text(ctx->xml, enroll, ns, "estPassword", b64); - free(b64); - - db_update_session_password(ctx, user, realm, session_id, password); - - return spp_node; -} - - -static xml_node_t * hs20_user_input_registration(struct hs20_svc *ctx, - const char *session_id, - int enrollment_done) -{ - xml_namespace_t *ns; - xml_node_t *spp_node, *node = NULL; - xml_node_t *pps, *tnds; - char buf[400]; - char *str; - char *user, *realm, *pw, *type, *mm, *test; - const char *status; - int cert = 0; - int machine_managed = 0; - char *fingerprint; - - user = db_get_session_val(ctx, NULL, NULL, session_id, "user"); - realm = db_get_session_val(ctx, NULL, NULL, session_id, "realm"); - pw = db_get_session_val(ctx, NULL, NULL, session_id, "password"); - - if (!user || !realm || !pw) { - debug_print(ctx, 1, "Could not find session info from DB for " - "the new subscription"); - free(user); - free(realm); - free(pw); - return NULL; - } - - mm = db_get_session_val(ctx, NULL, NULL, session_id, "machine_managed"); - if (mm && atoi(mm)) - machine_managed = 1; - free(mm); - - type = db_get_session_val(ctx, NULL, NULL, session_id, "type"); - if (type && strcmp(type, "cert") == 0) - cert = 1; - free(type); - - if (cert && !enrollment_done) { - xml_node_t *ret; - hs20_eventlog(ctx, user, realm, session_id, - "request client certificate enrollment", NULL); - ret = spp_exec_get_certificate(ctx, session_id, user, realm, 1); - free(user); - free(realm); - free(pw); - return ret; - } - - if (!cert && strlen(pw) == 0) { - machine_managed = 1; - free(pw); - pw = malloc(11); - if (pw == NULL || new_password(pw, 11) < 0) { - free(user); - free(realm); - free(pw); - return NULL; - } - } - - status = "Provisioning complete, request sppUpdateResponse"; - spp_node = build_post_dev_data_response(ctx, &ns, session_id, status, - NULL); - if (spp_node == NULL) - return NULL; - - fingerprint = db_get_session_val(ctx, NULL, NULL, session_id, "cert"); - test = db_get_session_val(ctx, NULL, NULL, session_id, "test"); - if (test) - debug_print(ctx, 1, "TEST: Requested special behavior: %s", - test); - pps = build_pps(ctx, user, realm, pw, - fingerprint ? fingerprint : NULL, machine_managed, - test, NULL, NULL, NULL, NULL); - free(fingerprint); - free(test); - if (!pps) { - xml_node_free(ctx->xml, spp_node); - free(user); - free(realm); - free(pw); - return NULL; - } - - debug_print(ctx, 1, "Request DB subscription registration on success " - "notification"); - if (machine_managed) { - db_update_session_password(ctx, user, realm, session_id, pw); - db_update_session_machine_managed(ctx, user, realm, session_id, - machine_managed); - } - db_add_session_pps(ctx, user, realm, session_id, pps); - - hs20_eventlog_node(ctx, user, realm, session_id, - "new subscription", pps); - free(user); - free(pw); - - tnds = mo_to_tnds(ctx->xml, pps, 0, URN_HS20_PPS, NULL); - xml_node_free(ctx->xml, pps); - if (!tnds) { - xml_node_free(ctx->xml, spp_node); - free(realm); - return NULL; - } - - str = xml_node_to_str(ctx->xml, tnds); - xml_node_free(ctx->xml, tnds); - if (str == NULL) { - xml_node_free(ctx->xml, spp_node); - free(realm); - return NULL; - } - - node = xml_node_create_text(ctx->xml, spp_node, ns, "addMO", str); - free(str); - snprintf(buf, sizeof(buf), "./Wi-Fi/%s/PerProviderSubscription", realm); - free(realm); - xml_node_add_attr(ctx->xml, node, ns, "managementTreeURI", buf); - xml_node_add_attr(ctx->xml, node, ns, "moURN", URN_HS20_PPS); - - return spp_node; -} - - -static xml_node_t * hs20_user_input_free_remediation(struct hs20_svc *ctx, - const char *user, - const char *realm, - const char *session_id) -{ - xml_namespace_t *ns; - xml_node_t *spp_node; - xml_node_t *cred; - char buf[400]; - char *status; - char *free_account, *pw; - - free_account = db_get_osu_config_val(ctx, realm, "free_account"); - if (free_account == NULL) - return NULL; - pw = db_get_val(ctx, free_account, realm, "password", 0); - if (pw == NULL) { - free(free_account); - return NULL; - } - - cred = build_credential_pw(ctx, free_account, realm, pw, 1); - free(free_account); - free(pw); - if (!cred) { - xml_node_free(ctx->xml, cred); - return NULL; - } - - status = "Remediation complete, request sppUpdateResponse"; - spp_node = build_post_dev_data_response(ctx, &ns, session_id, status, - NULL); - if (spp_node == NULL) - return NULL; - - snprintf(buf, sizeof(buf), - "./Wi-Fi/%s/PerProviderSubscription/Cred01/Credential", - realm); - - if (add_update_node(ctx, spp_node, ns, buf, cred) < 0) { - xml_node_free(ctx->xml, spp_node); - return NULL; - } - - hs20_eventlog_node(ctx, user, realm, session_id, - "free/public remediation", cred); - xml_node_free(ctx->xml, cred); - - return spp_node; -} - - -static xml_node_t * hs20_user_input_complete(struct hs20_svc *ctx, - const char *user, - const char *realm, int dmacc, - const char *session_id) -{ - char *val; - enum hs20_session_operation oper; - - val = db_get_session_val(ctx, user, realm, session_id, "operation"); - if (val == NULL) { - debug_print(ctx, 1, "No session %s found to continue", - session_id); - return NULL; - } - oper = atoi(val); - free(val); - - if (oper == USER_REMEDIATION) { - return hs20_user_input_remediation(ctx, user, realm, dmacc, - session_id); - } - - if (oper == FREE_REMEDIATION) { - return hs20_user_input_free_remediation(ctx, user, realm, - session_id); - } - - if (oper == SUBSCRIPTION_REGISTRATION) { - return hs20_user_input_registration(ctx, session_id, 0); - } - - debug_print(ctx, 1, "User session %s not in state for user input " - "completion", session_id); - return NULL; -} - - -static xml_node_t * hs20_cert_reenroll_complete(struct hs20_svc *ctx, - const char *session_id) -{ - char *user, *realm, *cert; - char *status; - xml_namespace_t *ns; - xml_node_t *spp_node, *cred; - char buf[400]; - - user = db_get_session_val(ctx, NULL, NULL, session_id, "user"); - realm = db_get_session_val(ctx, NULL, NULL, session_id, "realm"); - cert = db_get_session_val(ctx, NULL, NULL, session_id, "cert"); - if (!user || !realm || !cert) { - debug_print(ctx, 1, - "Could not find session info from DB for certificate reenrollment"); - free(user); - free(realm); - free(cert); - return NULL; - } - - cred = build_credential_cert(ctx, user, realm, cert); - if (!cred) { - debug_print(ctx, 1, "Could not build credential"); - free(user); - free(realm); - free(cert); - return NULL; - } - - status = "Remediation complete, request sppUpdateResponse"; - spp_node = build_post_dev_data_response(ctx, &ns, session_id, status, - NULL); - if (spp_node == NULL) { - debug_print(ctx, 1, "Could not build sppPostDevDataResponse"); - free(user); - free(realm); - free(cert); - xml_node_free(ctx->xml, cred); - return NULL; - } - - snprintf(buf, sizeof(buf), - "./Wi-Fi/%s/PerProviderSubscription/Cred01/Credential", - realm); - - if (add_update_node(ctx, spp_node, ns, buf, cred) < 0) { - debug_print(ctx, 1, "Could not add update node"); - xml_node_free(ctx->xml, spp_node); - free(user); - free(realm); - free(cert); - return NULL; - } - - hs20_eventlog_node(ctx, user, realm, session_id, - "certificate reenrollment", cred); - xml_node_free(ctx->xml, cred); - - free(user); - free(realm); - free(cert); - return spp_node; -} - - -static xml_node_t * hs20_cert_enroll_completed(struct hs20_svc *ctx, - const char *user, - const char *realm, int dmacc, - const char *session_id) -{ - char *val; - enum hs20_session_operation oper; - - val = db_get_session_val(ctx, NULL, NULL, session_id, "operation"); - if (val == NULL) { - debug_print(ctx, 1, "No session %s found to continue", - session_id); - return NULL; - } - oper = atoi(val); - free(val); - - if (oper == SUBSCRIPTION_REGISTRATION) - return hs20_user_input_registration(ctx, session_id, 1); - if (oper == CERT_REENROLL) - return hs20_cert_reenroll_complete(ctx, session_id); - - debug_print(ctx, 1, "User session %s not in state for certificate " - "enrollment completion", session_id); - return NULL; -} - - -static xml_node_t * hs20_cert_enroll_failed(struct hs20_svc *ctx, - const char *user, - const char *realm, int dmacc, - const char *session_id) -{ - char *val; - enum hs20_session_operation oper; - xml_node_t *spp_node, *node; - char *status; - xml_namespace_t *ns; - - val = db_get_session_val(ctx, user, realm, session_id, "operation"); - if (val == NULL) { - debug_print(ctx, 1, "No session %s found to continue", - session_id); - return NULL; - } - oper = atoi(val); - free(val); - - if (oper != SUBSCRIPTION_REGISTRATION) { - debug_print(ctx, 1, "User session %s not in state for " - "enrollment failure", session_id); - return NULL; - } - - status = "Error occurred"; - spp_node = build_post_dev_data_response(ctx, &ns, session_id, status, - NULL); - if (spp_node == NULL) - return NULL; - node = xml_node_create(ctx->xml, spp_node, ns, "sppError"); - xml_node_add_attr(ctx->xml, node, NULL, "errorCode", - "Credentials cannot be provisioned at this time"); - db_remove_session(ctx, user, realm, session_id); - - return spp_node; -} - - -static xml_node_t * hs20_sim_provisioning(struct hs20_svc *ctx, - const char *user, - const char *realm, int dmacc, - const char *session_id) -{ - xml_namespace_t *ns; - xml_node_t *spp_node, *node = NULL; - xml_node_t *pps, *tnds; - char buf[400]; - char *str; - const char *status; - char dmacc_username[32]; - char dmacc_password[32]; - char *policy; - xml_node_t *policy_node = NULL; - - if (!ctx->imsi) { - debug_print(ctx, 1, "IMSI not available for SIM provisioning"); - return NULL; - } - - if (new_password(dmacc_username, sizeof(dmacc_username)) < 0 || - new_password(dmacc_password, sizeof(dmacc_password)) < 0) { - debug_print(ctx, 1, - "Failed to generate DMAcc username/password"); - return NULL; - } - - status = "Provisioning complete, request sppUpdateResponse"; - spp_node = build_post_dev_data_response(ctx, &ns, session_id, status, - NULL); - if (!spp_node) - return NULL; - - policy = db_get_osu_config_val(ctx, realm, "sim_policy"); - if (policy) { - policy_node = read_policy_file(ctx, policy); - os_free(policy); - if (!policy_node) { - xml_node_free(ctx->xml, spp_node); - return NULL; - } - update_policy_update_uri(ctx, realm, policy_node); - node = get_node_uri(ctx->xml, policy_node, - "Policy/PolicyUpdate"); - if (node) - build_username_password(ctx, node, dmacc_username, - dmacc_password); - } - - pps = build_pps(ctx, NULL, realm, NULL, NULL, 0, NULL, ctx->imsi, - dmacc_username, dmacc_password, policy_node); - if (!pps) { - xml_node_free(ctx->xml, spp_node); - return NULL; - } - - debug_print(ctx, 1, - "Request DB subscription registration on success notification"); - if (!user || !user[0]) - user = ctx->imsi; - db_add_session(ctx, user, realm, session_id, NULL, NULL, - SUBSCRIPTION_REGISTRATION, NULL); - db_add_session_dmacc(ctx, session_id, dmacc_username, dmacc_password); - if (ctx->eap_method) - db_add_session_eap_method(ctx, session_id, ctx->eap_method); - if (ctx->id_hash) - db_add_session_id_hash(ctx, session_id, ctx->id_hash); - db_add_session_pps(ctx, user, realm, session_id, pps); - - hs20_eventlog_node(ctx, user, realm, session_id, - "new subscription", pps); - - tnds = mo_to_tnds(ctx->xml, pps, 0, URN_HS20_PPS, NULL); - xml_node_free(ctx->xml, pps); - if (!tnds) { - xml_node_free(ctx->xml, spp_node); - return NULL; - } - - str = xml_node_to_str(ctx->xml, tnds); - xml_node_free(ctx->xml, tnds); - if (!str) { - xml_node_free(ctx->xml, spp_node); - return NULL; - } - - node = xml_node_create_text(ctx->xml, spp_node, ns, "addMO", str); - free(str); - snprintf(buf, sizeof(buf), "./Wi-Fi/%s/PerProviderSubscription", realm); - xml_node_add_attr(ctx->xml, node, ns, "managementTreeURI", buf); - xml_node_add_attr(ctx->xml, node, ns, "moURN", URN_HS20_PPS); - - return spp_node; -} - - -static xml_node_t * hs20_spp_post_dev_data(struct hs20_svc *ctx, - xml_node_t *node, - const char *user, - const char *realm, - const char *session_id, - int dmacc) -{ - const char *req_reason; - char *redirect_uri = NULL; - char *req_reason_buf = NULL; - char str[200]; - xml_node_t *ret = NULL, *devinfo = NULL, *devdetail = NULL; - xml_node_t *mo, *macaddr; - char *version; - int valid; - char *supp, *pos; - char *err; - u8 wifi_mac_addr[ETH_ALEN]; - - version = xml_node_get_attr_value_ns(ctx->xml, node, SPP_NS_URI, - "sppVersion"); - if (version == NULL || strstr(version, "1.0") == NULL) { - ret = build_post_dev_data_response( - ctx, NULL, session_id, "Error occurred", - "SPP version not supported"); - hs20_eventlog_node(ctx, user, realm, session_id, - "Unsupported sppVersion", ret); - xml_node_get_attr_value_free(ctx->xml, version); - return ret; - } - xml_node_get_attr_value_free(ctx->xml, version); - - mo = get_node(ctx->xml, node, "supportedMOList"); - if (mo == NULL) { - ret = build_post_dev_data_response( - ctx, NULL, session_id, "Error occurred", - "Other"); - hs20_eventlog_node(ctx, user, realm, session_id, - "No supportedMOList element", ret); - return ret; - } - supp = xml_node_get_text(ctx->xml, mo); - for (pos = supp; pos && *pos; pos++) - *pos = tolower(*pos); - if (supp == NULL || - strstr(supp, URN_OMA_DM_DEVINFO) == NULL || - strstr(supp, URN_OMA_DM_DEVDETAIL) == NULL || - strstr(supp, URN_HS20_PPS) == NULL) { - xml_node_get_text_free(ctx->xml, supp); - ret = build_post_dev_data_response( - ctx, NULL, session_id, "Error occurred", - "One or more mandatory MOs not supported"); - hs20_eventlog_node(ctx, user, realm, session_id, - "Unsupported MOs", ret); - return ret; - } - xml_node_get_text_free(ctx->xml, supp); - - req_reason_buf = xml_node_get_attr_value(ctx->xml, node, - "requestReason"); - if (req_reason_buf == NULL) { - debug_print(ctx, 1, "No requestReason attribute"); - return NULL; - } - req_reason = req_reason_buf; - - redirect_uri = xml_node_get_attr_value(ctx->xml, node, "redirectURI"); - - debug_print(ctx, 1, "requestReason: %s sessionID: %s redirectURI: %s", - req_reason, session_id, redirect_uri); - snprintf(str, sizeof(str), "sppPostDevData: requestReason=%s", - req_reason); - hs20_eventlog(ctx, user, realm, session_id, str, NULL); - - devinfo = spp_get_mo(ctx, node, URN_OMA_DM_DEVINFO, &valid, &err); - if (devinfo == NULL) { - ret = build_post_dev_data_response(ctx, NULL, session_id, - "Error occurred", "Other"); - hs20_eventlog_node(ctx, user, realm, session_id, - "No DevInfo moContainer in sppPostDevData", - ret); - os_free(err); - goto out; - } - - hs20_eventlog_node(ctx, user, realm, session_id, - "Received DevInfo MO", devinfo); - if (valid == 0) { - hs20_eventlog(ctx, user, realm, session_id, - "OMA-DM DDF DTD validation errors in DevInfo MO", - err); - ret = build_post_dev_data_response(ctx, NULL, session_id, - "Error occurred", "Other"); - os_free(err); - goto out; - } - os_free(err); - if (user) - db_update_mo(ctx, user, realm, "devinfo", devinfo); - - devdetail = spp_get_mo(ctx, node, URN_OMA_DM_DEVDETAIL, &valid, &err); - if (devdetail == NULL) { - ret = build_post_dev_data_response(ctx, NULL, session_id, - "Error occurred", "Other"); - hs20_eventlog_node(ctx, user, realm, session_id, - "No DevDetail moContainer in sppPostDevData", - ret); - os_free(err); - goto out; - } - - hs20_eventlog_node(ctx, user, realm, session_id, - "Received DevDetail MO", devdetail); - if (valid == 0) { - hs20_eventlog(ctx, user, realm, session_id, - "OMA-DM DDF DTD validation errors " - "in DevDetail MO", err); - ret = build_post_dev_data_response(ctx, NULL, session_id, - "Error occurred", "Other"); - os_free(err); - goto out; - } - os_free(err); - - os_memset(wifi_mac_addr, 0, ETH_ALEN); - macaddr = get_node(ctx->xml, devdetail, - "Ext/org.wi-fi/Wi-Fi/Wi-FiMACAddress"); - if (macaddr) { - char *addr, buf[50]; - - addr = xml_node_get_text(ctx->xml, macaddr); - if (addr && hwaddr_compact_aton(addr, wifi_mac_addr) == 0) { - snprintf(buf, sizeof(buf), "DevDetail MAC address: " - MACSTR, MAC2STR(wifi_mac_addr)); - hs20_eventlog(ctx, user, realm, session_id, buf, NULL); - xml_node_get_text_free(ctx->xml, addr); - } else { - hs20_eventlog(ctx, user, realm, session_id, - "Could not extract MAC address from DevDetail", - NULL); - } - } else { - hs20_eventlog(ctx, user, realm, session_id, - "No MAC address in DevDetail", NULL); - } - - if (user) - db_update_mo(ctx, user, realm, "devdetail", devdetail); - - if (user) - mo = spp_get_mo(ctx, node, URN_HS20_PPS, &valid, &err); - else { - mo = NULL; - err = NULL; - } - if (user && mo) { - hs20_eventlog_node(ctx, user, realm, session_id, - "Received PPS MO", mo); - if (valid == 0) { - hs20_eventlog(ctx, user, realm, session_id, - "OMA-DM DDF DTD validation errors " - "in PPS MO", err); - xml_node_get_attr_value_free(ctx->xml, redirect_uri); - os_free(err); - return build_post_dev_data_response( - ctx, NULL, session_id, - "Error occurred", "Other"); - } - db_update_mo(ctx, user, realm, "pps", mo); - db_update_val(ctx, user, realm, "fetch_pps", "0", dmacc); - xml_node_free(ctx->xml, mo); - } - os_free(err); - - if (user && !mo) { - char *fetch; - int fetch_pps; - - fetch = db_get_val(ctx, user, realm, "fetch_pps", dmacc); - fetch_pps = fetch ? atoi(fetch) : 0; - free(fetch); - - if (fetch_pps) { - enum hs20_session_operation oper; - if (strcasecmp(req_reason, "Subscription remediation") - == 0) - oper = CONTINUE_SUBSCRIPTION_REMEDIATION; - else if (strcasecmp(req_reason, "Policy update") == 0) - oper = CONTINUE_POLICY_UPDATE; - else - oper = NO_OPERATION; - if (db_add_session(ctx, user, realm, session_id, NULL, - NULL, oper, NULL) < 0) - goto out; - - ret = spp_exec_upload_mo(ctx, session_id, - URN_HS20_PPS); - hs20_eventlog_node(ctx, user, realm, session_id, - "request PPS MO upload", - ret); - goto out; - } - } - - if (user && strcasecmp(req_reason, "MO upload") == 0) { - char *val = db_get_session_val(ctx, user, realm, session_id, - "operation"); - enum hs20_session_operation oper; - if (!val) { - debug_print(ctx, 1, "No session %s found to continue", - session_id); - goto out; - } - oper = atoi(val); - free(val); - if (oper == CONTINUE_SUBSCRIPTION_REMEDIATION) - req_reason = "Subscription remediation"; - else if (oper == CONTINUE_POLICY_UPDATE) - req_reason = "Policy update"; - else { - debug_print(ctx, 1, - "No pending operation in session %s", - session_id); - goto out; - } - } - - if (strcasecmp(req_reason, "Subscription registration") == 0) { - ret = hs20_subscription_registration(ctx, realm, session_id, - redirect_uri, - wifi_mac_addr); - hs20_eventlog_node(ctx, user, realm, session_id, - "subscription registration response", - ret); - goto out; - } - if (user && strcasecmp(req_reason, "Subscription remediation") == 0) { - ret = hs20_subscription_remediation(ctx, user, realm, - session_id, dmacc, - redirect_uri); - hs20_eventlog_node(ctx, user, realm, session_id, - "subscription remediation response", - ret); - goto out; - } - if (user && strcasecmp(req_reason, "Policy update") == 0) { - ret = hs20_policy_update(ctx, user, realm, session_id, dmacc); - hs20_eventlog_node(ctx, user, realm, session_id, - "policy update response", - ret); - goto out; - } - - if (strcasecmp(req_reason, "User input completed") == 0) { - db_add_session_devinfo(ctx, session_id, devinfo); - db_add_session_devdetail(ctx, session_id, devdetail); - ret = hs20_user_input_complete(ctx, user, realm, dmacc, - session_id); - hs20_eventlog_node(ctx, user, realm, session_id, - "user input completed response", ret); - goto out; - } - - if (strcasecmp(req_reason, "Certificate enrollment completed") == 0) { - ret = hs20_cert_enroll_completed(ctx, user, realm, dmacc, - session_id); - hs20_eventlog_node(ctx, user, realm, session_id, - "certificate enrollment response", ret); - goto out; - } - - if (strcasecmp(req_reason, "Certificate enrollment failed") == 0) { - ret = hs20_cert_enroll_failed(ctx, user, realm, dmacc, - session_id); - hs20_eventlog_node(ctx, user, realm, session_id, - "certificate enrollment failed response", - ret); - goto out; - } - - if (strcasecmp(req_reason, "Subscription provisioning") == 0) { - ret = hs20_sim_provisioning(ctx, user, realm, dmacc, - session_id); - hs20_eventlog_node(ctx, user, realm, session_id, - "subscription provisioning response", - ret); - goto out; - } - - debug_print(ctx, 1, "Unsupported requestReason '%s' user '%s'", - req_reason, user); -out: - xml_node_get_attr_value_free(ctx->xml, req_reason_buf); - xml_node_get_attr_value_free(ctx->xml, redirect_uri); - if (devinfo) - xml_node_free(ctx->xml, devinfo); - if (devdetail) - xml_node_free(ctx->xml, devdetail); - return ret; -} - - -static xml_node_t * build_spp_exchange_complete(struct hs20_svc *ctx, - const char *session_id, - const char *status, - const char *error_code) -{ - xml_namespace_t *ns; - xml_node_t *spp_node, *node; - - spp_node = xml_node_create_root(ctx->xml, SPP_NS_URI, "spp", &ns, - "sppExchangeComplete"); - - - xml_node_add_attr(ctx->xml, spp_node, ns, "sppVersion", "1.0"); - xml_node_add_attr(ctx->xml, spp_node, ns, "sessionID", session_id); - xml_node_add_attr(ctx->xml, spp_node, ns, "sppStatus", status); - - if (error_code) { - node = xml_node_create(ctx->xml, spp_node, ns, "sppError"); - xml_node_add_attr(ctx->xml, node, NULL, "errorCode", - error_code); - } - - return spp_node; -} - - -static int add_subscription(struct hs20_svc *ctx, const char *session_id) -{ - char *user, *realm, *pw, *pw_mm, *pps, *str; - char *osu_user, *osu_password, *eap_method; - char *policy = NULL; - char *sql; - int ret = -1; - char *free_account; - int free_acc; - char *type; - int cert = 0; - char *cert_pem, *fingerprint; - const char *method; - - user = db_get_session_val(ctx, NULL, NULL, session_id, "user"); - realm = db_get_session_val(ctx, NULL, NULL, session_id, "realm"); - pw = db_get_session_val(ctx, NULL, NULL, session_id, "password"); - pw_mm = db_get_session_val(ctx, NULL, NULL, session_id, - "machine_managed"); - pps = db_get_session_val(ctx, NULL, NULL, session_id, "pps"); - cert_pem = db_get_session_val(ctx, NULL, NULL, session_id, "cert_pem"); - fingerprint = db_get_session_val(ctx, NULL, NULL, session_id, "cert"); - type = db_get_session_val(ctx, NULL, NULL, session_id, "type"); - if (type && strcmp(type, "cert") == 0) - cert = 1; - free(type); - osu_user = db_get_session_val(ctx, NULL, NULL, session_id, "osu_user"); - osu_password = db_get_session_val(ctx, NULL, NULL, session_id, - "osu_password"); - eap_method = db_get_session_val(ctx, NULL, NULL, session_id, - "eap_method"); - - if (!user || !realm || !pw) { - debug_print(ctx, 1, "Could not find session info from DB for " - "the new subscription"); - goto out; - } - - free_account = db_get_osu_config_val(ctx, realm, "free_account"); - free_acc = free_account && strcmp(free_account, user) == 0; - free(free_account); - - policy = db_get_osu_config_val(ctx, realm, "sim_policy"); - - debug_print(ctx, 1, - "New subscription: user='%s' realm='%s' free_acc=%d", - user, realm, free_acc); - debug_print(ctx, 1, "New subscription: pps='%s'", pps); - - sql = sqlite3_mprintf("UPDATE eventlog SET user=%Q, realm=%Q WHERE " - "sessionid=%Q AND (user='' OR user IS NULL)", - user, realm, session_id); - if (sql) { - debug_print(ctx, 1, "DB: %s", sql); - if (sqlite3_exec(ctx->db, sql, NULL, NULL, NULL) != SQLITE_OK) { - debug_print(ctx, 1, "Failed to update eventlog in " - "sqlite database: %s", - sqlite3_errmsg(ctx->db)); - } - sqlite3_free(sql); - } - - if (free_acc) { - hs20_eventlog(ctx, user, realm, session_id, - "completed shared free account registration", - NULL); - ret = 0; - goto out; - } - - str = db_get_session_val(ctx, NULL, NULL, session_id, "mac_addr"); - - if (eap_method && eap_method[0]) - method = eap_method; - else - method = cert ? "TLS" : "TTLS-MSCHAPV2"; - sql = sqlite3_mprintf("INSERT INTO users(identity,realm,phase2,methods,cert,cert_pem,machine_managed,mac_addr,osu_user,osu_password,policy) VALUES (%Q,%Q,%d,%Q,%Q,%Q,%d,%Q,%Q,%Q,%Q)", - user, realm, cert ? 0 : 1, - method, - fingerprint ? fingerprint : "", - cert_pem ? cert_pem : "", - pw_mm && atoi(pw_mm) ? 1 : 0, - str ? str : "", - osu_user ? osu_user : "", - osu_password ? osu_password : "", - policy ? policy : ""); - free(str); - if (sql == NULL) - goto out; - debug_print(ctx, 1, "DB: %s", sql); - if (sqlite3_exec(ctx->db, sql, NULL, NULL, NULL) != SQLITE_OK) { - debug_print(ctx, 1, "Failed to add user in sqlite database: %s", - sqlite3_errmsg(ctx->db)); - sqlite3_free(sql); - goto out; - } - sqlite3_free(sql); - - if (cert) - ret = 0; - else - ret = update_password(ctx, user, realm, pw, 0); - if (ret < 0) { - sql = sqlite3_mprintf("DELETE FROM users WHERE identity=%Q AND realm=%Q AND (phase2=1 OR methods='TLS')", - user, realm); - if (sql) { - debug_print(ctx, 1, "DB: %s", sql); - sqlite3_exec(ctx->db, sql, NULL, NULL, NULL); - sqlite3_free(sql); - } - } - - if (pps) - db_update_mo_str(ctx, user, realm, "pps", pps); - - str = db_get_session_val(ctx, NULL, NULL, session_id, "devinfo"); - if (str) { - db_update_mo_str(ctx, user, realm, "devinfo", str); - free(str); - } - - str = db_get_session_val(ctx, NULL, NULL, session_id, "devdetail"); - if (str) { - db_update_mo_str(ctx, user, realm, "devdetail", str); - free(str); - } - - if (cert && user) { - const char *serialnum; - - str = db_get_session_val(ctx, NULL, NULL, session_id, - "mac_addr"); - - if (os_strncmp(user, "cert-", 5) == 0) - serialnum = user + 5; - else - serialnum = ""; - sql = sqlite3_mprintf("INSERT OR REPLACE INTO cert_enroll (mac_addr,user,realm,serialnum) VALUES(%Q,%Q,%Q,%Q)", - str ? str : "", user, realm ? realm : "", - serialnum); - free(str); - if (sql) { - debug_print(ctx, 1, "DB: %s", sql); - if (sqlite3_exec(ctx->db, sql, NULL, NULL, NULL) != - SQLITE_OK) { - debug_print(ctx, 1, - "Failed to add cert_enroll entry into sqlite database: %s", - sqlite3_errmsg(ctx->db)); - } - sqlite3_free(sql); - } - } - - str = db_get_session_val(ctx, NULL, NULL, session_id, - "mobile_identifier_hash"); - if (str) { - sql = sqlite3_mprintf("DELETE FROM sim_provisioning WHERE mobile_identifier_hash=%Q", - str); - if (sql) { - debug_print(ctx, 1, "DB: %s", sql); - if (sqlite3_exec(ctx->db, sql, NULL, NULL, NULL) != - SQLITE_OK) { - debug_print(ctx, 1, - "Failed to delete pending sim_provisioning entry: %s", - sqlite3_errmsg(ctx->db)); - } - sqlite3_free(sql); - } - os_free(str); - } - - if (ret == 0) { - hs20_eventlog(ctx, user, realm, session_id, - "completed subscription registration", NULL); - } - -out: - free(user); - free(realm); - free(pw); - free(pw_mm); - free(pps); - free(cert_pem); - free(fingerprint); - free(osu_user); - free(osu_password); - free(eap_method); - os_free(policy); - return ret; -} - - -static xml_node_t * hs20_spp_update_response(struct hs20_svc *ctx, - xml_node_t *node, - const char *user, - const char *realm, - const char *session_id, - int dmacc) -{ - char *status; - xml_node_t *ret; - char *val; - enum hs20_session_operation oper; - - status = xml_node_get_attr_value_ns(ctx->xml, node, SPP_NS_URI, - "sppStatus"); - if (status == NULL) { - debug_print(ctx, 1, "No sppStatus attribute"); - return NULL; - } - - debug_print(ctx, 1, "sppUpdateResponse: sppStatus: %s sessionID: %s", - status, session_id); - - val = db_get_session_val(ctx, NULL, NULL, session_id, "operation"); - if (!val) { - debug_print(ctx, 1, - "No session active for sessionID: %s", - session_id); - oper = NO_OPERATION; - } else - oper = atoi(val); - - if (strcasecmp(status, "OK") == 0) { - char *new_pw = NULL; - - xml_node_get_attr_value_free(ctx->xml, status); - - if (oper == USER_REMEDIATION) { - new_pw = db_get_session_val(ctx, user, realm, - session_id, "password"); - if (new_pw == NULL || strlen(new_pw) == 0) { - free(new_pw); - ret = build_spp_exchange_complete( - ctx, session_id, "Error occurred", - "Other"); - hs20_eventlog_node(ctx, user, realm, - session_id, "No password " - "had been assigned for " - "session", ret); - db_remove_session(ctx, user, realm, session_id); - return ret; - } - oper = UPDATE_PASSWORD; - } - if (oper == UPDATE_PASSWORD) { - if (!new_pw) { - new_pw = db_get_session_val(ctx, user, realm, - session_id, - "password"); - if (!new_pw) { - db_remove_session(ctx, user, realm, - session_id); - return NULL; - } - } - debug_print(ctx, 1, "Update user '%s' password in DB", - user); - if (update_password(ctx, user, realm, new_pw, dmacc) < - 0) { - debug_print(ctx, 1, "Failed to update user " - "'%s' password in DB", user); - ret = build_spp_exchange_complete( - ctx, session_id, "Error occurred", - "Other"); - hs20_eventlog_node(ctx, user, realm, - session_id, "Failed to " - "update database", ret); - db_remove_session(ctx, user, realm, session_id); - return ret; - } - hs20_eventlog(ctx, user, realm, - session_id, "Updated user password " - "in database", NULL); - } - if (oper == CLEAR_REMEDIATION) { - debug_print(ctx, 1, - "Clear remediation requirement for user '%s' in DB", - user); - if (clear_remediation(ctx, user, realm, dmacc) < 0) { - debug_print(ctx, 1, - "Failed to clear remediation requirement for user '%s' in DB", - user); - ret = build_spp_exchange_complete( - ctx, session_id, "Error occurred", - "Other"); - hs20_eventlog_node(ctx, user, realm, - session_id, - "Failed to update database", - ret); - db_remove_session(ctx, user, realm, session_id); - return ret; - } - hs20_eventlog(ctx, user, realm, - session_id, - "Cleared remediation requirement in database", - NULL); - } - if (oper == SUBSCRIPTION_REGISTRATION) { - if (add_subscription(ctx, session_id) < 0) { - debug_print(ctx, 1, "Failed to add " - "subscription into DB"); - ret = build_spp_exchange_complete( - ctx, session_id, "Error occurred", - "Other"); - hs20_eventlog_node(ctx, user, realm, - session_id, "Failed to " - "update database", ret); - db_remove_session(ctx, user, realm, session_id); - return ret; - } - } - if (oper == POLICY_REMEDIATION || oper == POLICY_UPDATE) { - char *val; - val = db_get_val(ctx, user, realm, "remediation", - dmacc); - if (val && strcmp(val, "policy") == 0) - db_update_val(ctx, user, realm, "remediation", - "", dmacc); - free(val); - } - if (oper == POLICY_UPDATE) - db_update_val(ctx, user, realm, "polupd_done", "1", - dmacc); - if (oper == CERT_REENROLL) { - char *new_user; - char event[200]; - - new_user = db_get_session_val(ctx, NULL, NULL, - session_id, "user"); - if (!new_user) { - debug_print(ctx, 1, - "Failed to find new user name (cert-serialnum)"); - ret = build_spp_exchange_complete( - ctx, session_id, "Error occurred", - "Other"); - hs20_eventlog_node(ctx, user, realm, - session_id, - "Failed to find new user name (cert reenroll)", - ret); - db_remove_session(ctx, NULL, NULL, session_id); - return ret; - } - - debug_print(ctx, 1, - "Update certificate user entry to use the new serial number (old=%s new=%s)", - user, new_user); - os_snprintf(event, sizeof(event), "renamed user to: %s", - new_user); - hs20_eventlog(ctx, user, realm, session_id, event, - NULL); - - if (db_update_val(ctx, user, realm, "identity", - new_user, 0) < 0 || - db_update_val(ctx, new_user, realm, "remediation", - "", 0) < 0) { - debug_print(ctx, 1, - "Failed to update user name (cert-serialnum)"); - ret = build_spp_exchange_complete( - ctx, session_id, "Error occurred", - "Other"); - hs20_eventlog_node(ctx, user, realm, - session_id, - "Failed to update user name (cert reenroll)", - ret); - db_remove_session(ctx, NULL, NULL, session_id); - os_free(new_user); - return ret; - } - - os_free(new_user); - } - ret = build_spp_exchange_complete( - ctx, session_id, - "Exchange complete, release TLS connection", NULL); - hs20_eventlog_node(ctx, user, realm, session_id, - "Exchange completed", ret); - db_remove_session(ctx, NULL, NULL, session_id); - return ret; - } - - ret = build_spp_exchange_complete(ctx, session_id, "Error occurred", - "Other"); - hs20_eventlog_node(ctx, user, realm, session_id, "Error occurred", ret); - db_remove_session(ctx, user, realm, session_id); - xml_node_get_attr_value_free(ctx->xml, status); - return ret; -} - - -#define SPP_SESSION_ID_LEN 16 - -static char * gen_spp_session_id(void) -{ - FILE *f; - int i; - char *session; - - session = os_malloc(SPP_SESSION_ID_LEN * 2 + 1); - if (session == NULL) - return NULL; - - f = fopen("/dev/urandom", "r"); - if (f == NULL) { - os_free(session); - return NULL; - } - for (i = 0; i < SPP_SESSION_ID_LEN; i++) - os_snprintf(session + i * 2, 3, "%02x", fgetc(f)); - - fclose(f); - return session; -} - -xml_node_t * hs20_spp_server_process(struct hs20_svc *ctx, xml_node_t *node, - const char *auth_user, - const char *auth_realm, int dmacc) -{ - xml_node_t *ret = NULL; - char *session_id; - const char *op_name; - char *xml_err; - char fname[200]; - - debug_dump_node(ctx, "received request", node); - - if (!dmacc && auth_user && auth_realm) { - char *real; - real = db_get_val(ctx, auth_user, auth_realm, "identity", 0); - if (!real) { - real = db_get_val(ctx, auth_user, auth_realm, - "identity", 1); - if (real) - dmacc = 1; - } - os_free(real); - } - - snprintf(fname, sizeof(fname), "%s/spp/spp.xsd", ctx->root_dir); - if (xml_validate(ctx->xml, node, fname, &xml_err) < 0) { - /* - * We may not be able to extract the sessionID from invalid - * input, but well, we can try. - */ - session_id = xml_node_get_attr_value_ns(ctx->xml, node, - SPP_NS_URI, - "sessionID"); - debug_print(ctx, 1, - "SPP message failed validation, xsd file: %s xml-error: %s", - fname, xml_err); - hs20_eventlog_node(ctx, auth_user, auth_realm, session_id, - "SPP message failed validation", node); - hs20_eventlog(ctx, auth_user, auth_realm, session_id, - "Validation errors", xml_err); - os_free(xml_err); - xml_node_get_attr_value_free(ctx->xml, session_id); - /* TODO: what to return here? */ - ret = xml_node_create_root(ctx->xml, NULL, NULL, NULL, - "SppValidationError"); - return ret; - } - - session_id = xml_node_get_attr_value_ns(ctx->xml, node, SPP_NS_URI, - "sessionID"); - if (session_id) { - char *tmp; - debug_print(ctx, 1, "Received sessionID %s", session_id); - tmp = os_strdup(session_id); - xml_node_get_attr_value_free(ctx->xml, session_id); - if (tmp == NULL) - return NULL; - session_id = tmp; - } else { - session_id = gen_spp_session_id(); - if (session_id == NULL) { - debug_print(ctx, 1, "Failed to generate sessionID"); - return NULL; - } - debug_print(ctx, 1, "Generated sessionID %s", session_id); - } - - op_name = xml_node_get_localname(ctx->xml, node); - if (op_name == NULL) { - debug_print(ctx, 1, "Could not get op_name"); - return NULL; - } - - if (strcmp(op_name, "sppPostDevData") == 0) { - hs20_eventlog_node(ctx, auth_user, auth_realm, session_id, - "sppPostDevData received and validated", - node); - ret = hs20_spp_post_dev_data(ctx, node, auth_user, auth_realm, - session_id, dmacc); - } else if (strcmp(op_name, "sppUpdateResponse") == 0) { - hs20_eventlog_node(ctx, auth_user, auth_realm, session_id, - "sppUpdateResponse received and validated", - node); - ret = hs20_spp_update_response(ctx, node, auth_user, - auth_realm, session_id, dmacc); - } else { - hs20_eventlog_node(ctx, auth_user, auth_realm, session_id, - "Unsupported SPP message received and " - "validated", node); - debug_print(ctx, 1, "Unsupported operation '%s'", op_name); - /* TODO: what to return here? */ - ret = xml_node_create_root(ctx->xml, NULL, NULL, NULL, - "SppUnknownCommandError"); - } - os_free(session_id); - - if (ret == NULL) { - /* TODO: what to return here? */ - ret = xml_node_create_root(ctx->xml, NULL, NULL, NULL, - "SppInternalError"); - } - - return ret; -} - - -int hs20_spp_server_init(struct hs20_svc *ctx) -{ - char fname[200]; - ctx->db = NULL; - snprintf(fname, sizeof(fname), "%s/AS/DB/eap_user.db", ctx->root_dir); - if (sqlite3_open(fname, &ctx->db)) { - printf("Failed to open sqlite database: %s\n", - sqlite3_errmsg(ctx->db)); - sqlite3_close(ctx->db); - return -1; - } - - return 0; -} - - -void hs20_spp_server_deinit(struct hs20_svc *ctx) -{ - sqlite3_close(ctx->db); - ctx->db = NULL; -} diff --git a/hs20/server/spp_server.h b/hs20/server/spp_server.h deleted file mode 100644 index 421974c607b8..000000000000 --- a/hs20/server/spp_server.h +++ /dev/null @@ -1,36 +0,0 @@ -/* - * Hotspot 2.0 SPP server - * Copyright (c) 2012-2013, Qualcomm Atheros, Inc. - * - * This software may be distributed under the terms of the BSD license. - * See README for more details. - */ - -#ifndef SPP_SERVER_H -#define SPP_SERVER_H - -struct hs20_svc { - const void *ctx; - struct xml_node_ctx *xml; - char *root_dir; - FILE *debug_log; - sqlite3 *db; - const char *addr; - const char *test; - const char *imsi; - const char *eap_method; - const char *id_hash; -}; - - -void debug_print(struct hs20_svc *ctx, int print, const char *fmt, ...) - __attribute__ ((format (printf, 3, 4))); -void debug_dump_node(struct hs20_svc *ctx, const char *title, xml_node_t *node); - -xml_node_t * hs20_spp_server_process(struct hs20_svc *ctx, xml_node_t *node, - const char *auth_user, - const char *auth_realm, int dmacc); -int hs20_spp_server_init(struct hs20_svc *ctx); -void hs20_spp_server_deinit(struct hs20_svc *ctx); - -#endif /* SPP_SERVER_H */ diff --git a/hs20/server/sql-example.txt b/hs20/server/sql-example.txt deleted file mode 100644 index 20dcf2f5c688..000000000000 --- a/hs20/server/sql-example.txt +++ /dev/null @@ -1,17 +0,0 @@ -INSERT INTO osu_config(realm,field,value) VALUES('example.com','fqdn','example.com'); -INSERT INTO osu_config(realm,field,value) VALUES('example.com','friendly_name','Example Operator'); -INSERT INTO osu_config(realm,field,value) VALUES('example.com','spp_http_auth_url','https://subscription-server.osu.example.com/hs20/spp.php?realm=example.com'); -INSERT INTO osu_config(realm,field,value) VALUES('example.com','trust_root_cert_url','https://osu-server.osu.example.com/hs20/files/spp-root-ca.der'); -INSERT INTO osu_config(realm,field,value) VALUES('example.com','trust_root_cert_fingerprint','5b393a9246865569485c2605c3304e48212b449367858299beba9384c4cf4647'); -INSERT INTO osu_config(realm,field,value) VALUES('example.com','aaa_trust_root_cert_url','https://osu-server.osu.example.com/hs20/files/aaa-root-ca.der'); -INSERT INTO osu_config(realm,field,value) VALUES('example.com','aaa_trust_root_cert_fingerprint','5b393a9246865569485c2605c3304e48212b449367858299beba9384c4cf4647'); -INSERT INTO osu_config(realm,field,value) VALUES('example.com','free_account','free'); -INSERT INTO osu_config(realm,field,value) VALUES('example.com','policy_url','https://subscription-server.osu.example.com/hs20/spp.php?realm=example.com'); -INSERT INTO osu_config(realm,field,value) VALUES('example.com','remediation_url','https://subscription-server.osu.example.com/hs20/remediation.php?session_id='); -INSERT INTO osu_config(realm,field,value) VALUES('example.com','free_remediation_url','https://subscription-server.osu.example.com/hs20/free-remediation.php?session_id='); -INSERT INTO osu_config(realm,field,value) VALUES('example.com','signup_url','https://subscription-server.osu.example.com/hs20/signup.php?session_id='); - - -INSERT INTO users(identity,realm,methods,password,phase2,shared) VALUES('free','example.com','TTLS-MSCHAPV2','free',1,1); - -INSERT INTO wildcards(identity,methods) VALUES('','TTLS,TLS'); diff --git a/hs20/server/sql.txt b/hs20/server/sql.txt deleted file mode 100644 index 2cc6edea4063..000000000000 --- a/hs20/server/sql.txt +++ /dev/null @@ -1,108 +0,0 @@ -CREATE TABLE eventlog( - user TEXT, - realm TEXT, - sessionid TEXT COLLATE NOCASE, - timestamp TEXT, - notes TEXT, - dump TEXT, - addr TEXT -); - -CREATE TABLE sessions( - timestamp TEXT, - id TEXT COLLATE NOCASE, - user TEXT, - realm TEXT, - password TEXT, - machine_managed BOOLEAN, - operation INTEGER, - type TEXT, - pps TEXT, - redirect_uri TEXT, - devinfo TEXT, - devdetail TEXT, - cert TEXT, - cert_pem TEXT, - mac_addr TEXT, - osu_user TEXT, - osu_password TEXT, - eap_method TEXT, - mobile_identifier_hash TEXT, - test TEXT -); - -CREATE index sessions_id_index ON sessions(id); - -CREATE TABLE osu_config( - realm TEXT, - field TEXT, - value TEXT -); - -CREATE TABLE users( - identity TEXT PRIMARY KEY, - methods TEXT, - password TEXT, - machine_managed BOOLEAN, - remediation TEXT, - phase2 INTEGER, - realm TEXT, - policy TEXT, - devinfo TEXT, - devdetail TEXT, - pps TEXT, - fetch_pps INTEGER, - osu_user TEXT, - osu_password TEXT, - shared INTEGER, - cert TEXT, - cert_pem TEXT, - t_c_timestamp INTEGER, - mac_addr TEXT, - last_msk TEXT, - polupd_done TEXT, - subrem TEXT -); - -CREATE TABLE wildcards( - identity TEXT PRIMARY KEY, - methods TEXT -); - -CREATE TABLE authlog( - timestamp TEXT, - session TEXT, - nas_ip TEXT, - username TEXT, - note TEXT -); - -CREATE TABLE pending_tc( - mac_addr TEXT PRIMARY KEY, - identity TEXT -); - -CREATE TABLE current_sessions( - mac_addr TEXT PRIMARY KEY, - identity TEXT, - start_time TEXT, - nas TEXT, - hs20_t_c_filtering BOOLEAN, - waiting_coa_ack BOOLEAN, - coa_ack_received BOOLEAN -); - -CREATE TABLE cert_enroll( - mac_addr TEXT PRIMARY KEY, - user TEXT, - realm TEXT, - serialnum TEXT -); - -CREATE TABLE sim_provisioning( - mobile_identifier_hash TEXT PRIMARY KEY, - imsi TEXT, - mac_addr TEXT, - eap_method TEXT, - timestamp TEXT -); diff --git a/hs20/server/www/add-free.php b/hs20/server/www/add-free.php deleted file mode 100644 index 1efc65563274..000000000000 --- a/hs20/server/www/add-free.php +++ /dev/null @@ -1,50 +0,0 @@ -<?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 --git a/hs20/server/www/add-mo.php b/hs20/server/www/add-mo.php deleted file mode 100644 index a3b4513531f8..000000000000 --- a/hs20/server/www/add-mo.php +++ /dev/null @@ -1,56 +0,0 @@ -<?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 --git a/hs20/server/www/cert-enroll.php b/hs20/server/www/cert-enroll.php deleted file mode 100644 index f023ca5a5b03..000000000000 --- a/hs20/server/www/cert-enroll.php +++ /dev/null @@ -1,39 +0,0 @@ -<?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 --git a/hs20/server/www/config.php b/hs20/server/www/config.php deleted file mode 100644 index 4272b102a88c..000000000000 --- a/hs20/server/www/config.php +++ /dev/null @@ -1,7 +0,0 @@ -<?php -$osu_root = "/home/user/hs20-server"; -$osu_db = "sqlite:$osu_root/AS/DB/eap_user.db"; -$t_c_file = "$osu_root/terms-and-conditions"; -$t_c_timestamp = 123456789; -$hostapd_ctrl = "udg:///home/user/hs20-server/AS/ctrl/as" -?> diff --git a/hs20/server/www/est.php b/hs20/server/www/est.php deleted file mode 100644 index b7fb260d56c4..000000000000 --- a/hs20/server/www/est.php +++ /dev/null @@ -1,232 +0,0 @@ -<?php - -require('config.php'); - -$params = explode("/", $_SERVER["PATH_INFO"], 3); -$realm = $params[1]; -$cmd = $params[2]; -$method = $_SERVER["REQUEST_METHOD"]; - -unset($user); -unset($rowid); - -$db = new PDO($osu_db); -if (!$db) { - error_log("EST: Could not access database"); - die("Could not access database"); -} - -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'); - } - - $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'); - } -} 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"]; - $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 != '10') { - error_log("EST: Unexpected operation $oper for user=$user realm=$realm"); - die("Session not found"); - } -} - - -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" || $cmd == "simplereenroll")) { - $reenroll = $cmd == "simplereenroll"; - if (!$reenroll && (!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 ($reenroll && - (!isset($user) || - !isset($_SERVER["SSL_CLIENT_VERIFY"]) || - $_SERVER["SSL_CLIENT_VERIFY"] != "SUCCESS")) { - header('HTTP/1.1 403 Forbidden'); - error_log("EST: simplereenroll - require certificate 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); - error_log("EST: sha256(DER cert): $fingerprint"); - - $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 --git a/hs20/server/www/free-remediation.php b/hs20/server/www/free-remediation.php deleted file mode 100644 index 5648b30e8d6b..000000000000 --- a/hs20/server/www/free-remediation.php +++ /dev/null @@ -1,19 +0,0 @@ -<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 --git a/hs20/server/www/free.php b/hs20/server/www/free.php deleted file mode 100644 index 8195069ed8ff..000000000000 --- a/hs20/server/www/free.php +++ /dev/null @@ -1,23 +0,0 @@ -<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 --git a/hs20/server/www/redirect.php b/hs20/server/www/redirect.php deleted file mode 100644 index 8fc9cd644273..000000000000 --- a/hs20/server/www/redirect.php +++ /dev/null @@ -1,32 +0,0 @@ -<?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 --git a/hs20/server/www/remediation-pw.php b/hs20/server/www/remediation-pw.php deleted file mode 100644 index 76fdccbdf9f7..000000000000 --- a/hs20/server/www/remediation-pw.php +++ /dev/null @@ -1,41 +0,0 @@ -<?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"); - -$pw = $_POST["password"]; -if (strlen($id) < 32 || !isset($pw)) { - die("Invalid POST data"); -} - -$row = $db->query("SELECT rowid,* FROM sessions WHERE id='$id'")->fetch(); -if ($row == false) { - die("Session not found"); -} -$user = $row['user']; -$realm = $row['realm']; - -$uri = $row['redirect_uri']; -$rowid = $row['rowid']; - -if (!$db->exec("UPDATE sessions SET password='$pw' 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 subscription remediation')"); - -header("Location: $uri", true, 302); - -?> diff --git a/hs20/server/www/remediation.php b/hs20/server/www/remediation.php deleted file mode 100644 index 3628065ac225..000000000000 --- a/hs20/server/www/remediation.php +++ /dev/null @@ -1,55 +0,0 @@ -<html> -<head> -<title>Hotspot 2.0 subscription remediation</title> -</head> -<body> - -<?php - -require('config.php'); - -$db = new PDO($osu_db); -if (!$db) { - die($sqliteerror); -} - -if (isset($_GET["session_id"])) - $id = preg_replace("/[^a-fA-F0-9]/", "", $_GET["session_id"]); -else - $id = 0; -echo "SessionID: " . $id . "<br>\n"; - -$row = $db->query("SELECT * FROM sessions WHERE id='$id'")->fetch(); -if ($row == false) { - die("Session not found"); -} - -$username = $row['user']; -echo "User: " . $username . "@" . $row['realm'] . "<br>\n"; - -$user = $db->query("SELECT machine_managed,methods FROM users WHERE identity='$username'")->fetch(); -if ($user == false) { - die("User not found"); -} - -echo "<hr><br>\n"; - -$cert = $user['methods'] == "TLS" || strncmp($username, "cert-", 5) == 0; - -if ($cert) { - echo "<a href=\"redirect.php?id=" . $_GET["session_id"] . "\">Complete user subscription remediation</a><br>\n"; -} else if ($user['machine_managed'] == "1") { - echo "<a href=\"redirect.php?id=" . $_GET["session_id"] . "\">Complete user subscription remediation</a><br>\n"; - echo "This will provide a new machine-generated password.<br>\n"; -} else { - echo "<form action=\"remediation-pw.php\" method=\"POST\">\n"; - echo "<input type=\"hidden\" name=\"id\" value=\"$id\">\n"; - echo "New password: <input type=\"password\" name=\"password\"><br>\n"; - echo "<input type=\"submit\" value=\"Change password\">\n"; - echo "</form>\n"; -} - -?> - -</body> -</html> diff --git a/hs20/server/www/signup.php b/hs20/server/www/signup.php deleted file mode 100644 index 80a9d403e8fc..000000000000 --- a/hs20/server/www/signup.php +++ /dev/null @@ -1,59 +0,0 @@ -<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,test FROM sessions WHERE id='$id'")->fetch(); -if ($row == false) { - die("Session not found for id: $id"); -} -$realm = $row['realm']; -$test = $row['test']; - -if (strlen($test) > 0) { - echo "<p style=\"color:#FF0000\">Special test functionality: $test</red></big></p>\n"; -} - -echo "<h3>Sign up for a subscription - $realm</h3>\n"; - -echo "<p>This page can be used to select between three different types of subscriptions for testing purposes.</p>\n"; - -echo "<h4>Option 1 - shared free access credential</h4>\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 "<h4>Option 2 - username/password credential</h4>\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 "<h4>Option 3 - client certificate credential</h4>\n"; - -echo "<p><a href=\"cert-enroll.php?id=$id\">Enroll a client certificate</a></p>\n" -?> - -</body> -</html> diff --git a/hs20/server/www/spp.php b/hs20/server/www/spp.php deleted file mode 100644 index c56d3d69e0ed..000000000000 --- a/hs20/server/www/spp.php +++ /dev/null @@ -1,168 +0,0 @@ -<?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"); -} - -if (isset($_GET["test"])) - $test = PREG_REPLACE("/[^0-9a-zA-Z\_\-]/i", '', $_GET["test"]); -else - $test = ""; - -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($_GET["hotspot2dot0-mobile-identifier-hash"])) { - $id_hash = $_GET["hotspot2dot0-mobile-identifier-hash"]; - $id_hash = PREG_REPLACE("/[^0-9a-h]/i", '', $id_hash); - - $db = new PDO($osu_db); - if (!$db) { - error_log("spp.php - Could not access database"); - die("Could not access database"); - } - - $row = $db->query("SELECT * FROM sim_provisioning " . - "WHERE mobile_identifier_hash='$id_hash'")->fetch(); - if (!$row) { - error_log("spp.php - SIM provisioning failed - mobile_identifier_hash not found"); - die('SIM provisioning failed - mobile_identifier_hash not found'); - } - - $imsi = $row['imsi']; - $mac_addr = $row['mac_addr']; - $eap_method = $row['eap_method']; - - $row = $db->query("SELECT COUNT(*) FROM osu_config " . - "WHERE realm='$realm'")->fetch(); - if (!$row || intval($row[0]) < 1) { - error_log("spp.php - SIM provisioning failed - realm $realm not found"); - die('SIM provisioning failed'); - } - - error_log("spp.php - SIM provisioning for IMSI $imsi"); - putenv("HS20SIMPROV=yes"); - putenv("HS20IMSI=$imsi"); - putenv("HS20MACADDR=$mac_addr"); - putenv("HS20EAPMETHOD=$eap_method"); - putenv("HS20IDHASH=$id_hash"); -} 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"); -putenv("HS20TEST=$test"); - -$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 --git a/hs20/server/www/terms.php b/hs20/server/www/terms.php deleted file mode 100644 index acba23ef1ad7..000000000000 --- a/hs20/server/www/terms.php +++ /dev/null @@ -1,87 +0,0 @@ -<?php - -require('config.php'); - -function print_header() -{ - echo "<html>\n"; - echo "<head><title>HS 2.0 Terms and Conditions</title></head>\n"; - echo "<body>\n"; -} - -$db = new PDO($osu_db); -if (!$db) { - die($sqliteerror); -} - -if (!isset($_GET["addr"])) { - die("Missing addr parameter"); -} -$addr = $_GET["addr"]; - -$accept = isset($_GET["accept"]) && $_GET["accept"] == "yes"; - -$res = $db->prepare("SELECT identity FROM pending_tc WHERE mac_addr=?"); -$res->execute(array($addr)); -$row = $res->fetch(); -if (!$row) { - die("No pending session for the specified MAC address"); -} -$identity = $row[0]; - -if (!$accept) { - print_header(); - - echo "<p>Accept the following terms and conditions by clicking here: <a href=\"terms.php?addr=$addr&accept=yes\">Accept</a></p>\n<hr>\n"; - readfile($t_c_file); -} else { - $res = $db->prepare("UPDATE users SET t_c_timestamp=? WHERE identity=?"); - if (!$res->execute(array($t_c_timestamp, $identity))) { - die("Failed to update user account."); - } - - $res = $db->prepare("DELETE FROM pending_tc WHERE mac_addr=?"); - $res->execute(array($addr)); - - $fp = fsockopen($hostapd_ctrl); - if (!$fp) { - die("Could not connect to hostapd(AS)"); - } - - fwrite($fp, "DAC_REQUEST coa $addr t_c_clear"); - fclose($fp); - - $waiting = true; - $ack = false; - for ($i = 1; $i <= 10; $i++) { - $res = $db->prepare("SELECT waiting_coa_ack,coa_ack_received FROM current_sessions WHERE mac_addr=?"); - $res->execute(array($addr)); - $row = $res->fetch(); - if (!$row) { - die("No current session for the specified MAC address"); - } - if (strlen($row[0]) > 0) - $waiting = $row[0] == 1; - if (strlen($row[1]) > 0) - $ack = $row[1] == 1; - $res->closeCursor(); - if (!$waiting) - break; - sleep(1); - } - if ($ack) { - header('X-WFA-Hotspot20-Filtering: removed'); - print_header(); - echo "<p>Terms and conditions were accepted.</p>\n"; - - echo "<P>Filtering disabled.</P>\n"; - } else { - print_header(); - echo "<P>Failed to disable filtering.</P>\n"; - } -} - -?> - -</body> -</html> diff --git a/hs20/server/www/users.php b/hs20/server/www/users.php deleted file mode 100644 index 2bd555275dda..000000000000 --- a/hs20/server/www/users.php +++ /dev/null @@ -1,377 +0,0 @@ -<?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-reenroll' && $id > 0) { - $db->exec("UPDATE users SET remediation='reenroll' 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"); -} - -if ($cmd == 'clear-t-c' && $id > 0) { - $db->exec("UPDATE users SET t_c_timestamp=NULL 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>]"; - if ($row['methods'] == 'TLS') { - echo " [<a href=\"users.php?cmd=subrem-add-reenroll&id=" . - $row['rowid'] . "\">add:reenroll</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 if ($rem == "reenroll") { - echo "Reenroll [<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"; - -if (strncmp($row['identity'], "cert-", 5) != 0) - echo "Machine managed: " . ($row['machine_managed'] == "1" ? "TRUE" : "FALSE") . "<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"; - -if (strlen($row['t_c_timestamp']) > 0) { - echo "<br>\n"; - echo "<a href=\"users.php?cmd=clear-t-c&id=" . - $row['rowid'] . - "\">Clear Terms and Conditions acceptance</a><br>\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 cellspacing=0 cellpadding=0>\n"; -echo "<tr><th>User<th>Realm<th><small>Remediation</small><th>Policy<th><small>Account type</small><th><small>Phase 2 method(s)</small><th>DevId<th>MAC Address<th>T&C\n"; - -$res = $db->query('SELECT rowid,* FROM users WHERE (phase2=1 OR methods=\'TLS\') ORDER BY identity'); -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 "-"; - } else if ($rem == "user") { - echo "User"; - } else if ($rem == "policy") { - echo "Policy"; - } else if ($rem == "free") { - echo "Free"; - } else if ($rem == "reenroll") { - echo "Reenroll"; - } else { - echo "Machine"; - } - echo "<td>" . $row['policy']; - if ($row['shared'] > 0) - echo "<td>shared"; - else - echo "<td>default"; - echo "<td><small>" . $row['methods'] . "</small>"; - echo "<td>"; - $xml = xml_parser_create(); - xml_parse_into_struct($xml, $row['devinfo'], $devinfo); - foreach($devinfo as $k) { - if ($k['tag'] == 'DEVID') { - echo "<small>" . $k['value'] . "</small>"; - break; - } - } - echo "<td><small>" . $row['mac_addr'] . "</small>"; - echo "<td><small>" . $row['t_c_timestamp'] . "</small>"; - echo "\n"; -} -echo "</table>\n"; - -} - -?> - -</html> |