15b9c547cSRui Paulo /*
25b9c547cSRui Paulo * Hotspot 2.0 SPP client
35b9c547cSRui Paulo * Copyright (c) 2012-2014, Qualcomm Atheros, Inc.
45b9c547cSRui Paulo *
55b9c547cSRui Paulo * This software may be distributed under the terms of the BSD license.
65b9c547cSRui Paulo * See README for more details.
75b9c547cSRui Paulo */
85b9c547cSRui Paulo
95b9c547cSRui Paulo #include "includes.h"
105b9c547cSRui Paulo #include <sys/stat.h>
115b9c547cSRui Paulo
125b9c547cSRui Paulo #include "common.h"
135b9c547cSRui Paulo #include "browser.h"
145b9c547cSRui Paulo #include "wpa_ctrl.h"
155b9c547cSRui Paulo #include "wpa_helpers.h"
165b9c547cSRui Paulo #include "xml-utils.h"
175b9c547cSRui Paulo #include "http-utils.h"
185b9c547cSRui Paulo #include "utils/base64.h"
195b9c547cSRui Paulo #include "crypto/crypto.h"
205b9c547cSRui Paulo #include "crypto/sha256.h"
215b9c547cSRui Paulo #include "osu_client.h"
225b9c547cSRui Paulo
235b9c547cSRui Paulo
24325151a3SRui Paulo extern const char *spp_xsd_fname;
25325151a3SRui Paulo
265b9c547cSRui Paulo static int hs20_spp_update_response(struct hs20_osu_client *ctx,
275b9c547cSRui Paulo const char *session_id,
285b9c547cSRui Paulo const char *spp_status,
295b9c547cSRui Paulo const char *error_code);
305b9c547cSRui Paulo static void hs20_policy_update_complete(
315b9c547cSRui Paulo struct hs20_osu_client *ctx, const char *pps_fname);
325b9c547cSRui Paulo
335b9c547cSRui Paulo
get_spp_attr_value(struct xml_node_ctx * ctx,xml_node_t * node,char * attr_name)345b9c547cSRui Paulo static char * get_spp_attr_value(struct xml_node_ctx *ctx, xml_node_t *node,
355b9c547cSRui Paulo char *attr_name)
365b9c547cSRui Paulo {
375b9c547cSRui Paulo return xml_node_get_attr_value_ns(ctx, node, SPP_NS_URI, attr_name);
385b9c547cSRui Paulo }
395b9c547cSRui Paulo
405b9c547cSRui Paulo
hs20_spp_validate(struct hs20_osu_client * ctx,xml_node_t * node,const char * expected_name)415b9c547cSRui Paulo static int hs20_spp_validate(struct hs20_osu_client *ctx, xml_node_t *node,
425b9c547cSRui Paulo const char *expected_name)
435b9c547cSRui Paulo {
445b9c547cSRui Paulo struct xml_node_ctx *xctx = ctx->xml;
455b9c547cSRui Paulo const char *name;
465b9c547cSRui Paulo char *err;
475b9c547cSRui Paulo int ret;
485b9c547cSRui Paulo
495b9c547cSRui Paulo if (!xml_node_is_element(xctx, node))
505b9c547cSRui Paulo return -1;
515b9c547cSRui Paulo
525b9c547cSRui Paulo name = xml_node_get_localname(xctx, node);
535b9c547cSRui Paulo if (name == NULL)
545b9c547cSRui Paulo return -1;
555b9c547cSRui Paulo
565b9c547cSRui Paulo if (strcmp(expected_name, name) != 0) {
575b9c547cSRui Paulo wpa_printf(MSG_INFO, "Unexpected SOAP method name '%s' (expected '%s')",
585b9c547cSRui Paulo name, expected_name);
595b9c547cSRui Paulo write_summary(ctx, "Unexpected SOAP method name '%s' (expected '%s')",
605b9c547cSRui Paulo name, expected_name);
615b9c547cSRui Paulo return -1;
625b9c547cSRui Paulo }
635b9c547cSRui Paulo
64325151a3SRui Paulo ret = xml_validate(xctx, node, spp_xsd_fname, &err);
655b9c547cSRui Paulo if (ret < 0) {
665b9c547cSRui Paulo wpa_printf(MSG_INFO, "XML schema validation error(s)\n%s", err);
675b9c547cSRui Paulo write_summary(ctx, "SPP XML schema validation failed");
685b9c547cSRui Paulo os_free(err);
695b9c547cSRui Paulo }
705b9c547cSRui Paulo return ret;
715b9c547cSRui Paulo }
725b9c547cSRui Paulo
735b9c547cSRui Paulo
add_mo_container(struct xml_node_ctx * ctx,xml_namespace_t * ns,xml_node_t * parent,const char * urn,const char * fname)745b9c547cSRui Paulo static void add_mo_container(struct xml_node_ctx *ctx, xml_namespace_t *ns,
755b9c547cSRui Paulo xml_node_t *parent, const char *urn,
765b9c547cSRui Paulo const char *fname)
775b9c547cSRui Paulo {
785b9c547cSRui Paulo xml_node_t *node;
795b9c547cSRui Paulo xml_node_t *fnode, *tnds;
805b9c547cSRui Paulo char *str;
815b9c547cSRui Paulo
82325151a3SRui Paulo errno = 0;
835b9c547cSRui Paulo fnode = node_from_file(ctx, fname);
84325151a3SRui Paulo if (!fnode) {
85325151a3SRui Paulo wpa_printf(MSG_ERROR,
86325151a3SRui Paulo "Failed to create XML node from file: %s, possible error: %s",
87325151a3SRui Paulo fname, strerror(errno));
885b9c547cSRui Paulo return;
89325151a3SRui Paulo }
905b9c547cSRui Paulo tnds = mo_to_tnds(ctx, fnode, 0, urn, "syncml:dmddf1.2");
915b9c547cSRui Paulo xml_node_free(ctx, fnode);
925b9c547cSRui Paulo if (!tnds)
935b9c547cSRui Paulo return;
945b9c547cSRui Paulo
955b9c547cSRui Paulo str = xml_node_to_str(ctx, tnds);
965b9c547cSRui Paulo xml_node_free(ctx, tnds);
975b9c547cSRui Paulo if (str == NULL)
985b9c547cSRui Paulo return;
995b9c547cSRui Paulo
1005b9c547cSRui Paulo node = xml_node_create_text(ctx, parent, ns, "moContainer", str);
1015b9c547cSRui Paulo if (node)
1025b9c547cSRui Paulo xml_node_add_attr(ctx, node, ns, "moURN", urn);
1035b9c547cSRui Paulo os_free(str);
1045b9c547cSRui Paulo }
1055b9c547cSRui Paulo
1065b9c547cSRui Paulo
build_spp_post_dev_data(struct hs20_osu_client * ctx,xml_namespace_t ** ret_ns,const char * session_id,const char * reason)1075b9c547cSRui Paulo static xml_node_t * build_spp_post_dev_data(struct hs20_osu_client *ctx,
1085b9c547cSRui Paulo xml_namespace_t **ret_ns,
1095b9c547cSRui Paulo const char *session_id,
1105b9c547cSRui Paulo const char *reason)
1115b9c547cSRui Paulo {
1125b9c547cSRui Paulo xml_namespace_t *ns;
1135b9c547cSRui Paulo xml_node_t *spp_node;
1145b9c547cSRui Paulo
1155b9c547cSRui Paulo write_summary(ctx, "Building sppPostDevData requestReason='%s'",
1165b9c547cSRui Paulo reason);
1175b9c547cSRui Paulo spp_node = xml_node_create_root(ctx->xml, SPP_NS_URI, "spp", &ns,
1185b9c547cSRui Paulo "sppPostDevData");
1195b9c547cSRui Paulo if (spp_node == NULL)
1205b9c547cSRui Paulo return NULL;
1215b9c547cSRui Paulo if (ret_ns)
1225b9c547cSRui Paulo *ret_ns = ns;
1235b9c547cSRui Paulo
1245b9c547cSRui Paulo xml_node_add_attr(ctx->xml, spp_node, ns, "sppVersion", "1.0");
1255b9c547cSRui Paulo xml_node_add_attr(ctx->xml, spp_node, NULL, "requestReason", reason);
1265b9c547cSRui Paulo if (session_id)
1275b9c547cSRui Paulo xml_node_add_attr(ctx->xml, spp_node, ns, "sessionID",
1285b9c547cSRui Paulo session_id);
1295b9c547cSRui Paulo xml_node_add_attr(ctx->xml, spp_node, NULL, "redirectURI",
1305b9c547cSRui Paulo "http://localhost:12345/");
1315b9c547cSRui Paulo
1325b9c547cSRui Paulo xml_node_create_text(ctx->xml, spp_node, ns, "supportedSPPVersions",
1335b9c547cSRui Paulo "1.0");
1345b9c547cSRui Paulo xml_node_create_text(ctx->xml, spp_node, ns, "supportedMOList",
1355b9c547cSRui Paulo URN_HS20_PPS " " URN_OMA_DM_DEVINFO " "
1365b9c547cSRui Paulo URN_OMA_DM_DEVDETAIL " " URN_HS20_DEVDETAIL_EXT);
1375b9c547cSRui Paulo
1385b9c547cSRui Paulo add_mo_container(ctx->xml, ns, spp_node, URN_OMA_DM_DEVINFO,
1395b9c547cSRui Paulo "devinfo.xml");
1405b9c547cSRui Paulo add_mo_container(ctx->xml, ns, spp_node, URN_OMA_DM_DEVDETAIL,
1415b9c547cSRui Paulo "devdetail.xml");
1425b9c547cSRui Paulo
1435b9c547cSRui Paulo return spp_node;
1445b9c547cSRui Paulo }
1455b9c547cSRui Paulo
1465b9c547cSRui Paulo
process_update_node(struct hs20_osu_client * ctx,xml_node_t * pps,xml_node_t * update)1475b9c547cSRui Paulo static int process_update_node(struct hs20_osu_client *ctx, xml_node_t *pps,
1485b9c547cSRui Paulo xml_node_t *update)
1495b9c547cSRui Paulo {
1505b9c547cSRui Paulo xml_node_t *node, *parent, *tnds, *unode;
1515b9c547cSRui Paulo char *str;
1525b9c547cSRui Paulo const char *name;
1535b9c547cSRui Paulo char *uri, *pos;
1545b9c547cSRui Paulo char *cdata, *cdata_end;
1555b9c547cSRui Paulo size_t fqdn_len;
1565b9c547cSRui Paulo
1575b9c547cSRui Paulo wpa_printf(MSG_INFO, "Processing updateNode");
1585b9c547cSRui Paulo debug_dump_node(ctx, "updateNode", update);
1595b9c547cSRui Paulo
1605b9c547cSRui Paulo uri = get_spp_attr_value(ctx->xml, update, "managementTreeURI");
1615b9c547cSRui Paulo if (uri == NULL) {
1625b9c547cSRui Paulo wpa_printf(MSG_INFO, "No managementTreeURI present");
1635b9c547cSRui Paulo return -1;
1645b9c547cSRui Paulo }
1655b9c547cSRui Paulo wpa_printf(MSG_INFO, "managementTreeUri: '%s'", uri);
1665b9c547cSRui Paulo
1675b9c547cSRui Paulo name = os_strrchr(uri, '/');
1685b9c547cSRui Paulo if (name == NULL) {
1695b9c547cSRui Paulo wpa_printf(MSG_INFO, "Unexpected URI");
1705b9c547cSRui Paulo xml_node_get_attr_value_free(ctx->xml, uri);
1715b9c547cSRui Paulo return -1;
1725b9c547cSRui Paulo }
1735b9c547cSRui Paulo name++;
1745b9c547cSRui Paulo wpa_printf(MSG_INFO, "Update interior node: '%s'", name);
1755b9c547cSRui Paulo
1765b9c547cSRui Paulo str = xml_node_get_text(ctx->xml, update);
1775b9c547cSRui Paulo if (str == NULL) {
1785b9c547cSRui Paulo wpa_printf(MSG_INFO, "Could not extract MO text");
1795b9c547cSRui Paulo xml_node_get_attr_value_free(ctx->xml, uri);
1805b9c547cSRui Paulo return -1;
1815b9c547cSRui Paulo }
1825b9c547cSRui Paulo wpa_printf(MSG_DEBUG, "[hs20] nodeContainer text: '%s'", str);
1835b9c547cSRui Paulo cdata = strstr(str, "<![CDATA[");
1845b9c547cSRui Paulo cdata_end = strstr(str, "]]>");
1855b9c547cSRui Paulo if (cdata && cdata_end && cdata_end > cdata &&
1865b9c547cSRui Paulo cdata < strstr(str, "MgmtTree") &&
1875b9c547cSRui Paulo cdata_end > strstr(str, "/MgmtTree")) {
1885b9c547cSRui Paulo char *tmp;
1895b9c547cSRui Paulo wpa_printf(MSG_DEBUG, "[hs20] Removing extra CDATA container");
1905b9c547cSRui Paulo tmp = strdup(cdata + 9);
1915b9c547cSRui Paulo if (tmp) {
1925b9c547cSRui Paulo cdata_end = strstr(tmp, "]]>");
1935b9c547cSRui Paulo if (cdata_end)
1945b9c547cSRui Paulo *cdata_end = '\0';
1955b9c547cSRui Paulo wpa_printf(MSG_DEBUG, "[hs20] nodeContainer text with CDATA container removed: '%s'",
1965b9c547cSRui Paulo tmp);
1975b9c547cSRui Paulo tnds = xml_node_from_buf(ctx->xml, tmp);
1985b9c547cSRui Paulo free(tmp);
1995b9c547cSRui Paulo } else
2005b9c547cSRui Paulo tnds = NULL;
2015b9c547cSRui Paulo } else
2025b9c547cSRui Paulo tnds = xml_node_from_buf(ctx->xml, str);
2035b9c547cSRui Paulo xml_node_get_text_free(ctx->xml, str);
2045b9c547cSRui Paulo if (tnds == NULL) {
2055b9c547cSRui Paulo wpa_printf(MSG_INFO, "[hs20] Could not parse nodeContainer text");
2065b9c547cSRui Paulo xml_node_get_attr_value_free(ctx->xml, uri);
2075b9c547cSRui Paulo return -1;
2085b9c547cSRui Paulo }
2095b9c547cSRui Paulo
2105b9c547cSRui Paulo unode = tnds_to_mo(ctx->xml, tnds);
2115b9c547cSRui Paulo xml_node_free(ctx->xml, tnds);
2125b9c547cSRui Paulo if (unode == NULL) {
2135b9c547cSRui Paulo wpa_printf(MSG_INFO, "[hs20] Could not parse nodeContainer TNDS text");
2145b9c547cSRui Paulo xml_node_get_attr_value_free(ctx->xml, uri);
2155b9c547cSRui Paulo return -1;
2165b9c547cSRui Paulo }
2175b9c547cSRui Paulo
2185b9c547cSRui Paulo debug_dump_node(ctx, "Parsed TNDS", unode);
2195b9c547cSRui Paulo
2205b9c547cSRui Paulo if (get_node_uri(ctx->xml, unode, name) == NULL) {
2215b9c547cSRui Paulo wpa_printf(MSG_INFO, "[hs20] %s node not found", name);
2225b9c547cSRui Paulo xml_node_free(ctx->xml, unode);
2235b9c547cSRui Paulo xml_node_get_attr_value_free(ctx->xml, uri);
2245b9c547cSRui Paulo return -1;
2255b9c547cSRui Paulo }
2265b9c547cSRui Paulo
2275b9c547cSRui Paulo if (os_strncasecmp(uri, "./Wi-Fi/", 8) != 0) {
2285b9c547cSRui Paulo wpa_printf(MSG_INFO, "Do not allow update outside ./Wi-Fi");
2295b9c547cSRui Paulo xml_node_free(ctx->xml, unode);
2305b9c547cSRui Paulo xml_node_get_attr_value_free(ctx->xml, uri);
2315b9c547cSRui Paulo return -1;
2325b9c547cSRui Paulo }
2335b9c547cSRui Paulo pos = uri + 8;
2345b9c547cSRui Paulo
2355b9c547cSRui Paulo if (ctx->fqdn == NULL) {
2365b9c547cSRui Paulo wpa_printf(MSG_INFO, "FQDN not known");
2375b9c547cSRui Paulo xml_node_free(ctx->xml, unode);
2385b9c547cSRui Paulo xml_node_get_attr_value_free(ctx->xml, uri);
2395b9c547cSRui Paulo return -1;
2405b9c547cSRui Paulo }
2415b9c547cSRui Paulo fqdn_len = os_strlen(ctx->fqdn);
2425b9c547cSRui Paulo if (os_strncasecmp(pos, ctx->fqdn, fqdn_len) != 0 ||
2435b9c547cSRui Paulo pos[fqdn_len] != '/') {
2445b9c547cSRui Paulo wpa_printf(MSG_INFO, "Do not allow update outside ./Wi-Fi/%s",
2455b9c547cSRui Paulo ctx->fqdn);
2465b9c547cSRui Paulo xml_node_free(ctx->xml, unode);
2475b9c547cSRui Paulo xml_node_get_attr_value_free(ctx->xml, uri);
2485b9c547cSRui Paulo return -1;
2495b9c547cSRui Paulo }
2505b9c547cSRui Paulo pos += fqdn_len + 1;
2515b9c547cSRui Paulo
2525b9c547cSRui Paulo if (os_strncasecmp(pos, "PerProviderSubscription/", 24) != 0) {
2535b9c547cSRui Paulo wpa_printf(MSG_INFO, "Do not allow update outside ./Wi-Fi/%s/PerProviderSubscription",
2545b9c547cSRui Paulo ctx->fqdn);
2555b9c547cSRui Paulo xml_node_free(ctx->xml, unode);
2565b9c547cSRui Paulo xml_node_get_attr_value_free(ctx->xml, uri);
2575b9c547cSRui Paulo return -1;
2585b9c547cSRui Paulo }
2595b9c547cSRui Paulo pos += 24;
2605b9c547cSRui Paulo
2615b9c547cSRui Paulo wpa_printf(MSG_INFO, "Update command for PPS node %s", pos);
2625b9c547cSRui Paulo
2635b9c547cSRui Paulo node = get_node(ctx->xml, pps, pos);
2645b9c547cSRui Paulo if (node) {
2655b9c547cSRui Paulo parent = xml_node_get_parent(ctx->xml, node);
2665b9c547cSRui Paulo xml_node_detach(ctx->xml, node);
2675b9c547cSRui Paulo wpa_printf(MSG_INFO, "Replace '%s' node", name);
2685b9c547cSRui Paulo } else {
2695b9c547cSRui Paulo char *pos2;
2705b9c547cSRui Paulo pos2 = os_strrchr(pos, '/');
2715b9c547cSRui Paulo if (pos2 == NULL) {
2725b9c547cSRui Paulo parent = pps;
2735b9c547cSRui Paulo } else {
2745b9c547cSRui Paulo *pos2 = '\0';
2755b9c547cSRui Paulo parent = get_node(ctx->xml, pps, pos);
2765b9c547cSRui Paulo }
2775b9c547cSRui Paulo if (parent == NULL) {
2785b9c547cSRui Paulo wpa_printf(MSG_INFO, "Could not find parent %s", pos);
2795b9c547cSRui Paulo xml_node_free(ctx->xml, unode);
2805b9c547cSRui Paulo xml_node_get_attr_value_free(ctx->xml, uri);
2815b9c547cSRui Paulo return -1;
2825b9c547cSRui Paulo }
2835b9c547cSRui Paulo wpa_printf(MSG_INFO, "Add '%s' node", name);
2845b9c547cSRui Paulo }
2855b9c547cSRui Paulo xml_node_add_child(ctx->xml, parent, unode);
2865b9c547cSRui Paulo
2875b9c547cSRui Paulo xml_node_get_attr_value_free(ctx->xml, uri);
2885b9c547cSRui Paulo
2895b9c547cSRui Paulo return 0;
2905b9c547cSRui Paulo }
2915b9c547cSRui Paulo
2925b9c547cSRui Paulo
update_pps(struct hs20_osu_client * ctx,xml_node_t * update,const char * pps_fname,xml_node_t * pps)2935b9c547cSRui Paulo static int update_pps(struct hs20_osu_client *ctx, xml_node_t *update,
2945b9c547cSRui Paulo const char *pps_fname, xml_node_t *pps)
2955b9c547cSRui Paulo {
2965b9c547cSRui Paulo wpa_printf(MSG_INFO, "Updating PPS based on updateNode element(s)");
2975b9c547cSRui Paulo xml_node_for_each_sibling(ctx->xml, update) {
2985b9c547cSRui Paulo xml_node_for_each_check(ctx->xml, update);
2995b9c547cSRui Paulo if (process_update_node(ctx, pps, update) < 0)
3005b9c547cSRui Paulo return -1;
3015b9c547cSRui Paulo }
3025b9c547cSRui Paulo
3035b9c547cSRui Paulo return update_pps_file(ctx, pps_fname, pps);
3045b9c547cSRui Paulo }
3055b9c547cSRui Paulo
3065b9c547cSRui Paulo
hs20_sub_rem_complete(struct hs20_osu_client * ctx,const char * pps_fname)3075b9c547cSRui Paulo static void hs20_sub_rem_complete(struct hs20_osu_client *ctx,
3085b9c547cSRui Paulo const char *pps_fname)
3095b9c547cSRui Paulo {
3105b9c547cSRui Paulo /*
3115b9c547cSRui Paulo * Update wpa_supplicant credentials and reconnect using updated
3125b9c547cSRui Paulo * information.
3135b9c547cSRui Paulo */
3145b9c547cSRui Paulo wpa_printf(MSG_INFO, "Updating wpa_supplicant credentials");
3155b9c547cSRui Paulo cmd_set_pps(ctx, pps_fname);
3165b9c547cSRui Paulo
3175b9c547cSRui Paulo if (ctx->no_reconnect)
3185b9c547cSRui Paulo return;
3195b9c547cSRui Paulo
3205b9c547cSRui Paulo wpa_printf(MSG_INFO, "Requesting reconnection with updated configuration");
3215b9c547cSRui Paulo if (wpa_command(ctx->ifname, "INTERWORKING_SELECT auto") < 0)
3225b9c547cSRui Paulo wpa_printf(MSG_ERROR, "Failed to request wpa_supplicant to reconnect");
3235b9c547cSRui Paulo }
3245b9c547cSRui Paulo
3255b9c547cSRui Paulo
hs20_spp_upload_mo(struct hs20_osu_client * ctx,xml_node_t * cmd,const char * session_id,const char * pps_fname)3265b9c547cSRui Paulo static xml_node_t * hs20_spp_upload_mo(struct hs20_osu_client *ctx,
3275b9c547cSRui Paulo xml_node_t *cmd,
3285b9c547cSRui Paulo const char *session_id,
3295b9c547cSRui Paulo const char *pps_fname)
3305b9c547cSRui Paulo {
3315b9c547cSRui Paulo xml_namespace_t *ns;
3325b9c547cSRui Paulo xml_node_t *node, *ret_node;
3335b9c547cSRui Paulo char *urn;
3345b9c547cSRui Paulo
3355b9c547cSRui Paulo urn = get_spp_attr_value(ctx->xml, cmd, "moURN");
3365b9c547cSRui Paulo if (!urn) {
3375b9c547cSRui Paulo wpa_printf(MSG_INFO, "No URN included");
3385b9c547cSRui Paulo return NULL;
3395b9c547cSRui Paulo }
3405b9c547cSRui Paulo wpa_printf(MSG_INFO, "Upload MO request - URN=%s", urn);
3415b9c547cSRui Paulo if (strcasecmp(urn, URN_HS20_PPS) != 0) {
3425b9c547cSRui Paulo wpa_printf(MSG_INFO, "Unsupported moURN");
3435b9c547cSRui Paulo xml_node_get_attr_value_free(ctx->xml, urn);
3445b9c547cSRui Paulo return NULL;
3455b9c547cSRui Paulo }
3465b9c547cSRui Paulo xml_node_get_attr_value_free(ctx->xml, urn);
3475b9c547cSRui Paulo
3485b9c547cSRui Paulo if (!pps_fname) {
3495b9c547cSRui Paulo wpa_printf(MSG_INFO, "PPS file name no known");
3505b9c547cSRui Paulo return NULL;
3515b9c547cSRui Paulo }
3525b9c547cSRui Paulo
3535b9c547cSRui Paulo node = build_spp_post_dev_data(ctx, &ns, session_id,
3545b9c547cSRui Paulo "MO upload");
3555b9c547cSRui Paulo if (node == NULL)
3565b9c547cSRui Paulo return NULL;
3575b9c547cSRui Paulo add_mo_container(ctx->xml, ns, node, URN_HS20_PPS, pps_fname);
3585b9c547cSRui Paulo
3595b9c547cSRui Paulo ret_node = soap_send_receive(ctx->http, node);
3605b9c547cSRui Paulo if (ret_node == NULL)
3615b9c547cSRui Paulo return NULL;
3625b9c547cSRui Paulo
3635b9c547cSRui Paulo debug_dump_node(ctx, "Received response to MO upload", ret_node);
3645b9c547cSRui Paulo
3655b9c547cSRui Paulo if (hs20_spp_validate(ctx, ret_node, "sppPostDevDataResponse") < 0) {
3665b9c547cSRui Paulo wpa_printf(MSG_INFO, "SPP validation failed");
3675b9c547cSRui Paulo xml_node_free(ctx->xml, ret_node);
3685b9c547cSRui Paulo return NULL;
3695b9c547cSRui Paulo }
3705b9c547cSRui Paulo
3715b9c547cSRui Paulo return ret_node;
3725b9c547cSRui Paulo }
3735b9c547cSRui Paulo
3745b9c547cSRui Paulo
hs20_add_mo(struct hs20_osu_client * ctx,xml_node_t * add_mo,char * fname,size_t fname_len)3755b9c547cSRui Paulo static int hs20_add_mo(struct hs20_osu_client *ctx, xml_node_t *add_mo,
3765b9c547cSRui Paulo char *fname, size_t fname_len)
3775b9c547cSRui Paulo {
3785b9c547cSRui Paulo char *uri, *urn;
3795b9c547cSRui Paulo int ret;
3805b9c547cSRui Paulo
3815b9c547cSRui Paulo debug_dump_node(ctx, "Received addMO", add_mo);
3825b9c547cSRui Paulo
3835b9c547cSRui Paulo urn = get_spp_attr_value(ctx->xml, add_mo, "moURN");
3845b9c547cSRui Paulo if (urn == NULL) {
3855b9c547cSRui Paulo wpa_printf(MSG_INFO, "[hs20] No moURN in addMO");
3865b9c547cSRui Paulo return -1;
3875b9c547cSRui Paulo }
3885b9c547cSRui Paulo wpa_printf(MSG_INFO, "addMO - moURN: '%s'", urn);
3895b9c547cSRui Paulo if (strcasecmp(urn, URN_HS20_PPS) != 0) {
3905b9c547cSRui Paulo wpa_printf(MSG_INFO, "[hs20] Unsupported MO in addMO");
3915b9c547cSRui Paulo xml_node_get_attr_value_free(ctx->xml, urn);
3925b9c547cSRui Paulo return -1;
3935b9c547cSRui Paulo }
3945b9c547cSRui Paulo xml_node_get_attr_value_free(ctx->xml, urn);
3955b9c547cSRui Paulo
3965b9c547cSRui Paulo uri = get_spp_attr_value(ctx->xml, add_mo, "managementTreeURI");
3975b9c547cSRui Paulo if (uri == NULL) {
3985b9c547cSRui Paulo wpa_printf(MSG_INFO, "[hs20] No managementTreeURI in addMO");
3995b9c547cSRui Paulo return -1;
4005b9c547cSRui Paulo }
4015b9c547cSRui Paulo wpa_printf(MSG_INFO, "addMO - managementTreeURI: '%s'", uri);
4025b9c547cSRui Paulo
4035b9c547cSRui Paulo ret = hs20_add_pps_mo(ctx, uri, add_mo, fname, fname_len);
4045b9c547cSRui Paulo xml_node_get_attr_value_free(ctx->xml, uri);
4055b9c547cSRui Paulo return ret;
4065b9c547cSRui Paulo }
4075b9c547cSRui Paulo
4085b9c547cSRui Paulo
process_spp_user_input_response(struct hs20_osu_client * ctx,const char * session_id,xml_node_t * add_mo)4095b9c547cSRui Paulo static int process_spp_user_input_response(struct hs20_osu_client *ctx,
4105b9c547cSRui Paulo const char *session_id,
4115b9c547cSRui Paulo xml_node_t *add_mo)
4125b9c547cSRui Paulo {
4135b9c547cSRui Paulo int ret;
4145b9c547cSRui Paulo char fname[300];
4155b9c547cSRui Paulo
4165b9c547cSRui Paulo debug_dump_node(ctx, "addMO", add_mo);
4175b9c547cSRui Paulo
4185b9c547cSRui Paulo wpa_printf(MSG_INFO, "Subscription registration completed");
4195b9c547cSRui Paulo
4205b9c547cSRui Paulo if (hs20_add_mo(ctx, add_mo, fname, sizeof(fname)) < 0) {
4215b9c547cSRui Paulo wpa_printf(MSG_INFO, "Could not add MO");
4225b9c547cSRui Paulo ret = hs20_spp_update_response(
4235b9c547cSRui Paulo ctx, session_id,
4245b9c547cSRui Paulo "Error occurred",
4255b9c547cSRui Paulo "MO addition or update failed");
4265b9c547cSRui Paulo return 0;
4275b9c547cSRui Paulo }
4285b9c547cSRui Paulo
4295b9c547cSRui Paulo ret = hs20_spp_update_response(ctx, session_id, "OK", NULL);
4305b9c547cSRui Paulo if (ret == 0)
4315b9c547cSRui Paulo hs20_sub_rem_complete(ctx, fname);
4325b9c547cSRui Paulo
4335b9c547cSRui Paulo return 0;
4345b9c547cSRui Paulo }
4355b9c547cSRui Paulo
4365b9c547cSRui Paulo
hs20_spp_user_input_completed(struct hs20_osu_client * ctx,const char * session_id)4375b9c547cSRui Paulo static xml_node_t * hs20_spp_user_input_completed(struct hs20_osu_client *ctx,
4385b9c547cSRui Paulo const char *session_id)
4395b9c547cSRui Paulo {
4405b9c547cSRui Paulo xml_node_t *node, *ret_node;
4415b9c547cSRui Paulo
4425b9c547cSRui Paulo node = build_spp_post_dev_data(ctx, NULL, session_id,
4435b9c547cSRui Paulo "User input completed");
4445b9c547cSRui Paulo if (node == NULL)
4455b9c547cSRui Paulo return NULL;
4465b9c547cSRui Paulo
4475b9c547cSRui Paulo ret_node = soap_send_receive(ctx->http, node);
4485b9c547cSRui Paulo if (!ret_node) {
4495b9c547cSRui Paulo if (soap_reinit_client(ctx->http) < 0)
4505b9c547cSRui Paulo return NULL;
4515b9c547cSRui Paulo wpa_printf(MSG_INFO, "Try to finish with re-opened connection");
4525b9c547cSRui Paulo node = build_spp_post_dev_data(ctx, NULL, session_id,
4535b9c547cSRui Paulo "User input completed");
4545b9c547cSRui Paulo if (node == NULL)
4555b9c547cSRui Paulo return NULL;
4565b9c547cSRui Paulo ret_node = soap_send_receive(ctx->http, node);
4575b9c547cSRui Paulo if (ret_node == NULL)
4585b9c547cSRui Paulo return NULL;
4595b9c547cSRui Paulo wpa_printf(MSG_INFO, "Continue with new connection");
4605b9c547cSRui Paulo }
4615b9c547cSRui Paulo
4625b9c547cSRui Paulo if (hs20_spp_validate(ctx, ret_node, "sppPostDevDataResponse") < 0) {
4635b9c547cSRui Paulo wpa_printf(MSG_INFO, "SPP validation failed");
4645b9c547cSRui Paulo xml_node_free(ctx->xml, ret_node);
4655b9c547cSRui Paulo return NULL;
4665b9c547cSRui Paulo }
4675b9c547cSRui Paulo
4685b9c547cSRui Paulo return ret_node;
4695b9c547cSRui Paulo }
4705b9c547cSRui Paulo
4715b9c547cSRui Paulo
hs20_spp_get_certificate(struct hs20_osu_client * ctx,xml_node_t * cmd,const char * session_id,const char * pps_fname)4725b9c547cSRui Paulo static xml_node_t * hs20_spp_get_certificate(struct hs20_osu_client *ctx,
4735b9c547cSRui Paulo xml_node_t *cmd,
4745b9c547cSRui Paulo const char *session_id,
4755b9c547cSRui Paulo const char *pps_fname)
4765b9c547cSRui Paulo {
4775b9c547cSRui Paulo xml_namespace_t *ns;
4785b9c547cSRui Paulo xml_node_t *node, *ret_node;
4795b9c547cSRui Paulo int res;
4805b9c547cSRui Paulo
4815b9c547cSRui Paulo wpa_printf(MSG_INFO, "Client certificate enrollment");
4825b9c547cSRui Paulo
4835b9c547cSRui Paulo res = osu_get_certificate(ctx, cmd);
4845b9c547cSRui Paulo if (res < 0)
4855b9c547cSRui Paulo wpa_printf(MSG_INFO, "EST simpleEnroll failed");
4865b9c547cSRui Paulo
4875b9c547cSRui Paulo node = build_spp_post_dev_data(ctx, &ns, session_id,
4885b9c547cSRui Paulo res == 0 ?
4895b9c547cSRui Paulo "Certificate enrollment completed" :
4905b9c547cSRui Paulo "Certificate enrollment failed");
4915b9c547cSRui Paulo if (node == NULL)
4925b9c547cSRui Paulo return NULL;
4935b9c547cSRui Paulo
4945b9c547cSRui Paulo ret_node = soap_send_receive(ctx->http, node);
4955b9c547cSRui Paulo if (ret_node == NULL)
4965b9c547cSRui Paulo return NULL;
4975b9c547cSRui Paulo
4985b9c547cSRui Paulo debug_dump_node(ctx, "Received response to certificate enrollment "
4995b9c547cSRui Paulo "completed", ret_node);
5005b9c547cSRui Paulo
5015b9c547cSRui Paulo if (hs20_spp_validate(ctx, ret_node, "sppPostDevDataResponse") < 0) {
5025b9c547cSRui Paulo wpa_printf(MSG_INFO, "SPP validation failed");
5035b9c547cSRui Paulo xml_node_free(ctx->xml, ret_node);
5045b9c547cSRui Paulo return NULL;
5055b9c547cSRui Paulo }
5065b9c547cSRui Paulo
5075b9c547cSRui Paulo return ret_node;
5085b9c547cSRui Paulo }
5095b9c547cSRui Paulo
5105b9c547cSRui Paulo
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)5115b9c547cSRui Paulo static int hs20_spp_exec(struct hs20_osu_client *ctx, xml_node_t *exec,
5125b9c547cSRui Paulo const char *session_id, const char *pps_fname,
5135b9c547cSRui Paulo xml_node_t *pps, xml_node_t **ret_node)
5145b9c547cSRui Paulo {
5155b9c547cSRui Paulo xml_node_t *cmd;
5165b9c547cSRui Paulo const char *name;
5175b9c547cSRui Paulo char *uri;
5185b9c547cSRui Paulo char *id = strdup(session_id);
5195b9c547cSRui Paulo
5205b9c547cSRui Paulo if (id == NULL)
5215b9c547cSRui Paulo return -1;
5225b9c547cSRui Paulo
5235b9c547cSRui Paulo *ret_node = NULL;
5245b9c547cSRui Paulo
5255b9c547cSRui Paulo debug_dump_node(ctx, "exec", exec);
5265b9c547cSRui Paulo
5275b9c547cSRui Paulo xml_node_for_each_child(ctx->xml, cmd, exec) {
5285b9c547cSRui Paulo xml_node_for_each_check(ctx->xml, cmd);
5295b9c547cSRui Paulo break;
5305b9c547cSRui Paulo }
5315b9c547cSRui Paulo if (!cmd) {
5325b9c547cSRui Paulo wpa_printf(MSG_INFO, "exec command element not found (cmd=%p)",
5335b9c547cSRui Paulo cmd);
5345b9c547cSRui Paulo free(id);
5355b9c547cSRui Paulo return -1;
5365b9c547cSRui Paulo }
5375b9c547cSRui Paulo
5385b9c547cSRui Paulo name = xml_node_get_localname(ctx->xml, cmd);
5395b9c547cSRui Paulo
5405b9c547cSRui Paulo if (strcasecmp(name, "launchBrowserToURI") == 0) {
5415b9c547cSRui Paulo int res;
5425b9c547cSRui Paulo uri = xml_node_get_text(ctx->xml, cmd);
5435b9c547cSRui Paulo if (!uri) {
5445b9c547cSRui Paulo wpa_printf(MSG_INFO, "No URI found");
5455b9c547cSRui Paulo free(id);
5465b9c547cSRui Paulo return -1;
5475b9c547cSRui Paulo }
5485b9c547cSRui Paulo wpa_printf(MSG_INFO, "Launch browser to URI '%s'", uri);
5495b9c547cSRui Paulo write_summary(ctx, "Launch browser to URI '%s'", uri);
550*c1d255d3SCy Schubert res = hs20_web_browser(uri, 1);
5515b9c547cSRui Paulo xml_node_get_text_free(ctx->xml, uri);
5525b9c547cSRui Paulo if (res > 0) {
5535b9c547cSRui Paulo wpa_printf(MSG_INFO, "User response in browser completed successfully - sessionid='%s'",
5545b9c547cSRui Paulo id);
5555b9c547cSRui Paulo write_summary(ctx, "User response in browser completed successfully");
5565b9c547cSRui Paulo *ret_node = hs20_spp_user_input_completed(ctx, id);
5575b9c547cSRui Paulo free(id);
5585b9c547cSRui Paulo return *ret_node ? 0 : -1;
5595b9c547cSRui Paulo } else {
5605b9c547cSRui Paulo wpa_printf(MSG_INFO, "Failed to receive user response");
5615b9c547cSRui Paulo write_summary(ctx, "Failed to receive user response");
5625b9c547cSRui Paulo hs20_spp_update_response(
5635b9c547cSRui Paulo ctx, id, "Error occurred", "Other");
5645b9c547cSRui Paulo free(id);
5655b9c547cSRui Paulo return -1;
5665b9c547cSRui Paulo }
5675b9c547cSRui Paulo }
5685b9c547cSRui Paulo
5695b9c547cSRui Paulo if (strcasecmp(name, "uploadMO") == 0) {
5705b9c547cSRui Paulo if (pps_fname == NULL)
5715b9c547cSRui Paulo return -1;
5725b9c547cSRui Paulo *ret_node = hs20_spp_upload_mo(ctx, cmd, id,
5735b9c547cSRui Paulo pps_fname);
5745b9c547cSRui Paulo free(id);
5755b9c547cSRui Paulo return *ret_node ? 0 : -1;
5765b9c547cSRui Paulo }
5775b9c547cSRui Paulo
5785b9c547cSRui Paulo if (strcasecmp(name, "getCertificate") == 0) {
5795b9c547cSRui Paulo *ret_node = hs20_spp_get_certificate(ctx, cmd, id,
5805b9c547cSRui Paulo pps_fname);
5815b9c547cSRui Paulo free(id);
5825b9c547cSRui Paulo return *ret_node ? 0 : -1;
5835b9c547cSRui Paulo }
5845b9c547cSRui Paulo
5855b9c547cSRui Paulo wpa_printf(MSG_INFO, "Unsupported exec command: '%s'", name);
5865b9c547cSRui Paulo free(id);
5875b9c547cSRui Paulo return -1;
5885b9c547cSRui Paulo }
5895b9c547cSRui Paulo
5905b9c547cSRui Paulo
5915b9c547cSRui Paulo enum spp_post_dev_data_use {
5925b9c547cSRui Paulo SPP_SUBSCRIPTION_REMEDIATION,
5935b9c547cSRui Paulo SPP_POLICY_UPDATE,
5945b9c547cSRui Paulo SPP_SUBSCRIPTION_REGISTRATION,
5955b9c547cSRui Paulo };
5965b9c547cSRui Paulo
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)5975b9c547cSRui Paulo static void process_spp_post_dev_data_response(
5985b9c547cSRui Paulo struct hs20_osu_client *ctx,
5995b9c547cSRui Paulo enum spp_post_dev_data_use use, xml_node_t *node,
6005b9c547cSRui Paulo const char *pps_fname, xml_node_t *pps)
6015b9c547cSRui Paulo {
6025b9c547cSRui Paulo xml_node_t *child;
6035b9c547cSRui Paulo char *status = NULL;
6045b9c547cSRui Paulo xml_node_t *update = NULL, *exec = NULL, *add_mo = NULL, *no_mo = NULL;
6055b9c547cSRui Paulo char *session_id = NULL;
6065b9c547cSRui Paulo
6075b9c547cSRui Paulo debug_dump_node(ctx, "sppPostDevDataResponse node", node);
6085b9c547cSRui Paulo
6095b9c547cSRui Paulo status = get_spp_attr_value(ctx->xml, node, "sppStatus");
6105b9c547cSRui Paulo if (status == NULL) {
6115b9c547cSRui Paulo wpa_printf(MSG_INFO, "No sppStatus attribute");
6125b9c547cSRui Paulo goto out;
6135b9c547cSRui Paulo }
6145b9c547cSRui Paulo write_summary(ctx, "Received sppPostDevDataResponse sppStatus='%s'",
6155b9c547cSRui Paulo status);
6165b9c547cSRui Paulo
6175b9c547cSRui Paulo session_id = get_spp_attr_value(ctx->xml, node, "sessionID");
6185b9c547cSRui Paulo if (session_id == NULL) {
6195b9c547cSRui Paulo wpa_printf(MSG_INFO, "No sessionID attribute");
6205b9c547cSRui Paulo goto out;
6215b9c547cSRui Paulo }
6225b9c547cSRui Paulo
6235b9c547cSRui Paulo wpa_printf(MSG_INFO, "[hs20] sppPostDevDataResponse - sppStatus: '%s' sessionID: '%s'",
6245b9c547cSRui Paulo status, session_id);
6255b9c547cSRui Paulo
6265b9c547cSRui Paulo xml_node_for_each_child(ctx->xml, child, node) {
6275b9c547cSRui Paulo const char *name;
6285b9c547cSRui Paulo xml_node_for_each_check(ctx->xml, child);
6295b9c547cSRui Paulo debug_dump_node(ctx, "child", child);
6305b9c547cSRui Paulo name = xml_node_get_localname(ctx->xml, child);
6315b9c547cSRui Paulo wpa_printf(MSG_INFO, "localname: '%s'", name);
6325b9c547cSRui Paulo if (!update && strcasecmp(name, "updateNode") == 0)
6335b9c547cSRui Paulo update = child;
6345b9c547cSRui Paulo if (!exec && strcasecmp(name, "exec") == 0)
6355b9c547cSRui Paulo exec = child;
6365b9c547cSRui Paulo if (!add_mo && strcasecmp(name, "addMO") == 0)
6375b9c547cSRui Paulo add_mo = child;
6385b9c547cSRui Paulo if (!no_mo && strcasecmp(name, "noMOUpdate") == 0)
6395b9c547cSRui Paulo no_mo = child;
6405b9c547cSRui Paulo }
6415b9c547cSRui Paulo
6425b9c547cSRui Paulo if (use == SPP_SUBSCRIPTION_REMEDIATION &&
6435b9c547cSRui Paulo strcasecmp(status,
6445b9c547cSRui Paulo "Remediation complete, request sppUpdateResponse") == 0)
6455b9c547cSRui Paulo {
6465b9c547cSRui Paulo int res, ret;
6475b9c547cSRui Paulo if (!update && !no_mo) {
6485b9c547cSRui Paulo wpa_printf(MSG_INFO, "No updateNode or noMOUpdate element");
6495b9c547cSRui Paulo goto out;
6505b9c547cSRui Paulo }
6515b9c547cSRui Paulo wpa_printf(MSG_INFO, "Subscription remediation completed");
6525b9c547cSRui Paulo res = update_pps(ctx, update, pps_fname, pps);
6535b9c547cSRui Paulo if (res < 0)
6545b9c547cSRui Paulo wpa_printf(MSG_INFO, "Failed to update PPS MO");
6555b9c547cSRui Paulo ret = hs20_spp_update_response(
6565b9c547cSRui Paulo ctx, session_id,
6575b9c547cSRui Paulo res < 0 ? "Error occurred" : "OK",
6585b9c547cSRui Paulo res < 0 ? "MO addition or update failed" : NULL);
6595b9c547cSRui Paulo if (res == 0 && ret == 0)
6605b9c547cSRui Paulo hs20_sub_rem_complete(ctx, pps_fname);
6615b9c547cSRui Paulo goto out;
6625b9c547cSRui Paulo }
6635b9c547cSRui Paulo
6645b9c547cSRui Paulo if (use == SPP_SUBSCRIPTION_REMEDIATION &&
6655b9c547cSRui Paulo strcasecmp(status, "Exchange complete, release TLS connection") ==
6665b9c547cSRui Paulo 0) {
6675b9c547cSRui Paulo if (!no_mo) {
6685b9c547cSRui Paulo wpa_printf(MSG_INFO, "No noMOUpdate element");
6695b9c547cSRui Paulo goto out;
6705b9c547cSRui Paulo }
6715b9c547cSRui Paulo wpa_printf(MSG_INFO, "Subscription remediation completed (no MO update)");
6725b9c547cSRui Paulo goto out;
6735b9c547cSRui Paulo }
6745b9c547cSRui Paulo
6755b9c547cSRui Paulo if (use == SPP_POLICY_UPDATE &&
6765b9c547cSRui Paulo strcasecmp(status, "Update complete, request sppUpdateResponse") ==
6775b9c547cSRui Paulo 0) {
6785b9c547cSRui Paulo int res, ret;
6795b9c547cSRui Paulo wpa_printf(MSG_INFO, "Policy update received - update PPS");
6805b9c547cSRui Paulo res = update_pps(ctx, update, pps_fname, pps);
6815b9c547cSRui Paulo ret = hs20_spp_update_response(
6825b9c547cSRui Paulo ctx, session_id,
6835b9c547cSRui Paulo res < 0 ? "Error occurred" : "OK",
6845b9c547cSRui Paulo res < 0 ? "MO addition or update failed" : NULL);
6855b9c547cSRui Paulo if (res == 0 && ret == 0)
6865b9c547cSRui Paulo hs20_policy_update_complete(ctx, pps_fname);
6875b9c547cSRui Paulo goto out;
6885b9c547cSRui Paulo }
6895b9c547cSRui Paulo
6905b9c547cSRui Paulo if (use == SPP_SUBSCRIPTION_REGISTRATION &&
6915b9c547cSRui Paulo strcasecmp(status, "Provisioning complete, request "
6925b9c547cSRui Paulo "sppUpdateResponse") == 0) {
6935b9c547cSRui Paulo if (!add_mo) {
6945b9c547cSRui Paulo wpa_printf(MSG_INFO, "No addMO element - not sure what to do next");
6955b9c547cSRui Paulo goto out;
6965b9c547cSRui Paulo }
6975b9c547cSRui Paulo process_spp_user_input_response(ctx, session_id, add_mo);
6985b9c547cSRui Paulo node = NULL;
6995b9c547cSRui Paulo goto out;
7005b9c547cSRui Paulo }
7015b9c547cSRui Paulo
7025b9c547cSRui Paulo if (strcasecmp(status, "No update available at this time") == 0) {
7035b9c547cSRui Paulo wpa_printf(MSG_INFO, "No update available at this time");
7045b9c547cSRui Paulo goto out;
7055b9c547cSRui Paulo }
7065b9c547cSRui Paulo
7075b9c547cSRui Paulo if (strcasecmp(status, "OK") == 0) {
7085b9c547cSRui Paulo int res;
7095b9c547cSRui Paulo xml_node_t *ret;
7105b9c547cSRui Paulo
7115b9c547cSRui Paulo if (!exec) {
7125b9c547cSRui Paulo wpa_printf(MSG_INFO, "No exec element - not sure what to do next");
7135b9c547cSRui Paulo goto out;
7145b9c547cSRui Paulo }
7155b9c547cSRui Paulo res = hs20_spp_exec(ctx, exec, session_id,
7165b9c547cSRui Paulo pps_fname, pps, &ret);
7175b9c547cSRui Paulo /* xml_node_free(ctx->xml, node); */
7185b9c547cSRui Paulo node = NULL;
7195b9c547cSRui Paulo if (res == 0 && ret)
7205b9c547cSRui Paulo process_spp_post_dev_data_response(ctx, use,
7215b9c547cSRui Paulo ret, pps_fname, pps);
7225b9c547cSRui Paulo goto out;
7235b9c547cSRui Paulo }
7245b9c547cSRui Paulo
7255b9c547cSRui Paulo if (strcasecmp(status, "Error occurred") == 0) {
7265b9c547cSRui Paulo xml_node_t *err;
7275b9c547cSRui Paulo char *code = NULL;
7285b9c547cSRui Paulo err = get_node(ctx->xml, node, "sppError");
7295b9c547cSRui Paulo if (err)
7305b9c547cSRui Paulo code = xml_node_get_attr_value(ctx->xml, err,
7315b9c547cSRui Paulo "errorCode");
7325b9c547cSRui Paulo wpa_printf(MSG_INFO, "Error occurred - errorCode=%s",
7335b9c547cSRui Paulo code ? code : "N/A");
7345b9c547cSRui Paulo xml_node_get_attr_value_free(ctx->xml, code);
7355b9c547cSRui Paulo goto out;
7365b9c547cSRui Paulo }
7375b9c547cSRui Paulo
7385b9c547cSRui Paulo wpa_printf(MSG_INFO,
7395b9c547cSRui Paulo "[hs20] Unsupported sppPostDevDataResponse sppStatus '%s'",
7405b9c547cSRui Paulo status);
7415b9c547cSRui Paulo out:
7425b9c547cSRui Paulo xml_node_get_attr_value_free(ctx->xml, status);
7435b9c547cSRui Paulo xml_node_get_attr_value_free(ctx->xml, session_id);
7445b9c547cSRui Paulo xml_node_free(ctx->xml, node);
7455b9c547cSRui Paulo }
7465b9c547cSRui Paulo
7475b9c547cSRui Paulo
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)7485b9c547cSRui Paulo static int spp_post_dev_data(struct hs20_osu_client *ctx,
7495b9c547cSRui Paulo enum spp_post_dev_data_use use,
7505b9c547cSRui Paulo const char *reason,
7515b9c547cSRui Paulo const char *pps_fname, xml_node_t *pps)
7525b9c547cSRui Paulo {
7535b9c547cSRui Paulo xml_node_t *payload;
7545b9c547cSRui Paulo xml_node_t *ret_node;
7555b9c547cSRui Paulo
7565b9c547cSRui Paulo payload = build_spp_post_dev_data(ctx, NULL, NULL, reason);
7575b9c547cSRui Paulo if (payload == NULL)
7585b9c547cSRui Paulo return -1;
7595b9c547cSRui Paulo
7605b9c547cSRui Paulo ret_node = soap_send_receive(ctx->http, payload);
7615b9c547cSRui Paulo if (!ret_node) {
7625b9c547cSRui Paulo const char *err = http_get_err(ctx->http);
7635b9c547cSRui Paulo if (err) {
7645b9c547cSRui Paulo wpa_printf(MSG_INFO, "HTTP error: %s", err);
7655b9c547cSRui Paulo write_result(ctx, "HTTP error: %s", err);
7665b9c547cSRui Paulo } else {
7675b9c547cSRui Paulo write_summary(ctx, "Failed to send SOAP message");
7685b9c547cSRui Paulo }
7695b9c547cSRui Paulo return -1;
7705b9c547cSRui Paulo }
7715b9c547cSRui Paulo
7725b9c547cSRui Paulo if (hs20_spp_validate(ctx, ret_node, "sppPostDevDataResponse") < 0) {
7735b9c547cSRui Paulo wpa_printf(MSG_INFO, "SPP validation failed");
7745b9c547cSRui Paulo xml_node_free(ctx->xml, ret_node);
7755b9c547cSRui Paulo return -1;
7765b9c547cSRui Paulo }
7775b9c547cSRui Paulo
7785b9c547cSRui Paulo process_spp_post_dev_data_response(ctx, use, ret_node,
7795b9c547cSRui Paulo pps_fname, pps);
7805b9c547cSRui Paulo return 0;
7815b9c547cSRui Paulo }
7825b9c547cSRui Paulo
7835b9c547cSRui Paulo
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)7845b9c547cSRui Paulo void spp_sub_rem(struct hs20_osu_client *ctx, const char *address,
7855b9c547cSRui Paulo const char *pps_fname,
7865b9c547cSRui Paulo const char *client_cert, const char *client_key,
7875b9c547cSRui Paulo const char *cred_username, const char *cred_password,
7885b9c547cSRui Paulo xml_node_t *pps)
7895b9c547cSRui Paulo {
7905b9c547cSRui Paulo wpa_printf(MSG_INFO, "SPP subscription remediation");
7915b9c547cSRui Paulo write_summary(ctx, "SPP subscription remediation");
7925b9c547cSRui Paulo
7935b9c547cSRui Paulo os_free(ctx->server_url);
7945b9c547cSRui Paulo ctx->server_url = os_strdup(address);
7955b9c547cSRui Paulo
7965b9c547cSRui Paulo if (soap_init_client(ctx->http, address, ctx->ca_fname,
7975b9c547cSRui Paulo cred_username, cred_password, client_cert,
7985b9c547cSRui Paulo client_key) == 0) {
7995b9c547cSRui Paulo spp_post_dev_data(ctx, SPP_SUBSCRIPTION_REMEDIATION,
8005b9c547cSRui Paulo "Subscription remediation", pps_fname, pps);
8015b9c547cSRui Paulo }
8025b9c547cSRui Paulo }
8035b9c547cSRui Paulo
8045b9c547cSRui Paulo
hs20_policy_update_complete(struct hs20_osu_client * ctx,const char * pps_fname)8055b9c547cSRui Paulo static void hs20_policy_update_complete(struct hs20_osu_client *ctx,
8065b9c547cSRui Paulo const char *pps_fname)
8075b9c547cSRui Paulo {
8085b9c547cSRui Paulo wpa_printf(MSG_INFO, "Policy update completed");
8095b9c547cSRui Paulo
8105b9c547cSRui Paulo /*
8115b9c547cSRui Paulo * Update wpa_supplicant credentials and reconnect using updated
8125b9c547cSRui Paulo * information.
8135b9c547cSRui Paulo */
8145b9c547cSRui Paulo wpa_printf(MSG_INFO, "Updating wpa_supplicant credentials");
8155b9c547cSRui Paulo cmd_set_pps(ctx, pps_fname);
8165b9c547cSRui Paulo
8175b9c547cSRui Paulo wpa_printf(MSG_INFO, "Requesting reconnection with updated configuration");
8185b9c547cSRui Paulo if (wpa_command(ctx->ifname, "INTERWORKING_SELECT auto") < 0)
8195b9c547cSRui Paulo wpa_printf(MSG_ERROR, "Failed to request wpa_supplicant to reconnect");
8205b9c547cSRui Paulo }
8215b9c547cSRui Paulo
8225b9c547cSRui Paulo
process_spp_exchange_complete(struct hs20_osu_client * ctx,xml_node_t * node)8235b9c547cSRui Paulo static int process_spp_exchange_complete(struct hs20_osu_client *ctx,
8245b9c547cSRui Paulo xml_node_t *node)
8255b9c547cSRui Paulo {
8265b9c547cSRui Paulo char *status, *session_id;
8275b9c547cSRui Paulo
8285b9c547cSRui Paulo debug_dump_node(ctx, "sppExchangeComplete", node);
8295b9c547cSRui Paulo
8305b9c547cSRui Paulo status = get_spp_attr_value(ctx->xml, node, "sppStatus");
8315b9c547cSRui Paulo if (status == NULL) {
8325b9c547cSRui Paulo wpa_printf(MSG_INFO, "No sppStatus attribute");
8335b9c547cSRui Paulo return -1;
8345b9c547cSRui Paulo }
8355b9c547cSRui Paulo write_summary(ctx, "Received sppExchangeComplete sppStatus='%s'",
8365b9c547cSRui Paulo status);
8375b9c547cSRui Paulo
8385b9c547cSRui Paulo session_id = get_spp_attr_value(ctx->xml, node, "sessionID");
8395b9c547cSRui Paulo if (session_id == NULL) {
8405b9c547cSRui Paulo wpa_printf(MSG_INFO, "No sessionID attribute");
8415b9c547cSRui Paulo xml_node_get_attr_value_free(ctx->xml, status);
8425b9c547cSRui Paulo return -1;
8435b9c547cSRui Paulo }
8445b9c547cSRui Paulo
8455b9c547cSRui Paulo wpa_printf(MSG_INFO, "[hs20] sppStatus: '%s' sessionID: '%s'",
8465b9c547cSRui Paulo status, session_id);
8475b9c547cSRui Paulo xml_node_get_attr_value_free(ctx->xml, session_id);
8485b9c547cSRui Paulo
8495b9c547cSRui Paulo if (strcasecmp(status, "Exchange complete, release TLS connection") ==
8505b9c547cSRui Paulo 0) {
8515b9c547cSRui Paulo xml_node_get_attr_value_free(ctx->xml, status);
8525b9c547cSRui Paulo return 0;
8535b9c547cSRui Paulo }
8545b9c547cSRui Paulo
8555b9c547cSRui Paulo wpa_printf(MSG_INFO, "Unexpected sppStatus '%s'", status);
8565b9c547cSRui Paulo write_summary(ctx, "Unexpected sppStatus '%s'", status);
8575b9c547cSRui Paulo xml_node_get_attr_value_free(ctx->xml, status);
8585b9c547cSRui Paulo return -1;
8595b9c547cSRui Paulo }
8605b9c547cSRui Paulo
8615b9c547cSRui Paulo
build_spp_update_response(struct hs20_osu_client * ctx,const char * session_id,const char * spp_status,const char * error_code)8625b9c547cSRui Paulo static xml_node_t * build_spp_update_response(struct hs20_osu_client *ctx,
8635b9c547cSRui Paulo const char *session_id,
8645b9c547cSRui Paulo const char *spp_status,
8655b9c547cSRui Paulo const char *error_code)
8665b9c547cSRui Paulo {
8675b9c547cSRui Paulo xml_namespace_t *ns;
8685b9c547cSRui Paulo xml_node_t *spp_node, *node;
8695b9c547cSRui Paulo
8705b9c547cSRui Paulo spp_node = xml_node_create_root(ctx->xml, SPP_NS_URI, "spp", &ns,
8715b9c547cSRui Paulo "sppUpdateResponse");
8725b9c547cSRui Paulo if (spp_node == NULL)
8735b9c547cSRui Paulo return NULL;
8745b9c547cSRui Paulo
8755b9c547cSRui Paulo xml_node_add_attr(ctx->xml, spp_node, ns, "sppVersion", "1.0");
8765b9c547cSRui Paulo xml_node_add_attr(ctx->xml, spp_node, ns, "sessionID", session_id);
8775b9c547cSRui Paulo xml_node_add_attr(ctx->xml, spp_node, ns, "sppStatus", spp_status);
8785b9c547cSRui Paulo
8795b9c547cSRui Paulo if (error_code) {
8805b9c547cSRui Paulo node = xml_node_create(ctx->xml, spp_node, ns, "sppError");
8815b9c547cSRui Paulo if (node)
8825b9c547cSRui Paulo xml_node_add_attr(ctx->xml, node, NULL, "errorCode",
8835b9c547cSRui Paulo error_code);
8845b9c547cSRui Paulo }
8855b9c547cSRui Paulo
8865b9c547cSRui Paulo return spp_node;
8875b9c547cSRui Paulo }
8885b9c547cSRui Paulo
8895b9c547cSRui Paulo
hs20_spp_update_response(struct hs20_osu_client * ctx,const char * session_id,const char * spp_status,const char * error_code)8905b9c547cSRui Paulo static int hs20_spp_update_response(struct hs20_osu_client *ctx,
8915b9c547cSRui Paulo const char *session_id,
8925b9c547cSRui Paulo const char *spp_status,
8935b9c547cSRui Paulo const char *error_code)
8945b9c547cSRui Paulo {
8955b9c547cSRui Paulo xml_node_t *node, *ret_node;
8965b9c547cSRui Paulo int ret;
8975b9c547cSRui Paulo
8985b9c547cSRui Paulo write_summary(ctx, "Building sppUpdateResponse sppStatus='%s' error_code='%s'",
8995b9c547cSRui Paulo spp_status, error_code);
9005b9c547cSRui Paulo node = build_spp_update_response(ctx, session_id, spp_status,
9015b9c547cSRui Paulo error_code);
9025b9c547cSRui Paulo if (node == NULL)
9035b9c547cSRui Paulo return -1;
9045b9c547cSRui Paulo ret_node = soap_send_receive(ctx->http, node);
9055b9c547cSRui Paulo if (!ret_node) {
9065b9c547cSRui Paulo if (soap_reinit_client(ctx->http) < 0)
9075b9c547cSRui Paulo return -1;
9085b9c547cSRui Paulo wpa_printf(MSG_INFO, "Try to finish with re-opened connection");
9095b9c547cSRui Paulo node = build_spp_update_response(ctx, session_id, spp_status,
9105b9c547cSRui Paulo error_code);
9115b9c547cSRui Paulo if (node == NULL)
9125b9c547cSRui Paulo return -1;
9135b9c547cSRui Paulo ret_node = soap_send_receive(ctx->http, node);
9145b9c547cSRui Paulo if (ret_node == NULL)
9155b9c547cSRui Paulo return -1;
9165b9c547cSRui Paulo wpa_printf(MSG_INFO, "Continue with new connection");
9175b9c547cSRui Paulo }
9185b9c547cSRui Paulo
9195b9c547cSRui Paulo if (hs20_spp_validate(ctx, ret_node, "sppExchangeComplete") < 0) {
9205b9c547cSRui Paulo wpa_printf(MSG_INFO, "SPP validation failed");
9215b9c547cSRui Paulo xml_node_free(ctx->xml, ret_node);
9225b9c547cSRui Paulo return -1;
9235b9c547cSRui Paulo }
9245b9c547cSRui Paulo
9255b9c547cSRui Paulo ret = process_spp_exchange_complete(ctx, ret_node);
9265b9c547cSRui Paulo xml_node_free(ctx->xml, ret_node);
9275b9c547cSRui Paulo return ret;
9285b9c547cSRui Paulo }
9295b9c547cSRui Paulo
9305b9c547cSRui Paulo
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)9315b9c547cSRui Paulo void spp_pol_upd(struct hs20_osu_client *ctx, const char *address,
9325b9c547cSRui Paulo const char *pps_fname,
9335b9c547cSRui Paulo const char *client_cert, const char *client_key,
9345b9c547cSRui Paulo const char *cred_username, const char *cred_password,
9355b9c547cSRui Paulo xml_node_t *pps)
9365b9c547cSRui Paulo {
9375b9c547cSRui Paulo wpa_printf(MSG_INFO, "SPP policy update");
9385b9c547cSRui Paulo write_summary(ctx, "SPP policy update");
9395b9c547cSRui Paulo
9405b9c547cSRui Paulo os_free(ctx->server_url);
9415b9c547cSRui Paulo ctx->server_url = os_strdup(address);
9425b9c547cSRui Paulo
9435b9c547cSRui Paulo if (soap_init_client(ctx->http, address, ctx->ca_fname, cred_username,
9445b9c547cSRui Paulo cred_password, client_cert, client_key) == 0) {
9455b9c547cSRui Paulo spp_post_dev_data(ctx, SPP_POLICY_UPDATE, "Policy update",
9465b9c547cSRui Paulo pps_fname, pps);
9475b9c547cSRui Paulo }
9485b9c547cSRui Paulo }
9495b9c547cSRui Paulo
9505b9c547cSRui Paulo
cmd_prov(struct hs20_osu_client * ctx,const char * url)9515b9c547cSRui Paulo int cmd_prov(struct hs20_osu_client *ctx, const char *url)
9525b9c547cSRui Paulo {
9535b9c547cSRui Paulo unlink("Cert/est_cert.der");
9545b9c547cSRui Paulo unlink("Cert/est_cert.pem");
9555b9c547cSRui Paulo
9565b9c547cSRui Paulo if (url == NULL) {
9575b9c547cSRui Paulo wpa_printf(MSG_INFO, "Invalid prov command (missing URL)");
9585b9c547cSRui Paulo return -1;
9595b9c547cSRui Paulo }
9605b9c547cSRui Paulo
961325151a3SRui Paulo wpa_printf(MSG_INFO,
962325151a3SRui Paulo "Credential provisioning requested - URL: %s ca_fname: %s",
963325151a3SRui Paulo url, ctx->ca_fname ? ctx->ca_fname : "N/A");
9645b9c547cSRui Paulo
9655b9c547cSRui Paulo os_free(ctx->server_url);
9665b9c547cSRui Paulo ctx->server_url = os_strdup(url);
9675b9c547cSRui Paulo
9685b9c547cSRui Paulo if (soap_init_client(ctx->http, url, ctx->ca_fname, NULL, NULL, NULL,
9695b9c547cSRui Paulo NULL) < 0)
9705b9c547cSRui Paulo return -1;
9715b9c547cSRui Paulo spp_post_dev_data(ctx, SPP_SUBSCRIPTION_REGISTRATION,
9725b9c547cSRui Paulo "Subscription registration", NULL, NULL);
9735b9c547cSRui Paulo
9745b9c547cSRui Paulo return ctx->pps_cred_set ? 0 : -1;
9755b9c547cSRui Paulo }
9765b9c547cSRui Paulo
9775b9c547cSRui Paulo
cmd_sim_prov(struct hs20_osu_client * ctx,const char * url)9785b9c547cSRui Paulo int cmd_sim_prov(struct hs20_osu_client *ctx, const char *url)
9795b9c547cSRui Paulo {
9805b9c547cSRui Paulo if (url == NULL) {
9815b9c547cSRui Paulo wpa_printf(MSG_INFO, "Invalid prov command (missing URL)");
9825b9c547cSRui Paulo return -1;
9835b9c547cSRui Paulo }
9845b9c547cSRui Paulo
9855b9c547cSRui Paulo wpa_printf(MSG_INFO, "SIM provisioning requested");
9865b9c547cSRui Paulo
9875b9c547cSRui Paulo os_free(ctx->server_url);
9885b9c547cSRui Paulo ctx->server_url = os_strdup(url);
9895b9c547cSRui Paulo
9905b9c547cSRui Paulo wpa_printf(MSG_INFO, "Wait for IP address before starting SIM provisioning");
9915b9c547cSRui Paulo
9925b9c547cSRui Paulo if (wait_ip_addr(ctx->ifname, 15) < 0) {
9935b9c547cSRui Paulo wpa_printf(MSG_INFO, "Could not get IP address for WLAN - try connection anyway");
9945b9c547cSRui Paulo }
9955b9c547cSRui Paulo
9965b9c547cSRui Paulo if (soap_init_client(ctx->http, url, ctx->ca_fname, NULL, NULL, NULL,
9975b9c547cSRui Paulo NULL) < 0)
9985b9c547cSRui Paulo return -1;
9995b9c547cSRui Paulo spp_post_dev_data(ctx, SPP_SUBSCRIPTION_REGISTRATION,
10005b9c547cSRui Paulo "Subscription provisioning", NULL, NULL);
10015b9c547cSRui Paulo
10025b9c547cSRui Paulo return ctx->pps_cred_set ? 0 : -1;
10035b9c547cSRui Paulo }
1004