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