spp_client.c revision 1.1.1.3 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