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