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.2 christos extern const char *spp_xsd_fname; 25 1.1.1.2 christos 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.2 christos 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.2 christos errno = 0; 83 1.1 christos fnode = node_from_file(ctx, fname); 84 1.1.1.2 christos if (!fnode) { 85 1.1.1.2 christos wpa_printf(MSG_ERROR, 86 1.1.1.2 christos "Failed to create XML node from file: %s, possible error: %s", 87 1.1.1.2 christos fname, strerror(errno)); 88 1.1 christos return; 89 1.1.1.2 christos } 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.1.3 christos res = hs20_web_browser(uri, 1); 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 } 568 1.1 christos 569 1.1 christos if (strcasecmp(name, "uploadMO") == 0) { 570 1.1 christos if (pps_fname == NULL) 571 1.1 christos return -1; 572 1.1 christos *ret_node = hs20_spp_upload_mo(ctx, cmd, id, 573 1.1 christos pps_fname); 574 1.1 christos free(id); 575 1.1 christos return *ret_node ? 0 : -1; 576 1.1 christos } 577 1.1 christos 578 1.1 christos if (strcasecmp(name, "getCertificate") == 0) { 579 1.1 christos *ret_node = hs20_spp_get_certificate(ctx, cmd, id, 580 1.1 christos pps_fname); 581 1.1 christos free(id); 582 1.1 christos return *ret_node ? 0 : -1; 583 1.1 christos } 584 1.1 christos 585 1.1 christos wpa_printf(MSG_INFO, "Unsupported exec command: '%s'", name); 586 1.1 christos free(id); 587 1.1 christos return -1; 588 1.1 christos } 589 1.1 christos 590 1.1 christos 591 1.1 christos enum spp_post_dev_data_use { 592 1.1 christos SPP_SUBSCRIPTION_REMEDIATION, 593 1.1 christos SPP_POLICY_UPDATE, 594 1.1 christos SPP_SUBSCRIPTION_REGISTRATION, 595 1.1 christos }; 596 1.1 christos 597 1.1 christos static void process_spp_post_dev_data_response( 598 1.1 christos struct hs20_osu_client *ctx, 599 1.1 christos enum spp_post_dev_data_use use, xml_node_t *node, 600 1.1 christos const char *pps_fname, xml_node_t *pps) 601 1.1 christos { 602 1.1 christos xml_node_t *child; 603 1.1 christos char *status = NULL; 604 1.1 christos xml_node_t *update = NULL, *exec = NULL, *add_mo = NULL, *no_mo = NULL; 605 1.1 christos char *session_id = NULL; 606 1.1 christos 607 1.1 christos debug_dump_node(ctx, "sppPostDevDataResponse node", node); 608 1.1 christos 609 1.1 christos status = get_spp_attr_value(ctx->xml, node, "sppStatus"); 610 1.1 christos if (status == NULL) { 611 1.1 christos wpa_printf(MSG_INFO, "No sppStatus attribute"); 612 1.1 christos goto out; 613 1.1 christos } 614 1.1 christos write_summary(ctx, "Received sppPostDevDataResponse sppStatus='%s'", 615 1.1 christos status); 616 1.1 christos 617 1.1 christos session_id = get_spp_attr_value(ctx->xml, node, "sessionID"); 618 1.1 christos if (session_id == NULL) { 619 1.1 christos wpa_printf(MSG_INFO, "No sessionID attribute"); 620 1.1 christos goto out; 621 1.1 christos } 622 1.1 christos 623 1.1 christos wpa_printf(MSG_INFO, "[hs20] sppPostDevDataResponse - sppStatus: '%s' sessionID: '%s'", 624 1.1 christos status, session_id); 625 1.1 christos 626 1.1 christos xml_node_for_each_child(ctx->xml, child, node) { 627 1.1 christos const char *name; 628 1.1 christos xml_node_for_each_check(ctx->xml, child); 629 1.1 christos debug_dump_node(ctx, "child", child); 630 1.1 christos name = xml_node_get_localname(ctx->xml, child); 631 1.1 christos wpa_printf(MSG_INFO, "localname: '%s'", name); 632 1.1 christos if (!update && strcasecmp(name, "updateNode") == 0) 633 1.1 christos update = child; 634 1.1 christos if (!exec && strcasecmp(name, "exec") == 0) 635 1.1 christos exec = child; 636 1.1 christos if (!add_mo && strcasecmp(name, "addMO") == 0) 637 1.1 christos add_mo = child; 638 1.1 christos if (!no_mo && strcasecmp(name, "noMOUpdate") == 0) 639 1.1 christos no_mo = child; 640 1.1 christos } 641 1.1 christos 642 1.1 christos if (use == SPP_SUBSCRIPTION_REMEDIATION && 643 1.1 christos strcasecmp(status, 644 1.1 christos "Remediation complete, request sppUpdateResponse") == 0) 645 1.1 christos { 646 1.1 christos int res, ret; 647 1.1 christos if (!update && !no_mo) { 648 1.1 christos wpa_printf(MSG_INFO, "No updateNode or noMOUpdate element"); 649 1.1 christos goto out; 650 1.1 christos } 651 1.1 christos wpa_printf(MSG_INFO, "Subscription remediation completed"); 652 1.1 christos res = update_pps(ctx, update, pps_fname, pps); 653 1.1 christos if (res < 0) 654 1.1 christos wpa_printf(MSG_INFO, "Failed to update PPS MO"); 655 1.1 christos ret = hs20_spp_update_response( 656 1.1 christos ctx, session_id, 657 1.1 christos res < 0 ? "Error occurred" : "OK", 658 1.1 christos res < 0 ? "MO addition or update failed" : NULL); 659 1.1 christos if (res == 0 && ret == 0) 660 1.1 christos hs20_sub_rem_complete(ctx, pps_fname); 661 1.1 christos goto out; 662 1.1 christos } 663 1.1 christos 664 1.1 christos if (use == SPP_SUBSCRIPTION_REMEDIATION && 665 1.1 christos strcasecmp(status, "Exchange complete, release TLS connection") == 666 1.1 christos 0) { 667 1.1 christos if (!no_mo) { 668 1.1 christos wpa_printf(MSG_INFO, "No noMOUpdate element"); 669 1.1 christos goto out; 670 1.1 christos } 671 1.1 christos wpa_printf(MSG_INFO, "Subscription remediation completed (no MO update)"); 672 1.1 christos goto out; 673 1.1 christos } 674 1.1 christos 675 1.1 christos if (use == SPP_POLICY_UPDATE && 676 1.1 christos strcasecmp(status, "Update complete, request sppUpdateResponse") == 677 1.1 christos 0) { 678 1.1 christos int res, ret; 679 1.1 christos wpa_printf(MSG_INFO, "Policy update received - update PPS"); 680 1.1 christos res = update_pps(ctx, update, pps_fname, pps); 681 1.1 christos ret = hs20_spp_update_response( 682 1.1 christos ctx, session_id, 683 1.1 christos res < 0 ? "Error occurred" : "OK", 684 1.1 christos res < 0 ? "MO addition or update failed" : NULL); 685 1.1 christos if (res == 0 && ret == 0) 686 1.1 christos hs20_policy_update_complete(ctx, pps_fname); 687 1.1 christos goto out; 688 1.1 christos } 689 1.1 christos 690 1.1 christos if (use == SPP_SUBSCRIPTION_REGISTRATION && 691 1.1 christos strcasecmp(status, "Provisioning complete, request " 692 1.1 christos "sppUpdateResponse") == 0) { 693 1.1 christos if (!add_mo) { 694 1.1 christos wpa_printf(MSG_INFO, "No addMO element - not sure what to do next"); 695 1.1 christos goto out; 696 1.1 christos } 697 1.1 christos process_spp_user_input_response(ctx, session_id, add_mo); 698 1.1 christos node = NULL; 699 1.1 christos goto out; 700 1.1 christos } 701 1.1 christos 702 1.1 christos if (strcasecmp(status, "No update available at this time") == 0) { 703 1.1 christos wpa_printf(MSG_INFO, "No update available at this time"); 704 1.1 christos goto out; 705 1.1 christos } 706 1.1 christos 707 1.1 christos if (strcasecmp(status, "OK") == 0) { 708 1.1 christos int res; 709 1.1 christos xml_node_t *ret; 710 1.1 christos 711 1.1 christos if (!exec) { 712 1.1 christos wpa_printf(MSG_INFO, "No exec element - not sure what to do next"); 713 1.1 christos goto out; 714 1.1 christos } 715 1.1 christos res = hs20_spp_exec(ctx, exec, session_id, 716 1.1 christos pps_fname, pps, &ret); 717 1.1 christos /* xml_node_free(ctx->xml, node); */ 718 1.1 christos node = NULL; 719 1.1 christos if (res == 0 && ret) 720 1.1 christos process_spp_post_dev_data_response(ctx, use, 721 1.1 christos ret, pps_fname, pps); 722 1.1 christos goto out; 723 1.1 christos } 724 1.1 christos 725 1.1 christos if (strcasecmp(status, "Error occurred") == 0) { 726 1.1 christos xml_node_t *err; 727 1.1 christos char *code = NULL; 728 1.1 christos err = get_node(ctx->xml, node, "sppError"); 729 1.1 christos if (err) 730 1.1 christos code = xml_node_get_attr_value(ctx->xml, err, 731 1.1 christos "errorCode"); 732 1.1 christos wpa_printf(MSG_INFO, "Error occurred - errorCode=%s", 733 1.1 christos code ? code : "N/A"); 734 1.1 christos xml_node_get_attr_value_free(ctx->xml, code); 735 1.1 christos goto out; 736 1.1 christos } 737 1.1 christos 738 1.1 christos wpa_printf(MSG_INFO, 739 1.1 christos "[hs20] Unsupported sppPostDevDataResponse sppStatus '%s'", 740 1.1 christos status); 741 1.1 christos out: 742 1.1 christos xml_node_get_attr_value_free(ctx->xml, status); 743 1.1 christos xml_node_get_attr_value_free(ctx->xml, session_id); 744 1.1 christos xml_node_free(ctx->xml, node); 745 1.1 christos } 746 1.1 christos 747 1.1 christos 748 1.1 christos static int spp_post_dev_data(struct hs20_osu_client *ctx, 749 1.1 christos enum spp_post_dev_data_use use, 750 1.1 christos const char *reason, 751 1.1 christos const char *pps_fname, xml_node_t *pps) 752 1.1 christos { 753 1.1 christos xml_node_t *payload; 754 1.1 christos xml_node_t *ret_node; 755 1.1 christos 756 1.1 christos payload = build_spp_post_dev_data(ctx, NULL, NULL, reason); 757 1.1 christos if (payload == NULL) 758 1.1 christos return -1; 759 1.1 christos 760 1.1 christos ret_node = soap_send_receive(ctx->http, payload); 761 1.1 christos if (!ret_node) { 762 1.1 christos const char *err = http_get_err(ctx->http); 763 1.1 christos if (err) { 764 1.1 christos wpa_printf(MSG_INFO, "HTTP error: %s", err); 765 1.1 christos write_result(ctx, "HTTP error: %s", err); 766 1.1 christos } else { 767 1.1 christos write_summary(ctx, "Failed to send SOAP message"); 768 1.1 christos } 769 1.1 christos return -1; 770 1.1 christos } 771 1.1 christos 772 1.1 christos if (hs20_spp_validate(ctx, ret_node, "sppPostDevDataResponse") < 0) { 773 1.1 christos wpa_printf(MSG_INFO, "SPP validation failed"); 774 1.1 christos xml_node_free(ctx->xml, ret_node); 775 1.1 christos return -1; 776 1.1 christos } 777 1.1 christos 778 1.1 christos process_spp_post_dev_data_response(ctx, use, ret_node, 779 1.1 christos pps_fname, pps); 780 1.1 christos return 0; 781 1.1 christos } 782 1.1 christos 783 1.1 christos 784 1.1 christos void spp_sub_rem(struct hs20_osu_client *ctx, const char *address, 785 1.1 christos const char *pps_fname, 786 1.1 christos const char *client_cert, const char *client_key, 787 1.1 christos const char *cred_username, const char *cred_password, 788 1.1 christos xml_node_t *pps) 789 1.1 christos { 790 1.1 christos wpa_printf(MSG_INFO, "SPP subscription remediation"); 791 1.1 christos write_summary(ctx, "SPP subscription remediation"); 792 1.1 christos 793 1.1 christos os_free(ctx->server_url); 794 1.1 christos ctx->server_url = os_strdup(address); 795 1.1 christos 796 1.1 christos if (soap_init_client(ctx->http, address, ctx->ca_fname, 797 1.1 christos cred_username, cred_password, client_cert, 798 1.1 christos client_key) == 0) { 799 1.1 christos spp_post_dev_data(ctx, SPP_SUBSCRIPTION_REMEDIATION, 800 1.1 christos "Subscription remediation", pps_fname, pps); 801 1.1 christos } 802 1.1 christos } 803 1.1 christos 804 1.1 christos 805 1.1 christos static void hs20_policy_update_complete(struct hs20_osu_client *ctx, 806 1.1 christos const char *pps_fname) 807 1.1 christos { 808 1.1 christos wpa_printf(MSG_INFO, "Policy update completed"); 809 1.1 christos 810 1.1 christos /* 811 1.1 christos * Update wpa_supplicant credentials and reconnect using updated 812 1.1 christos * information. 813 1.1 christos */ 814 1.1 christos wpa_printf(MSG_INFO, "Updating wpa_supplicant credentials"); 815 1.1 christos cmd_set_pps(ctx, pps_fname); 816 1.1 christos 817 1.1 christos wpa_printf(MSG_INFO, "Requesting reconnection with updated configuration"); 818 1.1 christos if (wpa_command(ctx->ifname, "INTERWORKING_SELECT auto") < 0) 819 1.1 christos wpa_printf(MSG_ERROR, "Failed to request wpa_supplicant to reconnect"); 820 1.1 christos } 821 1.1 christos 822 1.1 christos 823 1.1 christos static int process_spp_exchange_complete(struct hs20_osu_client *ctx, 824 1.1 christos xml_node_t *node) 825 1.1 christos { 826 1.1 christos char *status, *session_id; 827 1.1 christos 828 1.1 christos debug_dump_node(ctx, "sppExchangeComplete", node); 829 1.1 christos 830 1.1 christos status = get_spp_attr_value(ctx->xml, node, "sppStatus"); 831 1.1 christos if (status == NULL) { 832 1.1 christos wpa_printf(MSG_INFO, "No sppStatus attribute"); 833 1.1 christos return -1; 834 1.1 christos } 835 1.1 christos write_summary(ctx, "Received sppExchangeComplete sppStatus='%s'", 836 1.1 christos status); 837 1.1 christos 838 1.1 christos session_id = get_spp_attr_value(ctx->xml, node, "sessionID"); 839 1.1 christos if (session_id == NULL) { 840 1.1 christos wpa_printf(MSG_INFO, "No sessionID attribute"); 841 1.1 christos xml_node_get_attr_value_free(ctx->xml, status); 842 1.1 christos return -1; 843 1.1 christos } 844 1.1 christos 845 1.1 christos wpa_printf(MSG_INFO, "[hs20] sppStatus: '%s' sessionID: '%s'", 846 1.1 christos status, session_id); 847 1.1 christos xml_node_get_attr_value_free(ctx->xml, session_id); 848 1.1 christos 849 1.1 christos if (strcasecmp(status, "Exchange complete, release TLS connection") == 850 1.1 christos 0) { 851 1.1 christos xml_node_get_attr_value_free(ctx->xml, status); 852 1.1 christos return 0; 853 1.1 christos } 854 1.1 christos 855 1.1 christos wpa_printf(MSG_INFO, "Unexpected sppStatus '%s'", status); 856 1.1 christos write_summary(ctx, "Unexpected sppStatus '%s'", status); 857 1.1 christos xml_node_get_attr_value_free(ctx->xml, status); 858 1.1 christos return -1; 859 1.1 christos } 860 1.1 christos 861 1.1 christos 862 1.1 christos static xml_node_t * build_spp_update_response(struct hs20_osu_client *ctx, 863 1.1 christos const char *session_id, 864 1.1 christos const char *spp_status, 865 1.1 christos const char *error_code) 866 1.1 christos { 867 1.1 christos xml_namespace_t *ns; 868 1.1 christos xml_node_t *spp_node, *node; 869 1.1 christos 870 1.1 christos spp_node = xml_node_create_root(ctx->xml, SPP_NS_URI, "spp", &ns, 871 1.1 christos "sppUpdateResponse"); 872 1.1 christos if (spp_node == NULL) 873 1.1 christos return NULL; 874 1.1 christos 875 1.1 christos xml_node_add_attr(ctx->xml, spp_node, ns, "sppVersion", "1.0"); 876 1.1 christos xml_node_add_attr(ctx->xml, spp_node, ns, "sessionID", session_id); 877 1.1 christos xml_node_add_attr(ctx->xml, spp_node, ns, "sppStatus", spp_status); 878 1.1 christos 879 1.1 christos if (error_code) { 880 1.1 christos node = xml_node_create(ctx->xml, spp_node, ns, "sppError"); 881 1.1 christos if (node) 882 1.1 christos xml_node_add_attr(ctx->xml, node, NULL, "errorCode", 883 1.1 christos error_code); 884 1.1 christos } 885 1.1 christos 886 1.1 christos return spp_node; 887 1.1 christos } 888 1.1 christos 889 1.1 christos 890 1.1 christos static int hs20_spp_update_response(struct hs20_osu_client *ctx, 891 1.1 christos const char *session_id, 892 1.1 christos const char *spp_status, 893 1.1 christos const char *error_code) 894 1.1 christos { 895 1.1 christos xml_node_t *node, *ret_node; 896 1.1 christos int ret; 897 1.1 christos 898 1.1 christos write_summary(ctx, "Building sppUpdateResponse sppStatus='%s' error_code='%s'", 899 1.1 christos spp_status, error_code); 900 1.1 christos node = build_spp_update_response(ctx, session_id, spp_status, 901 1.1 christos error_code); 902 1.1 christos if (node == NULL) 903 1.1 christos return -1; 904 1.1 christos ret_node = soap_send_receive(ctx->http, node); 905 1.1 christos if (!ret_node) { 906 1.1 christos if (soap_reinit_client(ctx->http) < 0) 907 1.1 christos return -1; 908 1.1 christos wpa_printf(MSG_INFO, "Try to finish with re-opened connection"); 909 1.1 christos node = build_spp_update_response(ctx, session_id, spp_status, 910 1.1 christos error_code); 911 1.1 christos if (node == NULL) 912 1.1 christos return -1; 913 1.1 christos ret_node = soap_send_receive(ctx->http, node); 914 1.1 christos if (ret_node == NULL) 915 1.1 christos return -1; 916 1.1 christos wpa_printf(MSG_INFO, "Continue with new connection"); 917 1.1 christos } 918 1.1 christos 919 1.1 christos if (hs20_spp_validate(ctx, ret_node, "sppExchangeComplete") < 0) { 920 1.1 christos wpa_printf(MSG_INFO, "SPP validation failed"); 921 1.1 christos xml_node_free(ctx->xml, ret_node); 922 1.1 christos return -1; 923 1.1 christos } 924 1.1 christos 925 1.1 christos ret = process_spp_exchange_complete(ctx, ret_node); 926 1.1 christos xml_node_free(ctx->xml, ret_node); 927 1.1 christos return ret; 928 1.1 christos } 929 1.1 christos 930 1.1 christos 931 1.1 christos void spp_pol_upd(struct hs20_osu_client *ctx, const char *address, 932 1.1 christos const char *pps_fname, 933 1.1 christos const char *client_cert, const char *client_key, 934 1.1 christos const char *cred_username, const char *cred_password, 935 1.1 christos xml_node_t *pps) 936 1.1 christos { 937 1.1 christos wpa_printf(MSG_INFO, "SPP policy update"); 938 1.1 christos write_summary(ctx, "SPP policy update"); 939 1.1 christos 940 1.1 christos os_free(ctx->server_url); 941 1.1 christos ctx->server_url = os_strdup(address); 942 1.1 christos 943 1.1 christos if (soap_init_client(ctx->http, address, ctx->ca_fname, cred_username, 944 1.1 christos cred_password, client_cert, client_key) == 0) { 945 1.1 christos spp_post_dev_data(ctx, SPP_POLICY_UPDATE, "Policy update", 946 1.1 christos pps_fname, pps); 947 1.1 christos } 948 1.1 christos } 949 1.1 christos 950 1.1 christos 951 1.1 christos int cmd_prov(struct hs20_osu_client *ctx, const char *url) 952 1.1 christos { 953 1.1 christos unlink("Cert/est_cert.der"); 954 1.1 christos unlink("Cert/est_cert.pem"); 955 1.1 christos 956 1.1 christos if (url == NULL) { 957 1.1 christos wpa_printf(MSG_INFO, "Invalid prov command (missing URL)"); 958 1.1 christos return -1; 959 1.1 christos } 960 1.1 christos 961 1.1.1.2 christos wpa_printf(MSG_INFO, 962 1.1.1.2 christos "Credential provisioning requested - URL: %s ca_fname: %s", 963 1.1.1.2 christos url, ctx->ca_fname ? ctx->ca_fname : "N/A"); 964 1.1 christos 965 1.1 christos os_free(ctx->server_url); 966 1.1 christos ctx->server_url = os_strdup(url); 967 1.1 christos 968 1.1 christos if (soap_init_client(ctx->http, url, ctx->ca_fname, NULL, NULL, NULL, 969 1.1 christos NULL) < 0) 970 1.1 christos return -1; 971 1.1 christos spp_post_dev_data(ctx, SPP_SUBSCRIPTION_REGISTRATION, 972 1.1 christos "Subscription registration", NULL, NULL); 973 1.1 christos 974 1.1 christos return ctx->pps_cred_set ? 0 : -1; 975 1.1 christos } 976 1.1 christos 977 1.1 christos 978 1.1 christos int cmd_sim_prov(struct hs20_osu_client *ctx, const char *url) 979 1.1 christos { 980 1.1 christos if (url == NULL) { 981 1.1 christos wpa_printf(MSG_INFO, "Invalid prov command (missing URL)"); 982 1.1 christos return -1; 983 1.1 christos } 984 1.1 christos 985 1.1 christos wpa_printf(MSG_INFO, "SIM provisioning requested"); 986 1.1 christos 987 1.1 christos os_free(ctx->server_url); 988 1.1 christos ctx->server_url = os_strdup(url); 989 1.1 christos 990 1.1 christos wpa_printf(MSG_INFO, "Wait for IP address before starting SIM provisioning"); 991 1.1 christos 992 1.1 christos if (wait_ip_addr(ctx->ifname, 15) < 0) { 993 1.1 christos wpa_printf(MSG_INFO, "Could not get IP address for WLAN - try connection anyway"); 994 1.1 christos } 995 1.1 christos 996 1.1 christos if (soap_init_client(ctx->http, url, ctx->ca_fname, NULL, NULL, NULL, 997 1.1 christos NULL) < 0) 998 1.1 christos return -1; 999 1.1 christos spp_post_dev_data(ctx, SPP_SUBSCRIPTION_REGISTRATION, 1000 1.1 christos "Subscription provisioning", NULL, NULL); 1001 1.1 christos 1002 1.1 christos return ctx->pps_cred_set ? 0 : -1; 1003 1.1 christos } 1004