Home | History | Annotate | Line # | Download | only in client
spp_client.c revision 1.1.1.1.4.1
      1          1.1  christos /*
      2          1.1  christos  * Hotspot 2.0 SPP client
      3          1.1  christos  * Copyright (c) 2012-2014, Qualcomm Atheros, Inc.
      4          1.1  christos  *
      5          1.1  christos  * This software may be distributed under the terms of the BSD license.
      6          1.1  christos  * See README for more details.
      7          1.1  christos  */
      8          1.1  christos 
      9          1.1  christos #include "includes.h"
     10          1.1  christos #include <sys/stat.h>
     11          1.1  christos 
     12          1.1  christos #include "common.h"
     13          1.1  christos #include "browser.h"
     14          1.1  christos #include "wpa_ctrl.h"
     15          1.1  christos #include "wpa_helpers.h"
     16          1.1  christos #include "xml-utils.h"
     17          1.1  christos #include "http-utils.h"
     18          1.1  christos #include "utils/base64.h"
     19          1.1  christos #include "crypto/crypto.h"
     20          1.1  christos #include "crypto/sha256.h"
     21          1.1  christos #include "osu_client.h"
     22          1.1  christos 
     23          1.1  christos 
     24  1.1.1.1.4.1  pgoyette extern const char *spp_xsd_fname;
     25  1.1.1.1.4.1  pgoyette 
     26          1.1  christos static int hs20_spp_update_response(struct hs20_osu_client *ctx,
     27          1.1  christos 				    const char *session_id,
     28          1.1  christos 				    const char *spp_status,
     29          1.1  christos 				    const char *error_code);
     30          1.1  christos static void hs20_policy_update_complete(
     31          1.1  christos 	struct hs20_osu_client *ctx, const char *pps_fname);
     32          1.1  christos 
     33          1.1  christos 
     34          1.1  christos static char * get_spp_attr_value(struct xml_node_ctx *ctx, xml_node_t *node,
     35          1.1  christos 				 char *attr_name)
     36          1.1  christos {
     37          1.1  christos 	return xml_node_get_attr_value_ns(ctx, node, SPP_NS_URI, attr_name);
     38          1.1  christos }
     39          1.1  christos 
     40          1.1  christos 
     41          1.1  christos static int hs20_spp_validate(struct hs20_osu_client *ctx, xml_node_t *node,
     42          1.1  christos 			     const char *expected_name)
     43          1.1  christos {
     44          1.1  christos 	struct xml_node_ctx *xctx = ctx->xml;
     45          1.1  christos 	const char *name;
     46          1.1  christos 	char *err;
     47          1.1  christos 	int ret;
     48          1.1  christos 
     49          1.1  christos 	if (!xml_node_is_element(xctx, node))
     50          1.1  christos 		return -1;
     51          1.1  christos 
     52          1.1  christos 	name = xml_node_get_localname(xctx, node);
     53          1.1  christos 	if (name == NULL)
     54          1.1  christos 		return -1;
     55          1.1  christos 
     56          1.1  christos 	if (strcmp(expected_name, name) != 0) {
     57          1.1  christos 		wpa_printf(MSG_INFO, "Unexpected SOAP method name '%s' (expected '%s')",
     58          1.1  christos 			   name, expected_name);
     59          1.1  christos 		write_summary(ctx, "Unexpected SOAP method name '%s' (expected '%s')",
     60          1.1  christos 			      name, expected_name);
     61          1.1  christos 		return -1;
     62          1.1  christos 	}
     63          1.1  christos 
     64  1.1.1.1.4.1  pgoyette 	ret = xml_validate(xctx, node, spp_xsd_fname, &err);
     65          1.1  christos 	if (ret < 0) {
     66          1.1  christos 		wpa_printf(MSG_INFO, "XML schema validation error(s)\n%s", err);
     67          1.1  christos 		write_summary(ctx, "SPP XML schema validation failed");
     68          1.1  christos 		os_free(err);
     69          1.1  christos 	}
     70          1.1  christos 	return ret;
     71          1.1  christos }
     72          1.1  christos 
     73          1.1  christos 
     74          1.1  christos static void add_mo_container(struct xml_node_ctx *ctx, xml_namespace_t *ns,
     75          1.1  christos 			     xml_node_t *parent, const char *urn,
     76          1.1  christos 			     const char *fname)
     77          1.1  christos {
     78          1.1  christos 	xml_node_t *node;
     79          1.1  christos 	xml_node_t *fnode, *tnds;
     80          1.1  christos 	char *str;
     81          1.1  christos 
     82  1.1.1.1.4.1  pgoyette 	errno = 0;
     83          1.1  christos 	fnode = node_from_file(ctx, fname);
     84  1.1.1.1.4.1  pgoyette 	if (!fnode) {
     85  1.1.1.1.4.1  pgoyette 		wpa_printf(MSG_ERROR,
     86  1.1.1.1.4.1  pgoyette 			   "Failed to create XML node from file: %s, possible error: %s",
     87  1.1.1.1.4.1  pgoyette 			   fname, strerror(errno));
     88          1.1  christos 		return;
     89  1.1.1.1.4.1  pgoyette 	}
     90          1.1  christos 	tnds = mo_to_tnds(ctx, fnode, 0, urn, "syncml:dmddf1.2");
     91          1.1  christos 	xml_node_free(ctx, fnode);
     92          1.1  christos 	if (!tnds)
     93          1.1  christos 		return;
     94          1.1  christos 
     95          1.1  christos 	str = xml_node_to_str(ctx, tnds);
     96          1.1  christos 	xml_node_free(ctx, tnds);
     97          1.1  christos 	if (str == NULL)
     98          1.1  christos 		return;
     99          1.1  christos 
    100          1.1  christos 	node = xml_node_create_text(ctx, parent, ns, "moContainer", str);
    101          1.1  christos 	if (node)
    102          1.1  christos 		xml_node_add_attr(ctx, node, ns, "moURN", urn);
    103          1.1  christos 	os_free(str);
    104          1.1  christos }
    105          1.1  christos 
    106          1.1  christos 
    107          1.1  christos static xml_node_t * build_spp_post_dev_data(struct hs20_osu_client *ctx,
    108          1.1  christos 					    xml_namespace_t **ret_ns,
    109          1.1  christos 					    const char *session_id,
    110          1.1  christos 					    const char *reason)
    111          1.1  christos {
    112          1.1  christos 	xml_namespace_t *ns;
    113          1.1  christos 	xml_node_t *spp_node;
    114          1.1  christos 
    115          1.1  christos 	write_summary(ctx, "Building sppPostDevData requestReason='%s'",
    116          1.1  christos 		      reason);
    117          1.1  christos 	spp_node = xml_node_create_root(ctx->xml, SPP_NS_URI, "spp", &ns,
    118          1.1  christos 					"sppPostDevData");
    119          1.1  christos 	if (spp_node == NULL)
    120          1.1  christos 		return NULL;
    121          1.1  christos 	if (ret_ns)
    122          1.1  christos 		*ret_ns = ns;
    123          1.1  christos 
    124          1.1  christos 	xml_node_add_attr(ctx->xml, spp_node, ns, "sppVersion", "1.0");
    125          1.1  christos 	xml_node_add_attr(ctx->xml, spp_node, NULL, "requestReason", reason);
    126          1.1  christos 	if (session_id)
    127          1.1  christos 		xml_node_add_attr(ctx->xml, spp_node, ns, "sessionID",
    128          1.1  christos 				  session_id);
    129          1.1  christos 	xml_node_add_attr(ctx->xml, spp_node, NULL, "redirectURI",
    130          1.1  christos 			  "http://localhost:12345/");
    131          1.1  christos 
    132          1.1  christos 	xml_node_create_text(ctx->xml, spp_node, ns, "supportedSPPVersions",
    133          1.1  christos 			     "1.0");
    134          1.1  christos 	xml_node_create_text(ctx->xml, spp_node, ns, "supportedMOList",
    135          1.1  christos 			     URN_HS20_PPS " " URN_OMA_DM_DEVINFO " "
    136          1.1  christos 			     URN_OMA_DM_DEVDETAIL " " URN_HS20_DEVDETAIL_EXT);
    137          1.1  christos 
    138          1.1  christos 	add_mo_container(ctx->xml, ns, spp_node, URN_OMA_DM_DEVINFO,
    139          1.1  christos 			 "devinfo.xml");
    140          1.1  christos 	add_mo_container(ctx->xml, ns, spp_node, URN_OMA_DM_DEVDETAIL,
    141          1.1  christos 			 "devdetail.xml");
    142          1.1  christos 
    143          1.1  christos 	return spp_node;
    144          1.1  christos }
    145          1.1  christos 
    146          1.1  christos 
    147          1.1  christos static int process_update_node(struct hs20_osu_client *ctx, xml_node_t *pps,
    148          1.1  christos 			       xml_node_t *update)
    149          1.1  christos {
    150          1.1  christos 	xml_node_t *node, *parent, *tnds, *unode;
    151          1.1  christos 	char *str;
    152          1.1  christos 	const char *name;
    153          1.1  christos 	char *uri, *pos;
    154          1.1  christos 	char *cdata, *cdata_end;
    155          1.1  christos 	size_t fqdn_len;
    156          1.1  christos 
    157          1.1  christos 	wpa_printf(MSG_INFO, "Processing updateNode");
    158          1.1  christos 	debug_dump_node(ctx, "updateNode", update);
    159          1.1  christos 
    160          1.1  christos 	uri = get_spp_attr_value(ctx->xml, update, "managementTreeURI");
    161          1.1  christos 	if (uri == NULL) {
    162          1.1  christos 		wpa_printf(MSG_INFO, "No managementTreeURI present");
    163          1.1  christos 		return -1;
    164          1.1  christos 	}
    165          1.1  christos 	wpa_printf(MSG_INFO, "managementTreeUri: '%s'", uri);
    166          1.1  christos 
    167          1.1  christos 	name = os_strrchr(uri, '/');
    168          1.1  christos 	if (name == NULL) {
    169          1.1  christos 		wpa_printf(MSG_INFO, "Unexpected URI");
    170          1.1  christos 		xml_node_get_attr_value_free(ctx->xml, uri);
    171          1.1  christos 		return -1;
    172          1.1  christos 	}
    173          1.1  christos 	name++;
    174          1.1  christos 	wpa_printf(MSG_INFO, "Update interior node: '%s'", name);
    175          1.1  christos 
    176          1.1  christos 	str = xml_node_get_text(ctx->xml, update);
    177          1.1  christos 	if (str == NULL) {
    178          1.1  christos 		wpa_printf(MSG_INFO, "Could not extract MO text");
    179          1.1  christos 		xml_node_get_attr_value_free(ctx->xml, uri);
    180          1.1  christos 		return -1;
    181          1.1  christos 	}
    182          1.1  christos 	wpa_printf(MSG_DEBUG, "[hs20] nodeContainer text: '%s'", str);
    183          1.1  christos 	cdata = strstr(str, "<![CDATA[");
    184          1.1  christos 	cdata_end = strstr(str, "]]>");
    185          1.1  christos 	if (cdata && cdata_end && cdata_end > cdata &&
    186          1.1  christos 	    cdata < strstr(str, "MgmtTree") &&
    187          1.1  christos 	    cdata_end > strstr(str, "/MgmtTree")) {
    188          1.1  christos 		char *tmp;
    189          1.1  christos 		wpa_printf(MSG_DEBUG, "[hs20] Removing extra CDATA container");
    190          1.1  christos 		tmp = strdup(cdata + 9);
    191          1.1  christos 		if (tmp) {
    192          1.1  christos 			cdata_end = strstr(tmp, "]]>");
    193          1.1  christos 			if (cdata_end)
    194          1.1  christos 				*cdata_end = '\0';
    195          1.1  christos 			wpa_printf(MSG_DEBUG, "[hs20] nodeContainer text with CDATA container removed: '%s'",
    196          1.1  christos 				   tmp);
    197          1.1  christos 			tnds = xml_node_from_buf(ctx->xml, tmp);
    198          1.1  christos 			free(tmp);
    199          1.1  christos 		} else
    200          1.1  christos 			tnds = NULL;
    201          1.1  christos 	} else
    202          1.1  christos 		tnds = xml_node_from_buf(ctx->xml, str);
    203          1.1  christos 	xml_node_get_text_free(ctx->xml, str);
    204          1.1  christos 	if (tnds == NULL) {
    205          1.1  christos 		wpa_printf(MSG_INFO, "[hs20] Could not parse nodeContainer text");
    206          1.1  christos 		xml_node_get_attr_value_free(ctx->xml, uri);
    207          1.1  christos 		return -1;
    208          1.1  christos 	}
    209          1.1  christos 
    210          1.1  christos 	unode = tnds_to_mo(ctx->xml, tnds);
    211          1.1  christos 	xml_node_free(ctx->xml, tnds);
    212          1.1  christos 	if (unode == NULL) {
    213          1.1  christos 		wpa_printf(MSG_INFO, "[hs20] Could not parse nodeContainer TNDS text");
    214          1.1  christos 		xml_node_get_attr_value_free(ctx->xml, uri);
    215          1.1  christos 		return -1;
    216          1.1  christos 	}
    217          1.1  christos 
    218          1.1  christos 	debug_dump_node(ctx, "Parsed TNDS", unode);
    219          1.1  christos 
    220          1.1  christos 	if (get_node_uri(ctx->xml, unode, name) == NULL) {
    221          1.1  christos 		wpa_printf(MSG_INFO, "[hs20] %s node not found", name);
    222          1.1  christos 		xml_node_free(ctx->xml, unode);
    223          1.1  christos 		xml_node_get_attr_value_free(ctx->xml, uri);
    224          1.1  christos 		return -1;
    225          1.1  christos 	}
    226          1.1  christos 
    227          1.1  christos 	if (os_strncasecmp(uri, "./Wi-Fi/", 8) != 0) {
    228          1.1  christos 		wpa_printf(MSG_INFO, "Do not allow update outside ./Wi-Fi");
    229          1.1  christos 		xml_node_free(ctx->xml, unode);
    230          1.1  christos 		xml_node_get_attr_value_free(ctx->xml, uri);
    231          1.1  christos 		return -1;
    232          1.1  christos 	}
    233          1.1  christos 	pos = uri + 8;
    234          1.1  christos 
    235          1.1  christos 	if (ctx->fqdn == NULL) {
    236          1.1  christos 		wpa_printf(MSG_INFO, "FQDN not known");
    237          1.1  christos 		xml_node_free(ctx->xml, unode);
    238          1.1  christos 		xml_node_get_attr_value_free(ctx->xml, uri);
    239          1.1  christos 		return -1;
    240          1.1  christos 	}
    241          1.1  christos 	fqdn_len = os_strlen(ctx->fqdn);
    242          1.1  christos 	if (os_strncasecmp(pos, ctx->fqdn, fqdn_len) != 0 ||
    243          1.1  christos 	    pos[fqdn_len] != '/') {
    244          1.1  christos 		wpa_printf(MSG_INFO, "Do not allow update outside ./Wi-Fi/%s",
    245          1.1  christos 			   ctx->fqdn);
    246          1.1  christos 		xml_node_free(ctx->xml, unode);
    247          1.1  christos 		xml_node_get_attr_value_free(ctx->xml, uri);
    248          1.1  christos 		return -1;
    249          1.1  christos 	}
    250          1.1  christos 	pos += fqdn_len + 1;
    251          1.1  christos 
    252          1.1  christos 	if (os_strncasecmp(pos, "PerProviderSubscription/", 24) != 0) {
    253          1.1  christos 		wpa_printf(MSG_INFO, "Do not allow update outside ./Wi-Fi/%s/PerProviderSubscription",
    254          1.1  christos 			   ctx->fqdn);
    255          1.1  christos 		xml_node_free(ctx->xml, unode);
    256          1.1  christos 		xml_node_get_attr_value_free(ctx->xml, uri);
    257          1.1  christos 		return -1;
    258          1.1  christos 	}
    259          1.1  christos 	pos += 24;
    260          1.1  christos 
    261          1.1  christos 	wpa_printf(MSG_INFO, "Update command for PPS node %s", pos);
    262          1.1  christos 
    263          1.1  christos 	node = get_node(ctx->xml, pps, pos);
    264          1.1  christos 	if (node) {
    265          1.1  christos 		parent = xml_node_get_parent(ctx->xml, node);
    266          1.1  christos 		xml_node_detach(ctx->xml, node);
    267          1.1  christos 		wpa_printf(MSG_INFO, "Replace '%s' node", name);
    268          1.1  christos 	} else {
    269          1.1  christos 		char *pos2;
    270          1.1  christos 		pos2 = os_strrchr(pos, '/');
    271          1.1  christos 		if (pos2 == NULL) {
    272          1.1  christos 			parent = pps;
    273          1.1  christos 		} else {
    274          1.1  christos 			*pos2 = '\0';
    275          1.1  christos 			parent = get_node(ctx->xml, pps, pos);
    276          1.1  christos 		}
    277          1.1  christos 		if (parent == NULL) {
    278          1.1  christos 			wpa_printf(MSG_INFO, "Could not find parent %s", pos);
    279          1.1  christos 			xml_node_free(ctx->xml, unode);
    280          1.1  christos 			xml_node_get_attr_value_free(ctx->xml, uri);
    281          1.1  christos 			return -1;
    282          1.1  christos 		}
    283          1.1  christos 		wpa_printf(MSG_INFO, "Add '%s' node", name);
    284          1.1  christos 	}
    285          1.1  christos 	xml_node_add_child(ctx->xml, parent, unode);
    286          1.1  christos 
    287          1.1  christos 	xml_node_get_attr_value_free(ctx->xml, uri);
    288          1.1  christos 
    289          1.1  christos 	return 0;
    290          1.1  christos }
    291          1.1  christos 
    292          1.1  christos 
    293          1.1  christos static int update_pps(struct hs20_osu_client *ctx, xml_node_t *update,
    294          1.1  christos 		      const char *pps_fname, xml_node_t *pps)
    295          1.1  christos {
    296          1.1  christos 	wpa_printf(MSG_INFO, "Updating PPS based on updateNode element(s)");
    297          1.1  christos 	xml_node_for_each_sibling(ctx->xml, update) {
    298          1.1  christos 		xml_node_for_each_check(ctx->xml, update);
    299          1.1  christos 		if (process_update_node(ctx, pps, update) < 0)
    300          1.1  christos 			return -1;
    301          1.1  christos 	}
    302          1.1  christos 
    303          1.1  christos 	return update_pps_file(ctx, pps_fname, pps);
    304          1.1  christos }
    305          1.1  christos 
    306          1.1  christos 
    307          1.1  christos static void hs20_sub_rem_complete(struct hs20_osu_client *ctx,
    308          1.1  christos 				  const char *pps_fname)
    309          1.1  christos {
    310          1.1  christos 	/*
    311          1.1  christos 	 * Update wpa_supplicant credentials and reconnect using updated
    312          1.1  christos 	 * information.
    313          1.1  christos 	 */
    314          1.1  christos 	wpa_printf(MSG_INFO, "Updating wpa_supplicant credentials");
    315          1.1  christos 	cmd_set_pps(ctx, pps_fname);
    316          1.1  christos 
    317          1.1  christos 	if (ctx->no_reconnect)
    318          1.1  christos 		return;
    319          1.1  christos 
    320          1.1  christos 	wpa_printf(MSG_INFO, "Requesting reconnection with updated configuration");
    321          1.1  christos 	if (wpa_command(ctx->ifname, "INTERWORKING_SELECT auto") < 0)
    322          1.1  christos 		wpa_printf(MSG_ERROR, "Failed to request wpa_supplicant to reconnect");
    323          1.1  christos }
    324          1.1  christos 
    325          1.1  christos 
    326          1.1  christos static xml_node_t * hs20_spp_upload_mo(struct hs20_osu_client *ctx,
    327          1.1  christos 				       xml_node_t *cmd,
    328          1.1  christos 				       const char *session_id,
    329          1.1  christos 				       const char *pps_fname)
    330          1.1  christos {
    331          1.1  christos 	xml_namespace_t *ns;
    332          1.1  christos 	xml_node_t *node, *ret_node;
    333          1.1  christos 	char *urn;
    334          1.1  christos 
    335          1.1  christos 	urn = get_spp_attr_value(ctx->xml, cmd, "moURN");
    336          1.1  christos 	if (!urn) {
    337          1.1  christos 		wpa_printf(MSG_INFO, "No URN included");
    338          1.1  christos 		return NULL;
    339          1.1  christos 	}
    340          1.1  christos 	wpa_printf(MSG_INFO, "Upload MO request - URN=%s", urn);
    341          1.1  christos 	if (strcasecmp(urn, URN_HS20_PPS) != 0) {
    342          1.1  christos 		wpa_printf(MSG_INFO, "Unsupported moURN");
    343          1.1  christos 		xml_node_get_attr_value_free(ctx->xml, urn);
    344          1.1  christos 		return NULL;
    345          1.1  christos 	}
    346          1.1  christos 	xml_node_get_attr_value_free(ctx->xml, urn);
    347          1.1  christos 
    348          1.1  christos 	if (!pps_fname) {
    349          1.1  christos 		wpa_printf(MSG_INFO, "PPS file name no known");
    350          1.1  christos 		return NULL;
    351          1.1  christos 	}
    352          1.1  christos 
    353          1.1  christos 	node = build_spp_post_dev_data(ctx, &ns, session_id,
    354          1.1  christos 				       "MO upload");
    355          1.1  christos 	if (node == NULL)
    356          1.1  christos 		return NULL;
    357          1.1  christos 	add_mo_container(ctx->xml, ns, node, URN_HS20_PPS, pps_fname);
    358          1.1  christos 
    359          1.1  christos 	ret_node = soap_send_receive(ctx->http, node);
    360          1.1  christos 	if (ret_node == NULL)
    361          1.1  christos 		return NULL;
    362          1.1  christos 
    363          1.1  christos 	debug_dump_node(ctx, "Received response to MO upload", ret_node);
    364          1.1  christos 
    365          1.1  christos 	if (hs20_spp_validate(ctx, ret_node, "sppPostDevDataResponse") < 0) {
    366          1.1  christos 		wpa_printf(MSG_INFO, "SPP validation failed");
    367          1.1  christos 		xml_node_free(ctx->xml, ret_node);
    368          1.1  christos 		return NULL;
    369          1.1  christos 	}
    370          1.1  christos 
    371          1.1  christos 	return ret_node;
    372          1.1  christos }
    373          1.1  christos 
    374          1.1  christos 
    375          1.1  christos static int hs20_add_mo(struct hs20_osu_client *ctx, xml_node_t *add_mo,
    376          1.1  christos 		       char *fname, size_t fname_len)
    377          1.1  christos {
    378          1.1  christos 	char *uri, *urn;
    379          1.1  christos 	int ret;
    380          1.1  christos 
    381          1.1  christos 	debug_dump_node(ctx, "Received addMO", add_mo);
    382          1.1  christos 
    383          1.1  christos 	urn = get_spp_attr_value(ctx->xml, add_mo, "moURN");
    384          1.1  christos 	if (urn == NULL) {
    385          1.1  christos 		wpa_printf(MSG_INFO, "[hs20] No moURN in addMO");
    386          1.1  christos 		return -1;
    387          1.1  christos 	}
    388          1.1  christos 	wpa_printf(MSG_INFO, "addMO - moURN: '%s'", urn);
    389          1.1  christos 	if (strcasecmp(urn, URN_HS20_PPS) != 0) {
    390          1.1  christos 		wpa_printf(MSG_INFO, "[hs20] Unsupported MO in addMO");
    391          1.1  christos 		xml_node_get_attr_value_free(ctx->xml, urn);
    392          1.1  christos 		return -1;
    393          1.1  christos 	}
    394          1.1  christos 	xml_node_get_attr_value_free(ctx->xml, urn);
    395          1.1  christos 
    396          1.1  christos 	uri = get_spp_attr_value(ctx->xml, add_mo, "managementTreeURI");
    397          1.1  christos 	if (uri == NULL) {
    398          1.1  christos 		wpa_printf(MSG_INFO, "[hs20] No managementTreeURI in addMO");
    399          1.1  christos 		return -1;
    400          1.1  christos 	}
    401          1.1  christos 	wpa_printf(MSG_INFO, "addMO - managementTreeURI: '%s'", uri);
    402          1.1  christos 
    403          1.1  christos 	ret = hs20_add_pps_mo(ctx, uri, add_mo, fname, fname_len);
    404          1.1  christos 	xml_node_get_attr_value_free(ctx->xml, uri);
    405          1.1  christos 	return ret;
    406          1.1  christos }
    407          1.1  christos 
    408          1.1  christos 
    409          1.1  christos static int process_spp_user_input_response(struct hs20_osu_client *ctx,
    410          1.1  christos 					   const char *session_id,
    411          1.1  christos 					   xml_node_t *add_mo)
    412          1.1  christos {
    413          1.1  christos 	int ret;
    414          1.1  christos 	char fname[300];
    415          1.1  christos 
    416          1.1  christos 	debug_dump_node(ctx, "addMO", add_mo);
    417          1.1  christos 
    418          1.1  christos 	wpa_printf(MSG_INFO, "Subscription registration completed");
    419          1.1  christos 
    420          1.1  christos 	if (hs20_add_mo(ctx, add_mo, fname, sizeof(fname)) < 0) {
    421          1.1  christos 		wpa_printf(MSG_INFO, "Could not add MO");
    422          1.1  christos 		ret = hs20_spp_update_response(
    423          1.1  christos 			ctx, session_id,
    424          1.1  christos 			"Error occurred",
    425          1.1  christos 			"MO addition or update failed");
    426          1.1  christos 		return 0;
    427          1.1  christos 	}
    428          1.1  christos 
    429          1.1  christos 	ret = hs20_spp_update_response(ctx, session_id, "OK", NULL);
    430          1.1  christos 	if (ret == 0)
    431          1.1  christos 		hs20_sub_rem_complete(ctx, fname);
    432          1.1  christos 
    433          1.1  christos 	return 0;
    434          1.1  christos }
    435          1.1  christos 
    436          1.1  christos 
    437          1.1  christos static xml_node_t * hs20_spp_user_input_completed(struct hs20_osu_client *ctx,
    438          1.1  christos 						    const char *session_id)
    439          1.1  christos {
    440          1.1  christos 	xml_node_t *node, *ret_node;
    441          1.1  christos 
    442          1.1  christos 	node = build_spp_post_dev_data(ctx, NULL, session_id,
    443          1.1  christos 				       "User input completed");
    444          1.1  christos 	if (node == NULL)
    445          1.1  christos 		return NULL;
    446          1.1  christos 
    447          1.1  christos 	ret_node = soap_send_receive(ctx->http, node);
    448          1.1  christos 	if (!ret_node) {
    449          1.1  christos 		if (soap_reinit_client(ctx->http) < 0)
    450          1.1  christos 			return NULL;
    451          1.1  christos 		wpa_printf(MSG_INFO, "Try to finish with re-opened connection");
    452          1.1  christos 		node = build_spp_post_dev_data(ctx, NULL, session_id,
    453          1.1  christos 					       "User input completed");
    454          1.1  christos 		if (node == NULL)
    455          1.1  christos 			return NULL;
    456          1.1  christos 		ret_node = soap_send_receive(ctx->http, node);
    457          1.1  christos 		if (ret_node == NULL)
    458          1.1  christos 			return NULL;
    459          1.1  christos 		wpa_printf(MSG_INFO, "Continue with new connection");
    460          1.1  christos 	}
    461          1.1  christos 
    462          1.1  christos 	if (hs20_spp_validate(ctx, ret_node, "sppPostDevDataResponse") < 0) {
    463          1.1  christos 		wpa_printf(MSG_INFO, "SPP validation failed");
    464          1.1  christos 		xml_node_free(ctx->xml, ret_node);
    465          1.1  christos 		return NULL;
    466          1.1  christos 	}
    467          1.1  christos 
    468          1.1  christos 	return ret_node;
    469          1.1  christos }
    470          1.1  christos 
    471          1.1  christos 
    472          1.1  christos static xml_node_t * hs20_spp_get_certificate(struct hs20_osu_client *ctx,
    473          1.1  christos 					     xml_node_t *cmd,
    474          1.1  christos 					     const char *session_id,
    475          1.1  christos 					     const char *pps_fname)
    476          1.1  christos {
    477          1.1  christos 	xml_namespace_t *ns;
    478          1.1  christos 	xml_node_t *node, *ret_node;
    479          1.1  christos 	int res;
    480          1.1  christos 
    481          1.1  christos 	wpa_printf(MSG_INFO, "Client certificate enrollment");
    482          1.1  christos 
    483          1.1  christos 	res = osu_get_certificate(ctx, cmd);
    484          1.1  christos 	if (res < 0)
    485          1.1  christos 		wpa_printf(MSG_INFO, "EST simpleEnroll failed");
    486          1.1  christos 
    487          1.1  christos 	node = build_spp_post_dev_data(ctx, &ns, session_id,
    488          1.1  christos 				       res == 0 ?
    489          1.1  christos 				       "Certificate enrollment completed" :
    490          1.1  christos 				       "Certificate enrollment failed");
    491          1.1  christos 	if (node == NULL)
    492          1.1  christos 		return NULL;
    493          1.1  christos 
    494          1.1  christos 	ret_node = soap_send_receive(ctx->http, node);
    495          1.1  christos 	if (ret_node == NULL)
    496          1.1  christos 		return NULL;
    497          1.1  christos 
    498          1.1  christos 	debug_dump_node(ctx, "Received response to certificate enrollment "
    499          1.1  christos 			"completed", ret_node);
    500          1.1  christos 
    501          1.1  christos 	if (hs20_spp_validate(ctx, ret_node, "sppPostDevDataResponse") < 0) {
    502          1.1  christos 		wpa_printf(MSG_INFO, "SPP validation failed");
    503          1.1  christos 		xml_node_free(ctx->xml, ret_node);
    504          1.1  christos 		return NULL;
    505          1.1  christos 	}
    506          1.1  christos 
    507          1.1  christos 	return ret_node;
    508          1.1  christos }
    509          1.1  christos 
    510          1.1  christos 
    511          1.1  christos static int hs20_spp_exec(struct hs20_osu_client *ctx, xml_node_t *exec,
    512          1.1  christos 			 const char *session_id, const char *pps_fname,
    513          1.1  christos 			 xml_node_t *pps, xml_node_t **ret_node)
    514          1.1  christos {
    515          1.1  christos 	xml_node_t *cmd;
    516          1.1  christos 	const char *name;
    517          1.1  christos 	char *uri;
    518          1.1  christos 	char *id = strdup(session_id);
    519          1.1  christos 
    520          1.1  christos 	if (id == NULL)
    521          1.1  christos 		return -1;
    522          1.1  christos 
    523          1.1  christos 	*ret_node = NULL;
    524          1.1  christos 
    525          1.1  christos 	debug_dump_node(ctx, "exec", exec);
    526          1.1  christos 
    527          1.1  christos 	xml_node_for_each_child(ctx->xml, cmd, exec) {
    528          1.1  christos 		xml_node_for_each_check(ctx->xml, cmd);
    529          1.1  christos 		break;
    530          1.1  christos 	}
    531          1.1  christos 	if (!cmd) {
    532          1.1  christos 		wpa_printf(MSG_INFO, "exec command element not found (cmd=%p)",
    533          1.1  christos 			   cmd);
    534          1.1  christos 		free(id);
    535          1.1  christos 		return -1;
    536          1.1  christos 	}
    537          1.1  christos 
    538          1.1  christos 	name = xml_node_get_localname(ctx->xml, cmd);
    539          1.1  christos 
    540          1.1  christos 	if (strcasecmp(name, "launchBrowserToURI") == 0) {
    541          1.1  christos 		int res;
    542          1.1  christos 		uri = xml_node_get_text(ctx->xml, cmd);
    543          1.1  christos 		if (!uri) {
    544          1.1  christos 			wpa_printf(MSG_INFO, "No URI found");
    545          1.1  christos 			free(id);
    546          1.1  christos 			return -1;
    547          1.1  christos 		}
    548          1.1  christos 		wpa_printf(MSG_INFO, "Launch browser to URI '%s'", uri);
    549          1.1  christos 		write_summary(ctx, "Launch browser to URI '%s'", uri);
    550          1.1  christos 		res = hs20_web_browser(uri);
    551          1.1  christos 		xml_node_get_text_free(ctx->xml, uri);
    552          1.1  christos 		if (res > 0) {
    553          1.1  christos 			wpa_printf(MSG_INFO, "User response in browser completed successfully - sessionid='%s'",
    554          1.1  christos 				   id);
    555          1.1  christos 			write_summary(ctx, "User response in browser completed successfully");
    556          1.1  christos 			*ret_node = hs20_spp_user_input_completed(ctx, id);
    557          1.1  christos 			free(id);
    558          1.1  christos 			return *ret_node ? 0 : -1;
    559          1.1  christos 		} else {
    560          1.1  christos 			wpa_printf(MSG_INFO, "Failed to receive user response");
    561          1.1  christos 			write_summary(ctx, "Failed to receive user response");
    562          1.1  christos 			hs20_spp_update_response(
    563          1.1  christos 				ctx, id, "Error occurred", "Other");
    564          1.1  christos 			free(id);
    565          1.1  christos 			return -1;
    566          1.1  christos 		}
    567          1.1  christos 		return 0;
    568          1.1  christos 	}
    569          1.1  christos 
    570          1.1  christos 	if (strcasecmp(name, "uploadMO") == 0) {
    571          1.1  christos 		if (pps_fname == NULL)
    572          1.1  christos 			return -1;
    573          1.1  christos 		*ret_node = hs20_spp_upload_mo(ctx, cmd, id,
    574          1.1  christos 					       pps_fname);
    575          1.1  christos 		free(id);
    576          1.1  christos 		return *ret_node ? 0 : -1;
    577          1.1  christos 	}
    578          1.1  christos 
    579          1.1  christos 	if (strcasecmp(name, "getCertificate") == 0) {
    580          1.1  christos 		*ret_node = hs20_spp_get_certificate(ctx, cmd, id,
    581          1.1  christos 						     pps_fname);
    582          1.1  christos 		free(id);
    583          1.1  christos 		return *ret_node ? 0 : -1;
    584          1.1  christos 	}
    585          1.1  christos 
    586          1.1  christos 	wpa_printf(MSG_INFO, "Unsupported exec command: '%s'", name);
    587          1.1  christos 	free(id);
    588          1.1  christos 	return -1;
    589          1.1  christos }
    590          1.1  christos 
    591          1.1  christos 
    592          1.1  christos enum spp_post_dev_data_use {
    593          1.1  christos 	SPP_SUBSCRIPTION_REMEDIATION,
    594          1.1  christos 	SPP_POLICY_UPDATE,
    595          1.1  christos 	SPP_SUBSCRIPTION_REGISTRATION,
    596          1.1  christos };
    597          1.1  christos 
    598          1.1  christos static void process_spp_post_dev_data_response(
    599          1.1  christos 	struct hs20_osu_client *ctx,
    600          1.1  christos 	enum spp_post_dev_data_use use, xml_node_t *node,
    601          1.1  christos 	const char *pps_fname, xml_node_t *pps)
    602          1.1  christos {
    603          1.1  christos 	xml_node_t *child;
    604          1.1  christos 	char *status = NULL;
    605          1.1  christos 	xml_node_t *update = NULL, *exec = NULL, *add_mo = NULL, *no_mo = NULL;
    606          1.1  christos 	char *session_id = NULL;
    607          1.1  christos 
    608          1.1  christos 	debug_dump_node(ctx, "sppPostDevDataResponse node", node);
    609          1.1  christos 
    610          1.1  christos 	status = get_spp_attr_value(ctx->xml, node, "sppStatus");
    611          1.1  christos 	if (status == NULL) {
    612          1.1  christos 		wpa_printf(MSG_INFO, "No sppStatus attribute");
    613          1.1  christos 		goto out;
    614          1.1  christos 	}
    615          1.1  christos 	write_summary(ctx, "Received sppPostDevDataResponse sppStatus='%s'",
    616          1.1  christos 		      status);
    617          1.1  christos 
    618          1.1  christos 	session_id = get_spp_attr_value(ctx->xml, node, "sessionID");
    619          1.1  christos 	if (session_id == NULL) {
    620          1.1  christos 		wpa_printf(MSG_INFO, "No sessionID attribute");
    621          1.1  christos 		goto out;
    622          1.1  christos 	}
    623          1.1  christos 
    624          1.1  christos 	wpa_printf(MSG_INFO, "[hs20] sppPostDevDataResponse - sppStatus: '%s'  sessionID: '%s'",
    625          1.1  christos 		   status, session_id);
    626          1.1  christos 
    627          1.1  christos 	xml_node_for_each_child(ctx->xml, child, node) {
    628          1.1  christos 		const char *name;
    629          1.1  christos 		xml_node_for_each_check(ctx->xml, child);
    630          1.1  christos 		debug_dump_node(ctx, "child", child);
    631          1.1  christos 		name = xml_node_get_localname(ctx->xml, child);
    632          1.1  christos 		wpa_printf(MSG_INFO, "localname: '%s'", name);
    633          1.1  christos 		if (!update && strcasecmp(name, "updateNode") == 0)
    634          1.1  christos 			update = child;
    635          1.1  christos 		if (!exec && strcasecmp(name, "exec") == 0)
    636          1.1  christos 			exec = child;
    637          1.1  christos 		if (!add_mo && strcasecmp(name, "addMO") == 0)
    638          1.1  christos 			add_mo = child;
    639          1.1  christos 		if (!no_mo && strcasecmp(name, "noMOUpdate") == 0)
    640          1.1  christos 			no_mo = child;
    641          1.1  christos 	}
    642          1.1  christos 
    643          1.1  christos 	if (use == SPP_SUBSCRIPTION_REMEDIATION &&
    644          1.1  christos 	    strcasecmp(status,
    645          1.1  christos 		       "Remediation complete, request sppUpdateResponse") == 0)
    646          1.1  christos 	{
    647          1.1  christos 		int res, ret;
    648          1.1  christos 		if (!update && !no_mo) {
    649          1.1  christos 			wpa_printf(MSG_INFO, "No updateNode or noMOUpdate element");
    650          1.1  christos 			goto out;
    651          1.1  christos 		}
    652          1.1  christos 		wpa_printf(MSG_INFO, "Subscription remediation completed");
    653          1.1  christos 		res = update_pps(ctx, update, pps_fname, pps);
    654          1.1  christos 		if (res < 0)
    655          1.1  christos 			wpa_printf(MSG_INFO, "Failed to update PPS MO");
    656          1.1  christos 		ret = hs20_spp_update_response(
    657          1.1  christos 			ctx, session_id,
    658          1.1  christos 			res < 0 ? "Error occurred" : "OK",
    659          1.1  christos 			res < 0 ? "MO addition or update failed" : NULL);
    660          1.1  christos 		if (res == 0 && ret == 0)
    661          1.1  christos 			hs20_sub_rem_complete(ctx, pps_fname);
    662          1.1  christos 		goto out;
    663          1.1  christos 	}
    664          1.1  christos 
    665          1.1  christos 	if (use == SPP_SUBSCRIPTION_REMEDIATION &&
    666          1.1  christos 	    strcasecmp(status, "Exchange complete, release TLS connection") ==
    667          1.1  christos 	    0) {
    668          1.1  christos 		if (!no_mo) {
    669          1.1  christos 			wpa_printf(MSG_INFO, "No noMOUpdate element");
    670          1.1  christos 			goto out;
    671          1.1  christos 		}
    672          1.1  christos 		wpa_printf(MSG_INFO, "Subscription remediation completed (no MO update)");
    673          1.1  christos 		goto out;
    674          1.1  christos 	}
    675          1.1  christos 
    676          1.1  christos 	if (use == SPP_POLICY_UPDATE &&
    677          1.1  christos 	    strcasecmp(status, "Update complete, request sppUpdateResponse") ==
    678          1.1  christos 	    0) {
    679          1.1  christos 		int res, ret;
    680          1.1  christos 		wpa_printf(MSG_INFO, "Policy update received - update PPS");
    681          1.1  christos 		res = update_pps(ctx, update, pps_fname, pps);
    682          1.1  christos 		ret = hs20_spp_update_response(
    683          1.1  christos 			ctx, session_id,
    684          1.1  christos 			res < 0 ? "Error occurred" : "OK",
    685          1.1  christos 			res < 0 ? "MO addition or update failed" : NULL);
    686          1.1  christos 		if (res == 0 && ret == 0)
    687          1.1  christos 			hs20_policy_update_complete(ctx, pps_fname);
    688          1.1  christos 		goto out;
    689          1.1  christos 	}
    690          1.1  christos 
    691          1.1  christos 	if (use == SPP_SUBSCRIPTION_REGISTRATION &&
    692          1.1  christos 	    strcasecmp(status, "Provisioning complete, request "
    693          1.1  christos 		       "sppUpdateResponse")  == 0) {
    694          1.1  christos 		if (!add_mo) {
    695          1.1  christos 			wpa_printf(MSG_INFO, "No addMO element - not sure what to do next");
    696          1.1  christos 			goto out;
    697          1.1  christos 		}
    698          1.1  christos 		process_spp_user_input_response(ctx, session_id, add_mo);
    699          1.1  christos 		node = NULL;
    700          1.1  christos 		goto out;
    701          1.1  christos 	}
    702          1.1  christos 
    703          1.1  christos 	if (strcasecmp(status, "No update available at this time") == 0) {
    704          1.1  christos 		wpa_printf(MSG_INFO, "No update available at this time");
    705          1.1  christos 		goto out;
    706          1.1  christos 	}
    707          1.1  christos 
    708          1.1  christos 	if (strcasecmp(status, "OK") == 0) {
    709          1.1  christos 		int res;
    710          1.1  christos 		xml_node_t *ret;
    711          1.1  christos 
    712          1.1  christos 		if (!exec) {
    713          1.1  christos 			wpa_printf(MSG_INFO, "No exec element - not sure what to do next");
    714          1.1  christos 			goto out;
    715          1.1  christos 		}
    716          1.1  christos 		res = hs20_spp_exec(ctx, exec, session_id,
    717          1.1  christos 				    pps_fname, pps, &ret);
    718          1.1  christos 		/* xml_node_free(ctx->xml, node); */
    719          1.1  christos 		node = NULL;
    720          1.1  christos 		if (res == 0 && ret)
    721          1.1  christos 			process_spp_post_dev_data_response(ctx, use,
    722          1.1  christos 							   ret, pps_fname, pps);
    723          1.1  christos 		goto out;
    724          1.1  christos 	}
    725          1.1  christos 
    726          1.1  christos 	if (strcasecmp(status, "Error occurred") == 0) {
    727          1.1  christos 		xml_node_t *err;
    728          1.1  christos 		char *code = NULL;
    729          1.1  christos 		err = get_node(ctx->xml, node, "sppError");
    730          1.1  christos 		if (err)
    731          1.1  christos 			code = xml_node_get_attr_value(ctx->xml, err,
    732          1.1  christos 						       "errorCode");
    733          1.1  christos 		wpa_printf(MSG_INFO, "Error occurred - errorCode=%s",
    734          1.1  christos 			   code ? code : "N/A");
    735          1.1  christos 		xml_node_get_attr_value_free(ctx->xml, code);
    736          1.1  christos 		goto out;
    737          1.1  christos 	}
    738          1.1  christos 
    739          1.1  christos 	wpa_printf(MSG_INFO,
    740          1.1  christos 		   "[hs20] Unsupported sppPostDevDataResponse sppStatus '%s'",
    741          1.1  christos 		   status);
    742          1.1  christos out:
    743          1.1  christos 	xml_node_get_attr_value_free(ctx->xml, status);
    744          1.1  christos 	xml_node_get_attr_value_free(ctx->xml, session_id);
    745          1.1  christos 	xml_node_free(ctx->xml, node);
    746          1.1  christos }
    747          1.1  christos 
    748          1.1  christos 
    749          1.1  christos static int spp_post_dev_data(struct hs20_osu_client *ctx,
    750          1.1  christos 			     enum spp_post_dev_data_use use,
    751          1.1  christos 			     const char *reason,
    752          1.1  christos 			     const char *pps_fname, xml_node_t *pps)
    753          1.1  christos {
    754          1.1  christos 	xml_node_t *payload;
    755          1.1  christos 	xml_node_t *ret_node;
    756          1.1  christos 
    757          1.1  christos 	payload = build_spp_post_dev_data(ctx, NULL, NULL, reason);
    758          1.1  christos 	if (payload == NULL)
    759          1.1  christos 		return -1;
    760          1.1  christos 
    761          1.1  christos 	ret_node = soap_send_receive(ctx->http, payload);
    762          1.1  christos 	if (!ret_node) {
    763          1.1  christos 		const char *err = http_get_err(ctx->http);
    764          1.1  christos 		if (err) {
    765          1.1  christos 			wpa_printf(MSG_INFO, "HTTP error: %s", err);
    766          1.1  christos 			write_result(ctx, "HTTP error: %s", err);
    767          1.1  christos 		} else {
    768          1.1  christos 			write_summary(ctx, "Failed to send SOAP message");
    769          1.1  christos 		}
    770          1.1  christos 		return -1;
    771          1.1  christos 	}
    772          1.1  christos 
    773          1.1  christos 	if (hs20_spp_validate(ctx, ret_node, "sppPostDevDataResponse") < 0) {
    774          1.1  christos 		wpa_printf(MSG_INFO, "SPP validation failed");
    775          1.1  christos 		xml_node_free(ctx->xml, ret_node);
    776          1.1  christos 		return -1;
    777          1.1  christos 	}
    778          1.1  christos 
    779          1.1  christos 	process_spp_post_dev_data_response(ctx, use, ret_node,
    780          1.1  christos 					   pps_fname, pps);
    781          1.1  christos 	return 0;
    782          1.1  christos }
    783          1.1  christos 
    784          1.1  christos 
    785          1.1  christos void spp_sub_rem(struct hs20_osu_client *ctx, const char *address,
    786          1.1  christos 		 const char *pps_fname,
    787          1.1  christos 		 const char *client_cert, const char *client_key,
    788          1.1  christos 		 const char *cred_username, const char *cred_password,
    789          1.1  christos 		 xml_node_t *pps)
    790          1.1  christos {
    791          1.1  christos 	wpa_printf(MSG_INFO, "SPP subscription remediation");
    792          1.1  christos 	write_summary(ctx, "SPP subscription remediation");
    793          1.1  christos 
    794          1.1  christos 	os_free(ctx->server_url);
    795          1.1  christos 	ctx->server_url = os_strdup(address);
    796          1.1  christos 
    797          1.1  christos 	if (soap_init_client(ctx->http, address, ctx->ca_fname,
    798          1.1  christos 			     cred_username, cred_password, client_cert,
    799          1.1  christos 			     client_key) == 0) {
    800          1.1  christos 		spp_post_dev_data(ctx, SPP_SUBSCRIPTION_REMEDIATION,
    801          1.1  christos 				  "Subscription remediation", pps_fname, pps);
    802          1.1  christos 	}
    803          1.1  christos }
    804          1.1  christos 
    805          1.1  christos 
    806          1.1  christos static void hs20_policy_update_complete(struct hs20_osu_client *ctx,
    807          1.1  christos 					const char *pps_fname)
    808          1.1  christos {
    809          1.1  christos 	wpa_printf(MSG_INFO, "Policy update completed");
    810          1.1  christos 
    811          1.1  christos 	/*
    812          1.1  christos 	 * Update wpa_supplicant credentials and reconnect using updated
    813          1.1  christos 	 * information.
    814          1.1  christos 	 */
    815          1.1  christos 	wpa_printf(MSG_INFO, "Updating wpa_supplicant credentials");
    816          1.1  christos 	cmd_set_pps(ctx, pps_fname);
    817          1.1  christos 
    818          1.1  christos 	wpa_printf(MSG_INFO, "Requesting reconnection with updated configuration");
    819          1.1  christos 	if (wpa_command(ctx->ifname, "INTERWORKING_SELECT auto") < 0)
    820          1.1  christos 		wpa_printf(MSG_ERROR, "Failed to request wpa_supplicant to reconnect");
    821          1.1  christos }
    822          1.1  christos 
    823          1.1  christos 
    824          1.1  christos static int process_spp_exchange_complete(struct hs20_osu_client *ctx,
    825          1.1  christos 					 xml_node_t *node)
    826          1.1  christos {
    827          1.1  christos 	char *status, *session_id;
    828          1.1  christos 
    829          1.1  christos 	debug_dump_node(ctx, "sppExchangeComplete", node);
    830          1.1  christos 
    831          1.1  christos 	status = get_spp_attr_value(ctx->xml, node, "sppStatus");
    832          1.1  christos 	if (status == NULL) {
    833          1.1  christos 		wpa_printf(MSG_INFO, "No sppStatus attribute");
    834          1.1  christos 		return -1;
    835          1.1  christos 	}
    836          1.1  christos 	write_summary(ctx, "Received sppExchangeComplete sppStatus='%s'",
    837          1.1  christos 		      status);
    838          1.1  christos 
    839          1.1  christos 	session_id = get_spp_attr_value(ctx->xml, node, "sessionID");
    840          1.1  christos 	if (session_id == NULL) {
    841          1.1  christos 		wpa_printf(MSG_INFO, "No sessionID attribute");
    842          1.1  christos 		xml_node_get_attr_value_free(ctx->xml, status);
    843          1.1  christos 		return -1;
    844          1.1  christos 	}
    845          1.1  christos 
    846          1.1  christos 	wpa_printf(MSG_INFO, "[hs20] sppStatus: '%s'  sessionID: '%s'",
    847          1.1  christos 		   status, session_id);
    848          1.1  christos 	xml_node_get_attr_value_free(ctx->xml, session_id);
    849          1.1  christos 
    850          1.1  christos 	if (strcasecmp(status, "Exchange complete, release TLS connection") ==
    851          1.1  christos 	    0) {
    852          1.1  christos 		xml_node_get_attr_value_free(ctx->xml, status);
    853          1.1  christos 		return 0;
    854          1.1  christos 	}
    855          1.1  christos 
    856          1.1  christos 	wpa_printf(MSG_INFO, "Unexpected sppStatus '%s'", status);
    857          1.1  christos 	write_summary(ctx, "Unexpected sppStatus '%s'", status);
    858          1.1  christos 	xml_node_get_attr_value_free(ctx->xml, status);
    859          1.1  christos 	return -1;
    860          1.1  christos }
    861          1.1  christos 
    862          1.1  christos 
    863          1.1  christos static xml_node_t * build_spp_update_response(struct hs20_osu_client *ctx,
    864          1.1  christos 					      const char *session_id,
    865          1.1  christos 					      const char *spp_status,
    866          1.1  christos 					      const char *error_code)
    867          1.1  christos {
    868          1.1  christos 	xml_namespace_t *ns;
    869          1.1  christos 	xml_node_t *spp_node, *node;
    870          1.1  christos 
    871          1.1  christos 	spp_node = xml_node_create_root(ctx->xml, SPP_NS_URI, "spp", &ns,
    872          1.1  christos 					"sppUpdateResponse");
    873          1.1  christos 	if (spp_node == NULL)
    874          1.1  christos 		return NULL;
    875          1.1  christos 
    876          1.1  christos 	xml_node_add_attr(ctx->xml, spp_node, ns, "sppVersion", "1.0");
    877          1.1  christos 	xml_node_add_attr(ctx->xml, spp_node, ns, "sessionID", session_id);
    878          1.1  christos 	xml_node_add_attr(ctx->xml, spp_node, ns, "sppStatus", spp_status);
    879          1.1  christos 
    880          1.1  christos 	if (error_code) {
    881          1.1  christos 		node = xml_node_create(ctx->xml, spp_node, ns, "sppError");
    882          1.1  christos 		if (node)
    883          1.1  christos 			xml_node_add_attr(ctx->xml, node, NULL, "errorCode",
    884          1.1  christos 					  error_code);
    885          1.1  christos 	}
    886          1.1  christos 
    887          1.1  christos 	return spp_node;
    888          1.1  christos }
    889          1.1  christos 
    890          1.1  christos 
    891          1.1  christos static int hs20_spp_update_response(struct hs20_osu_client *ctx,
    892          1.1  christos 				    const char *session_id,
    893          1.1  christos 				    const char *spp_status,
    894          1.1  christos 				    const char *error_code)
    895          1.1  christos {
    896          1.1  christos 	xml_node_t *node, *ret_node;
    897          1.1  christos 	int ret;
    898          1.1  christos 
    899          1.1  christos 	write_summary(ctx, "Building sppUpdateResponse sppStatus='%s' error_code='%s'",
    900          1.1  christos 		      spp_status, error_code);
    901          1.1  christos 	node = build_spp_update_response(ctx, session_id, spp_status,
    902          1.1  christos 					 error_code);
    903          1.1  christos 	if (node == NULL)
    904          1.1  christos 		return -1;
    905          1.1  christos 	ret_node = soap_send_receive(ctx->http, node);
    906          1.1  christos 	if (!ret_node) {
    907          1.1  christos 		if (soap_reinit_client(ctx->http) < 0)
    908          1.1  christos 			return -1;
    909          1.1  christos 		wpa_printf(MSG_INFO, "Try to finish with re-opened connection");
    910          1.1  christos 		node = build_spp_update_response(ctx, session_id, spp_status,
    911          1.1  christos 						 error_code);
    912          1.1  christos 		if (node == NULL)
    913          1.1  christos 			return -1;
    914          1.1  christos 		ret_node = soap_send_receive(ctx->http, node);
    915          1.1  christos 		if (ret_node == NULL)
    916          1.1  christos 			return -1;
    917          1.1  christos 		wpa_printf(MSG_INFO, "Continue with new connection");
    918          1.1  christos 	}
    919          1.1  christos 
    920          1.1  christos 	if (hs20_spp_validate(ctx, ret_node, "sppExchangeComplete") < 0) {
    921          1.1  christos 		wpa_printf(MSG_INFO, "SPP validation failed");
    922          1.1  christos 		xml_node_free(ctx->xml, ret_node);
    923          1.1  christos 		return -1;
    924          1.1  christos 	}
    925          1.1  christos 
    926          1.1  christos 	ret = process_spp_exchange_complete(ctx, ret_node);
    927          1.1  christos 	xml_node_free(ctx->xml, ret_node);
    928          1.1  christos 	return ret;
    929          1.1  christos }
    930          1.1  christos 
    931          1.1  christos 
    932          1.1  christos void spp_pol_upd(struct hs20_osu_client *ctx, const char *address,
    933          1.1  christos 		 const char *pps_fname,
    934          1.1  christos 		 const char *client_cert, const char *client_key,
    935          1.1  christos 		 const char *cred_username, const char *cred_password,
    936          1.1  christos 		 xml_node_t *pps)
    937          1.1  christos {
    938          1.1  christos 	wpa_printf(MSG_INFO, "SPP policy update");
    939          1.1  christos 	write_summary(ctx, "SPP policy update");
    940          1.1  christos 
    941          1.1  christos 	os_free(ctx->server_url);
    942          1.1  christos 	ctx->server_url = os_strdup(address);
    943          1.1  christos 
    944          1.1  christos 	if (soap_init_client(ctx->http, address, ctx->ca_fname, cred_username,
    945          1.1  christos 			     cred_password, client_cert, client_key) == 0) {
    946          1.1  christos 		spp_post_dev_data(ctx, SPP_POLICY_UPDATE, "Policy update",
    947          1.1  christos 				  pps_fname, pps);
    948          1.1  christos 	}
    949          1.1  christos }
    950          1.1  christos 
    951          1.1  christos 
    952          1.1  christos int cmd_prov(struct hs20_osu_client *ctx, const char *url)
    953          1.1  christos {
    954          1.1  christos 	unlink("Cert/est_cert.der");
    955          1.1  christos 	unlink("Cert/est_cert.pem");
    956          1.1  christos 
    957          1.1  christos 	if (url == NULL) {
    958          1.1  christos 		wpa_printf(MSG_INFO, "Invalid prov command (missing URL)");
    959          1.1  christos 		return -1;
    960          1.1  christos 	}
    961          1.1  christos 
    962  1.1.1.1.4.1  pgoyette 	wpa_printf(MSG_INFO,
    963  1.1.1.1.4.1  pgoyette 		   "Credential provisioning requested - URL: %s ca_fname: %s",
    964  1.1.1.1.4.1  pgoyette 		   url, ctx->ca_fname ? ctx->ca_fname : "N/A");
    965          1.1  christos 
    966          1.1  christos 	os_free(ctx->server_url);
    967          1.1  christos 	ctx->server_url = os_strdup(url);
    968          1.1  christos 
    969          1.1  christos 	if (soap_init_client(ctx->http, url, ctx->ca_fname, NULL, NULL, NULL,
    970          1.1  christos 			     NULL) < 0)
    971          1.1  christos 		return -1;
    972          1.1  christos 	spp_post_dev_data(ctx, SPP_SUBSCRIPTION_REGISTRATION,
    973          1.1  christos 			  "Subscription registration", NULL, NULL);
    974          1.1  christos 
    975          1.1  christos 	return ctx->pps_cred_set ? 0 : -1;
    976          1.1  christos }
    977          1.1  christos 
    978          1.1  christos 
    979          1.1  christos int cmd_sim_prov(struct hs20_osu_client *ctx, const char *url)
    980          1.1  christos {
    981          1.1  christos 	if (url == NULL) {
    982          1.1  christos 		wpa_printf(MSG_INFO, "Invalid prov command (missing URL)");
    983          1.1  christos 		return -1;
    984          1.1  christos 	}
    985          1.1  christos 
    986          1.1  christos 	wpa_printf(MSG_INFO, "SIM provisioning requested");
    987          1.1  christos 
    988          1.1  christos 	os_free(ctx->server_url);
    989          1.1  christos 	ctx->server_url = os_strdup(url);
    990          1.1  christos 
    991          1.1  christos 	wpa_printf(MSG_INFO, "Wait for IP address before starting SIM provisioning");
    992          1.1  christos 
    993          1.1  christos 	if (wait_ip_addr(ctx->ifname, 15) < 0) {
    994          1.1  christos 		wpa_printf(MSG_INFO, "Could not get IP address for WLAN - try connection anyway");
    995          1.1  christos 	}
    996          1.1  christos 
    997          1.1  christos 	if (soap_init_client(ctx->http, url, ctx->ca_fname, NULL, NULL, NULL,
    998          1.1  christos 			     NULL) < 0)
    999          1.1  christos 		return -1;
   1000          1.1  christos 	spp_post_dev_data(ctx, SPP_SUBSCRIPTION_REGISTRATION,
   1001          1.1  christos 			  "Subscription provisioning", NULL, NULL);
   1002          1.1  christos 
   1003          1.1  christos 	return ctx->pps_cred_set ? 0 : -1;
   1004          1.1  christos }
   1005