1 /*
2 * Hotspot 2.0 - OMA DM client
3 * Copyright (c) 2013-2014, Qualcomm Atheros, Inc.
4 *
5 * This software may be distributed under the terms of the BSD license.
6 * See README for more details.
7 */
8
9 #include "includes.h"
10
11 #include "common.h"
12 #include "wpa_helpers.h"
13 #include "xml-utils.h"
14 #include "http-utils.h"
15 #include "utils/browser.h"
16 #include "osu_client.h"
17
18
19 #define DM_SERVER_INITIATED_MGMT 1200
20 #define DM_CLIENT_INITIATED_MGMT 1201
21 #define DM_GENERIC_ALERT 1226
22
23 /* OMA-TS-SyncML-RepPro-V1_2_2 - 10. Response Status Codes */
24 #define DM_RESP_OK 200
25 #define DM_RESP_AUTH_ACCEPTED 212
26 #define DM_RESP_CHUNKED_ITEM_ACCEPTED 213
27 #define DM_RESP_NOT_EXECUTED 215
28 #define DM_RESP_ATOMIC_ROLL_BACK_OK 216
29 #define DM_RESP_NOT_MODIFIED 304
30 #define DM_RESP_BAD_REQUEST 400
31 #define DM_RESP_UNAUTHORIZED 401
32 #define DM_RESP_FORBIDDEN 403
33 #define DM_RESP_NOT_FOUND 404
34 #define DM_RESP_COMMAND_NOT_ALLOWED 405
35 #define DM_RESP_OPTIONAL_FEATURE_NOT_SUPPORTED 406
36 #define DM_RESP_MISSING_CREDENTIALS 407
37 #define DM_RESP_CONFLICT 409
38 #define DM_RESP_GONE 410
39 #define DM_RESP_INCOMPLETE_COMMAND 412
40 #define DM_RESP_REQ_ENTITY_TOO_LARGE 413
41 #define DM_RESP_URI_TOO_LONG 414
42 #define DM_RESP_UNSUPPORTED_MEDIA_TYPE_OR_FORMAT 415
43 #define DM_RESP_REQ_TOO_BIG 416
44 #define DM_RESP_ALREADY_EXISTS 418
45 #define DM_RESP_DEVICE_FULL 420
46 #define DM_RESP_SIZE_MISMATCH 424
47 #define DM_RESP_PERMISSION_DENIED 425
48 #define DM_RESP_COMMAND_FAILED 500
49 #define DM_RESP_COMMAND_NOT_IMPLEMENTED 501
50 #define DM_RESP_ATOMIC_ROLL_BACK_FAILED 516
51
52 #define DM_HS20_SUBSCRIPTION_CREATION \
53 "org.wi-fi.hotspot2dot0.SubscriptionCreation"
54 #define DM_HS20_SUBSCRIPTION_PROVISIONING \
55 "org.wi-fi.hotspot2dot0.SubscriptionProvisioning"
56 #define DM_HS20_SUBSCRIPTION_REMEDIATION \
57 "org.wi-fi.hotspot2dot0.SubscriptionRemediation"
58 #define DM_HS20_POLICY_UPDATE \
59 "org.wi-fi.hotspot2dot0.PolicyUpdate"
60
61 #define DM_URI_PPS "./Wi-Fi/org.wi-fi/PerProviderSubscription"
62 #define DM_URI_LAUNCH_BROWSER \
63 "./DevDetail/Ext/org.wi-fi/Wi-Fi/Ops/launchBrowserToURI"
64
65
66 static void add_item(struct hs20_osu_client *ctx, xml_node_t *parent,
67 const char *locuri, const char *data);
68
69
int2str(int val)70 static const char * int2str(int val)
71 {
72 static char buf[20];
73 snprintf(buf, sizeof(buf), "%d", val);
74 return buf;
75 }
76
77
oma_dm_get_target_locuri(struct hs20_osu_client * ctx,xml_node_t * node)78 static char * oma_dm_get_target_locuri(struct hs20_osu_client *ctx,
79 xml_node_t *node)
80 {
81 xml_node_t *locuri;
82 char *uri, *ret = NULL;
83
84 locuri = get_node(ctx->xml, node, "Item/Target/LocURI");
85 if (locuri == NULL)
86 return NULL;
87
88 uri = xml_node_get_text(ctx->xml, locuri);
89 if (uri)
90 ret = os_strdup(uri);
91 xml_node_get_text_free(ctx->xml, uri);
92 return ret;
93 }
94
95
oma_dm_add_locuri(struct hs20_osu_client * ctx,xml_node_t * parent,const char * element,const char * uri)96 static void oma_dm_add_locuri(struct hs20_osu_client *ctx, xml_node_t *parent,
97 const char *element, const char *uri)
98 {
99 xml_node_t *node;
100
101 node = xml_node_create(ctx->xml, parent, NULL, element);
102 if (node == NULL)
103 return;
104 xml_node_create_text(ctx->xml, node, NULL, "LocURI", uri);
105 }
106
107
oma_dm_build_hdr(struct hs20_osu_client * ctx,const char * url,int msgid)108 static xml_node_t * oma_dm_build_hdr(struct hs20_osu_client *ctx,
109 const char *url, int msgid)
110 {
111 xml_node_t *syncml, *synchdr;
112 xml_namespace_t *ns;
113
114 syncml = xml_node_create_root(ctx->xml, "SYNCML:SYNCML1.2", NULL, &ns,
115 "SyncML");
116
117 synchdr = xml_node_create(ctx->xml, syncml, NULL, "SyncHdr");
118 xml_node_create_text(ctx->xml, synchdr, NULL, "VerDTD", "1.2");
119 xml_node_create_text(ctx->xml, synchdr, NULL, "VerProto", "DM/1.2");
120 xml_node_create_text(ctx->xml, synchdr, NULL, "SessionID", "1");
121 xml_node_create_text(ctx->xml, synchdr, NULL, "MsgID", int2str(msgid));
122
123 oma_dm_add_locuri(ctx, synchdr, "Target", url);
124 oma_dm_add_locuri(ctx, synchdr, "Source", ctx->devid);
125
126 return syncml;
127 }
128
129
oma_dm_add_cmdid(struct hs20_osu_client * ctx,xml_node_t * parent,int cmdid)130 static void oma_dm_add_cmdid(struct hs20_osu_client *ctx, xml_node_t *parent,
131 int cmdid)
132 {
133 xml_node_create_text(ctx->xml, parent, NULL, "CmdID", int2str(cmdid));
134 }
135
136
add_alert(struct hs20_osu_client * ctx,xml_node_t * parent,int cmdid,int data)137 static xml_node_t * add_alert(struct hs20_osu_client *ctx, xml_node_t *parent,
138 int cmdid, int data)
139 {
140 xml_node_t *node;
141
142 node = xml_node_create(ctx->xml, parent, NULL, "Alert");
143 if (node == NULL)
144 return NULL;
145 oma_dm_add_cmdid(ctx, node, cmdid);
146 xml_node_create_text(ctx->xml, node, NULL, "Data", int2str(data));
147
148 return node;
149 }
150
151
add_status(struct hs20_osu_client * ctx,xml_node_t * parent,int msgref,int cmdref,int cmdid,const char * cmd,int data,const char * targetref)152 static xml_node_t * add_status(struct hs20_osu_client *ctx, xml_node_t *parent,
153 int msgref, int cmdref, int cmdid,
154 const char *cmd, int data, const char *targetref)
155 {
156 xml_node_t *node;
157
158 node = xml_node_create(ctx->xml, parent, NULL, "Status");
159 if (node == NULL)
160 return NULL;
161 oma_dm_add_cmdid(ctx, node, cmdid);
162 xml_node_create_text(ctx->xml, node, NULL, "MsgRef", int2str(msgref));
163 if (cmdref)
164 xml_node_create_text(ctx->xml, node, NULL, "CmdRef",
165 int2str(cmdref));
166 xml_node_create_text(ctx->xml, node, NULL, "Cmd", cmd);
167 xml_node_create_text(ctx->xml, node, NULL, "Data", int2str(data));
168 if (targetref) {
169 xml_node_create_text(ctx->xml, node, NULL, "TargetRef",
170 targetref);
171 }
172
173 return node;
174 }
175
176
add_results(struct hs20_osu_client * ctx,xml_node_t * parent,int msgref,int cmdref,int cmdid,const char * locuri,const char * data)177 static xml_node_t * add_results(struct hs20_osu_client *ctx, xml_node_t *parent,
178 int msgref, int cmdref, int cmdid,
179 const char *locuri, const char *data)
180 {
181 xml_node_t *node;
182
183 node = xml_node_create(ctx->xml, parent, NULL, "Results");
184 if (node == NULL)
185 return NULL;
186
187 oma_dm_add_cmdid(ctx, node, cmdid);
188 xml_node_create_text(ctx->xml, node, NULL, "MsgRef", int2str(msgref));
189 xml_node_create_text(ctx->xml, node, NULL, "CmdRef", int2str(cmdref));
190 add_item(ctx, node, locuri, data);
191
192 return node;
193 }
194
195
mo_str(struct hs20_osu_client * ctx,const char * urn,const char * fname)196 static char * mo_str(struct hs20_osu_client *ctx, const char *urn,
197 const char *fname)
198 {
199 xml_node_t *fnode, *tnds;
200 char *str;
201
202 fnode = node_from_file(ctx->xml, fname);
203 if (!fnode)
204 return NULL;
205 tnds = mo_to_tnds(ctx->xml, fnode, 0, urn, "syncml:dmddf1.2");
206 xml_node_free(ctx->xml, fnode);
207 if (!tnds)
208 return NULL;
209
210 str = xml_node_to_str(ctx->xml, tnds);
211 xml_node_free(ctx->xml, tnds);
212 if (str == NULL)
213 return NULL;
214 wpa_printf(MSG_INFO, "MgmtTree: %s", str);
215
216 return str;
217 }
218
219
add_item(struct hs20_osu_client * ctx,xml_node_t * parent,const char * locuri,const char * data)220 static void add_item(struct hs20_osu_client *ctx, xml_node_t *parent,
221 const char *locuri, const char *data)
222 {
223 xml_node_t *item, *node;
224
225 item = xml_node_create(ctx->xml, parent, NULL, "Item");
226 oma_dm_add_locuri(ctx, item, "Source", locuri);
227 node = xml_node_create(ctx->xml, item, NULL, "Meta");
228 xml_node_create_text_ns(ctx->xml, node, "syncml:metinf", "Format",
229 "Chr");
230 xml_node_create_text_ns(ctx->xml, node, "syncml:metinf", "Type",
231 "text/plain");
232 xml_node_create_text(ctx->xml, item, NULL, "Data", data);
233 }
234
235
add_replace_devinfo(struct hs20_osu_client * ctx,xml_node_t * parent,int cmdid)236 static void add_replace_devinfo(struct hs20_osu_client *ctx, xml_node_t *parent,
237 int cmdid)
238 {
239 xml_node_t *info, *child, *replace;
240 const char *name;
241 char locuri[200], *txt;
242
243 info = node_from_file(ctx->xml, "devinfo.xml");
244 if (info == NULL) {
245 wpa_printf(MSG_INFO, "Could not read devinfo.xml");
246 return;
247 }
248
249 replace = xml_node_create(ctx->xml, parent, NULL, "Replace");
250 if (replace == NULL) {
251 xml_node_free(ctx->xml, info);
252 return;
253 }
254 oma_dm_add_cmdid(ctx, replace, cmdid);
255
256 xml_node_for_each_child(ctx->xml, child, info) {
257 xml_node_for_each_check(ctx->xml, child);
258 name = xml_node_get_localname(ctx->xml, child);
259 os_snprintf(locuri, sizeof(locuri), "./DevInfo/%s", name);
260 txt = xml_node_get_text(ctx->xml, child);
261 if (txt) {
262 add_item(ctx, replace, locuri, txt);
263 xml_node_get_text_free(ctx->xml, txt);
264 }
265 }
266
267 xml_node_free(ctx->xml, info);
268 }
269
270
oma_dm_add_hs20_generic_alert(struct hs20_osu_client * ctx,xml_node_t * syncbody,int cmdid,const char * oper,const char * data)271 static void oma_dm_add_hs20_generic_alert(struct hs20_osu_client *ctx,
272 xml_node_t *syncbody,
273 int cmdid, const char *oper,
274 const char *data)
275 {
276 xml_node_t *node, *item;
277 char buf[200];
278
279 node = add_alert(ctx, syncbody, cmdid, DM_GENERIC_ALERT);
280
281 item = xml_node_create(ctx->xml, node, NULL, "Item");
282 oma_dm_add_locuri(ctx, item, "Source", DM_URI_PPS);
283 node = xml_node_create(ctx->xml, item, NULL, "Meta");
284 snprintf(buf, sizeof(buf), "Reversed-Domain-Name: %s", oper);
285 xml_node_create_text_ns(ctx->xml, node, "syncml:metinf", "Type", buf);
286 xml_node_create_text_ns(ctx->xml, node, "syncml:metinf", "Format",
287 "xml");
288 xml_node_create_text(ctx->xml, item, NULL, "Data", data);
289 }
290
291
build_oma_dm_1(struct hs20_osu_client * ctx,const char * url,int msgid,const char * oper)292 static xml_node_t * build_oma_dm_1(struct hs20_osu_client *ctx,
293 const char *url, int msgid, const char *oper)
294 {
295 xml_node_t *syncml, *syncbody;
296 char *str;
297 int cmdid = 0;
298
299 syncml = oma_dm_build_hdr(ctx, url, msgid);
300 if (syncml == NULL)
301 return NULL;
302
303 syncbody = xml_node_create(ctx->xml, syncml, NULL, "SyncBody");
304 if (syncbody == NULL) {
305 xml_node_free(ctx->xml, syncml);
306 return NULL;
307 }
308
309 cmdid++;
310 add_alert(ctx, syncbody, cmdid, DM_CLIENT_INITIATED_MGMT);
311
312 str = mo_str(ctx, NULL, "devdetail.xml");
313 if (str == NULL) {
314 xml_node_free(ctx->xml, syncml);
315 return NULL;
316 }
317 cmdid++;
318 oma_dm_add_hs20_generic_alert(ctx, syncbody, cmdid, oper, str);
319 os_free(str);
320
321 cmdid++;
322 add_replace_devinfo(ctx, syncbody, cmdid);
323
324 xml_node_create(ctx->xml, syncbody, NULL, "Final");
325
326 return syncml;
327 }
328
329
build_oma_dm_1_sub_reg(struct hs20_osu_client * ctx,const char * url,int msgid)330 static xml_node_t * build_oma_dm_1_sub_reg(struct hs20_osu_client *ctx,
331 const char *url, int msgid)
332 {
333 xml_node_t *syncml;
334
335 syncml = build_oma_dm_1(ctx, url, msgid, DM_HS20_SUBSCRIPTION_CREATION);
336 if (syncml)
337 debug_dump_node(ctx, "OMA-DM Package 1 (sub reg)", syncml);
338
339 return syncml;
340 }
341
342
build_oma_dm_1_sub_prov(struct hs20_osu_client * ctx,const char * url,int msgid)343 static xml_node_t * build_oma_dm_1_sub_prov(struct hs20_osu_client *ctx,
344 const char *url, int msgid)
345 {
346 xml_node_t *syncml;
347
348 syncml = build_oma_dm_1(ctx, url, msgid,
349 DM_HS20_SUBSCRIPTION_PROVISIONING);
350 if (syncml)
351 debug_dump_node(ctx, "OMA-DM Package 1 (sub prov)", syncml);
352
353 return syncml;
354 }
355
356
build_oma_dm_1_pol_upd(struct hs20_osu_client * ctx,const char * url,int msgid)357 static xml_node_t * build_oma_dm_1_pol_upd(struct hs20_osu_client *ctx,
358 const char *url, int msgid)
359 {
360 xml_node_t *syncml;
361
362 syncml = build_oma_dm_1(ctx, url, msgid, DM_HS20_POLICY_UPDATE);
363 if (syncml)
364 debug_dump_node(ctx, "OMA-DM Package 1 (pol upd)", syncml);
365
366 return syncml;
367 }
368
369
build_oma_dm_1_sub_rem(struct hs20_osu_client * ctx,const char * url,int msgid)370 static xml_node_t * build_oma_dm_1_sub_rem(struct hs20_osu_client *ctx,
371 const char *url, int msgid)
372 {
373 xml_node_t *syncml;
374
375 syncml = build_oma_dm_1(ctx, url, msgid,
376 DM_HS20_SUBSCRIPTION_REMEDIATION);
377 if (syncml)
378 debug_dump_node(ctx, "OMA-DM Package 1 (sub rem)", syncml);
379
380 return syncml;
381 }
382
383
oma_dm_exec_browser(struct hs20_osu_client * ctx,xml_node_t * exec)384 static int oma_dm_exec_browser(struct hs20_osu_client *ctx, xml_node_t *exec)
385 {
386 xml_node_t *node;
387 char *data;
388 int res;
389
390 node = get_node(ctx->xml, exec, "Item/Data");
391 if (node == NULL) {
392 wpa_printf(MSG_INFO, "No Data node found");
393 return DM_RESP_BAD_REQUEST;
394 }
395
396 data = xml_node_get_text(ctx->xml, node);
397 wpa_printf(MSG_INFO, "Data: %s", data);
398 wpa_printf(MSG_INFO, "Launch browser to URI '%s'", data);
399 write_summary(ctx, "Launch browser to URI '%s'", data);
400 res = hs20_web_browser(data);
401 xml_node_get_text_free(ctx->xml, data);
402 if (res > 0) {
403 wpa_printf(MSG_INFO, "User response in browser completed successfully");
404 write_summary(ctx, "User response in browser completed successfully");
405 return DM_RESP_OK;
406 } else {
407 wpa_printf(MSG_INFO, "Failed to receive user response");
408 write_summary(ctx, "Failed to receive user response");
409 return DM_RESP_COMMAND_FAILED;
410 }
411 }
412
413
oma_dm_exec_get_cert(struct hs20_osu_client * ctx,xml_node_t * exec)414 static int oma_dm_exec_get_cert(struct hs20_osu_client *ctx, xml_node_t *exec)
415 {
416 xml_node_t *node, *getcert;
417 char *data;
418 const char *name;
419 int res;
420
421 wpa_printf(MSG_INFO, "Client certificate enrollment");
422 write_summary(ctx, "Client certificate enrollment");
423
424 node = get_node(ctx->xml, exec, "Item/Data");
425 if (node == NULL) {
426 wpa_printf(MSG_INFO, "No Data node found");
427 return DM_RESP_BAD_REQUEST;
428 }
429
430 data = xml_node_get_text(ctx->xml, node);
431 wpa_printf(MSG_INFO, "Data: %s", data);
432 getcert = xml_node_from_buf(ctx->xml, data);
433 xml_node_get_text_free(ctx->xml, data);
434
435 if (getcert == NULL) {
436 wpa_printf(MSG_INFO, "Could not parse Item/Data node contents");
437 return DM_RESP_BAD_REQUEST;
438 }
439
440 debug_dump_node(ctx, "OMA-DM getCertificate", getcert);
441
442 name = xml_node_get_localname(ctx->xml, getcert);
443 if (name == NULL || os_strcasecmp(name, "getCertificate") != 0) {
444 wpa_printf(MSG_INFO, "Unexpected getCertificate node name '%s'",
445 name);
446 return DM_RESP_BAD_REQUEST;
447 }
448
449 res = osu_get_certificate(ctx, getcert);
450
451 xml_node_free(ctx->xml, getcert);
452
453 return res == 0 ? DM_RESP_OK : DM_RESP_COMMAND_FAILED;
454 }
455
456
oma_dm_exec(struct hs20_osu_client * ctx,xml_node_t * exec)457 static int oma_dm_exec(struct hs20_osu_client *ctx, xml_node_t *exec)
458 {
459 char *locuri;
460 int ret;
461
462 locuri = oma_dm_get_target_locuri(ctx, exec);
463 if (locuri == NULL) {
464 wpa_printf(MSG_INFO, "No Target LocURI node found");
465 return DM_RESP_BAD_REQUEST;
466 }
467
468 wpa_printf(MSG_INFO, "Target LocURI: %s", locuri);
469
470 if (os_strcasecmp(locuri, "./DevDetail/Ext/org.wi-fi/Wi-Fi/Ops/"
471 "launchBrowserToURI") == 0) {
472 ret = oma_dm_exec_browser(ctx, exec);
473 } else if (os_strcasecmp(locuri, "./DevDetail/Ext/org.wi-fi/Wi-Fi/Ops/"
474 "getCertificate") == 0) {
475 ret = oma_dm_exec_get_cert(ctx, exec);
476 } else {
477 wpa_printf(MSG_INFO, "Unsupported exec Target LocURI");
478 ret = DM_RESP_NOT_FOUND;
479 }
480 os_free(locuri);
481
482 return ret;
483 }
484
485
oma_dm_run_add(struct hs20_osu_client * ctx,const char * locuri,xml_node_t * add,xml_node_t * pps,const char * pps_fname)486 static int oma_dm_run_add(struct hs20_osu_client *ctx, const char *locuri,
487 xml_node_t *add, xml_node_t *pps,
488 const char *pps_fname)
489 {
490 const char *pos;
491 size_t fqdn_len;
492 xml_node_t *node, *tnds, *unode, *pps_node;
493 char *data, *uri, *upos, *end;
494 int use_tnds = 0;
495 size_t uri_len;
496
497 wpa_printf(MSG_INFO, "Add command target LocURI: %s", locuri);
498
499 if (os_strncasecmp(locuri, "./Wi-Fi/", 8) != 0) {
500 wpa_printf(MSG_INFO, "Do not allow Add outside ./Wi-Fi");
501 return DM_RESP_PERMISSION_DENIED;
502 }
503 pos = locuri + 8;
504
505 if (ctx->fqdn == NULL)
506 return DM_RESP_COMMAND_FAILED;
507 fqdn_len = os_strlen(ctx->fqdn);
508 if (os_strncasecmp(pos, ctx->fqdn, fqdn_len) != 0 ||
509 pos[fqdn_len] != '/') {
510 wpa_printf(MSG_INFO, "Do not allow Add outside ./Wi-Fi/%s",
511 ctx->fqdn);
512 return DM_RESP_PERMISSION_DENIED;
513 }
514 pos += fqdn_len + 1;
515
516 if (os_strncasecmp(pos, "PerProviderSubscription/", 24) != 0) {
517 wpa_printf(MSG_INFO,
518 "Do not allow Add outside ./Wi-Fi/%s/PerProviderSubscription",
519 ctx->fqdn);
520 return DM_RESP_PERMISSION_DENIED;
521 }
522 pos += 24;
523
524 wpa_printf(MSG_INFO, "Add command for PPS node %s", pos);
525
526 pps_node = get_node(ctx->xml, pps, pos);
527 if (pps_node) {
528 wpa_printf(MSG_INFO, "Specified PPS node exists already");
529 return DM_RESP_ALREADY_EXISTS;
530 }
531
532 uri = os_strdup(pos);
533 if (uri == NULL)
534 return DM_RESP_COMMAND_FAILED;
535 while (!pps_node) {
536 upos = os_strrchr(uri, '/');
537 if (!upos)
538 break;
539 upos[0] = '\0';
540 pps_node = get_node(ctx->xml, pps, uri);
541 wpa_printf(MSG_INFO, "Node %s %s", uri,
542 pps_node ? "exists" : "does not exist");
543 }
544
545 wpa_printf(MSG_INFO, "Parent URI: %s", uri);
546
547 if (!pps_node) {
548 /* Add at root of PPS MO */
549 pps_node = pps;
550 }
551
552 uri_len = os_strlen(uri);
553 os_strlcpy(uri, pos + uri_len, os_strlen(pos));
554 upos = uri;
555 while (*upos == '/')
556 upos++;
557 wpa_printf(MSG_INFO, "Nodes to add: %s", upos);
558
559 for (;;) {
560 end = os_strchr(upos, '/');
561 if (!end)
562 break;
563 *end = '\0';
564 wpa_printf(MSG_INFO, "Adding interim node %s", upos);
565 pps_node = xml_node_create(ctx->xml, pps_node, NULL, upos);
566 if (pps_node == NULL) {
567 os_free(uri);
568 return DM_RESP_COMMAND_FAILED;
569 }
570 upos = end + 1;
571 }
572
573 wpa_printf(MSG_INFO, "Adding node %s", upos);
574
575 node = get_node(ctx->xml, add, "Item/Meta/Type");
576 if (node) {
577 char *type;
578 type = xml_node_get_text(ctx->xml, node);
579 use_tnds = node &&
580 os_strstr(type, "application/vnd.syncml.dmtnds+xml");
581 }
582
583 node = get_node(ctx->xml, add, "Item/Data");
584 if (node == NULL) {
585 wpa_printf(MSG_INFO, "No Add/Item/Data found");
586 os_free(uri);
587 return DM_RESP_BAD_REQUEST;
588 }
589
590 data = xml_node_get_text(ctx->xml, node);
591 if (data == NULL) {
592 wpa_printf(MSG_INFO, "Could not get Add/Item/Data text");
593 os_free(uri);
594 return DM_RESP_BAD_REQUEST;
595 }
596
597 wpa_printf(MSG_DEBUG, "Add/Item/Data: %s", data);
598
599 if (use_tnds) {
600 tnds = xml_node_from_buf(ctx->xml, data);
601 xml_node_get_text_free(ctx->xml, data);
602 if (tnds == NULL) {
603 wpa_printf(MSG_INFO,
604 "Could not parse Add/Item/Data text");
605 os_free(uri);
606 return DM_RESP_BAD_REQUEST;
607 }
608
609 unode = tnds_to_mo(ctx->xml, tnds);
610 xml_node_free(ctx->xml, tnds);
611 if (unode == NULL) {
612 wpa_printf(MSG_INFO, "Could not parse TNDS text");
613 os_free(uri);
614 return DM_RESP_BAD_REQUEST;
615 }
616
617 debug_dump_node(ctx, "Parsed TNDS", unode);
618
619 xml_node_add_child(ctx->xml, pps_node, unode);
620 } else {
621 /* TODO: What to do here? */
622 os_free(uri);
623 return DM_RESP_BAD_REQUEST;
624 }
625
626 os_free(uri);
627
628 if (update_pps_file(ctx, pps_fname, pps) < 0)
629 return DM_RESP_COMMAND_FAILED;
630
631 ctx->pps_updated = 1;
632
633 return DM_RESP_OK;
634 }
635
636
oma_dm_add(struct hs20_osu_client * ctx,xml_node_t * add,xml_node_t * pps,const char * pps_fname)637 static int oma_dm_add(struct hs20_osu_client *ctx, xml_node_t *add,
638 xml_node_t *pps, const char *pps_fname)
639 {
640 xml_node_t *node;
641 char *locuri;
642 char fname[300];
643 int ret;
644
645 node = get_node(ctx->xml, add, "Item/Target/LocURI");
646 if (node == NULL) {
647 wpa_printf(MSG_INFO, "No Target LocURI node found");
648 return DM_RESP_BAD_REQUEST;
649 }
650 locuri = xml_node_get_text(ctx->xml, node);
651 wpa_printf(MSG_INFO, "Target LocURI: %s", locuri);
652 if (os_strncasecmp(locuri, "./Wi-Fi/", 8) != 0) {
653 wpa_printf(MSG_INFO, "Unsupported Add Target LocURI");
654 xml_node_get_text_free(ctx->xml, locuri);
655 return DM_RESP_PERMISSION_DENIED;
656 }
657
658 node = get_node(ctx->xml, add, "Item/Data");
659 if (node == NULL) {
660 wpa_printf(MSG_INFO, "No Data node found");
661 xml_node_get_text_free(ctx->xml, locuri);
662 return DM_RESP_BAD_REQUEST;
663 }
664
665 if (pps_fname && os_file_exists(pps_fname)) {
666 ret = oma_dm_run_add(ctx, locuri, add, pps, pps_fname);
667 if (ret != DM_RESP_OK) {
668 xml_node_get_text_free(ctx->xml, locuri);
669 return ret;
670 }
671 ret = 0;
672 os_strlcpy(fname, pps_fname, sizeof(fname));
673 } else
674 ret = hs20_add_pps_mo(ctx, locuri, node, fname, sizeof(fname));
675 xml_node_get_text_free(ctx->xml, locuri);
676 if (ret < 0)
677 return ret == -2 ? DM_RESP_ALREADY_EXISTS :
678 DM_RESP_COMMAND_FAILED;
679
680 if (ctx->no_reconnect == 2) {
681 os_snprintf(ctx->pps_fname, sizeof(ctx->pps_fname), "%s",
682 fname);
683 ctx->pps_cred_set = 1;
684 return DM_RESP_OK;
685 }
686
687 wpa_printf(MSG_INFO, "Updating wpa_supplicant credentials");
688 cmd_set_pps(ctx, fname);
689
690 if (ctx->no_reconnect)
691 return DM_RESP_OK;
692
693 wpa_printf(MSG_INFO, "Requesting reconnection with updated configuration");
694 if (wpa_command(ctx->ifname, "INTERWORKING_SELECT auto") < 0)
695 wpa_printf(MSG_INFO, "Failed to request wpa_supplicant to reconnect");
696
697 return DM_RESP_OK;
698 }
699
700
oma_dm_replace(struct hs20_osu_client * ctx,xml_node_t * replace,xml_node_t * pps,const char * pps_fname)701 static int oma_dm_replace(struct hs20_osu_client *ctx, xml_node_t *replace,
702 xml_node_t *pps, const char *pps_fname)
703 {
704 char *locuri, *pos;
705 size_t fqdn_len;
706 xml_node_t *node, *tnds, *unode, *pps_node, *parent;
707 char *data;
708 int use_tnds = 0;
709
710 locuri = oma_dm_get_target_locuri(ctx, replace);
711 if (locuri == NULL)
712 return DM_RESP_BAD_REQUEST;
713
714 wpa_printf(MSG_INFO, "Replace command target LocURI: %s", locuri);
715 if (os_strncasecmp(locuri, "./Wi-Fi/", 8) != 0) {
716 wpa_printf(MSG_INFO, "Do not allow Replace outside ./Wi-Fi");
717 os_free(locuri);
718 return DM_RESP_PERMISSION_DENIED;
719 }
720 pos = locuri + 8;
721
722 if (ctx->fqdn == NULL) {
723 os_free(locuri);
724 return DM_RESP_COMMAND_FAILED;
725 }
726 fqdn_len = os_strlen(ctx->fqdn);
727 if (os_strncasecmp(pos, ctx->fqdn, fqdn_len) != 0 ||
728 pos[fqdn_len] != '/') {
729 wpa_printf(MSG_INFO, "Do not allow Replace outside ./Wi-Fi/%s",
730 ctx->fqdn);
731 os_free(locuri);
732 return DM_RESP_PERMISSION_DENIED;
733 }
734 pos += fqdn_len + 1;
735
736 if (os_strncasecmp(pos, "PerProviderSubscription/", 24) != 0) {
737 wpa_printf(MSG_INFO,
738 "Do not allow Replace outside ./Wi-Fi/%s/PerProviderSubscription",
739 ctx->fqdn);
740 os_free(locuri);
741 return DM_RESP_PERMISSION_DENIED;
742 }
743 pos += 24;
744
745 wpa_printf(MSG_INFO, "Replace command for PPS node %s", pos);
746
747 pps_node = get_node(ctx->xml, pps, pos);
748 if (pps_node == NULL) {
749 wpa_printf(MSG_INFO, "Specified PPS node not found");
750 os_free(locuri);
751 return DM_RESP_NOT_FOUND;
752 }
753
754 node = get_node(ctx->xml, replace, "Item/Meta/Type");
755 if (node) {
756 char *type;
757 type = xml_node_get_text(ctx->xml, node);
758 use_tnds = node &&
759 os_strstr(type, "application/vnd.syncml.dmtnds+xml");
760 }
761
762 node = get_node(ctx->xml, replace, "Item/Data");
763 if (node == NULL) {
764 wpa_printf(MSG_INFO, "No Replace/Item/Data found");
765 os_free(locuri);
766 return DM_RESP_BAD_REQUEST;
767 }
768
769 data = xml_node_get_text(ctx->xml, node);
770 if (data == NULL) {
771 wpa_printf(MSG_INFO, "Could not get Replace/Item/Data text");
772 os_free(locuri);
773 return DM_RESP_BAD_REQUEST;
774 }
775
776 wpa_printf(MSG_DEBUG, "Replace/Item/Data: %s", data);
777
778 if (use_tnds) {
779 tnds = xml_node_from_buf(ctx->xml, data);
780 xml_node_get_text_free(ctx->xml, data);
781 if (tnds == NULL) {
782 wpa_printf(MSG_INFO,
783 "Could not parse Replace/Item/Data text");
784 os_free(locuri);
785 return DM_RESP_BAD_REQUEST;
786 }
787
788 unode = tnds_to_mo(ctx->xml, tnds);
789 xml_node_free(ctx->xml, tnds);
790 if (unode == NULL) {
791 wpa_printf(MSG_INFO, "Could not parse TNDS text");
792 os_free(locuri);
793 return DM_RESP_BAD_REQUEST;
794 }
795
796 debug_dump_node(ctx, "Parsed TNDS", unode);
797
798 parent = xml_node_get_parent(ctx->xml, pps_node);
799 xml_node_detach(ctx->xml, pps_node);
800 xml_node_add_child(ctx->xml, parent, unode);
801 } else {
802 xml_node_set_text(ctx->xml, pps_node, data);
803 xml_node_get_text_free(ctx->xml, data);
804 }
805
806 os_free(locuri);
807
808 if (update_pps_file(ctx, pps_fname, pps) < 0)
809 return DM_RESP_COMMAND_FAILED;
810
811 ctx->pps_updated = 1;
812
813 return DM_RESP_OK;
814 }
815
816
oma_dm_get(struct hs20_osu_client * ctx,xml_node_t * get,xml_node_t * pps,const char * pps_fname,char ** value)817 static int oma_dm_get(struct hs20_osu_client *ctx, xml_node_t *get,
818 xml_node_t *pps, const char *pps_fname, char **value)
819 {
820 char *locuri, *pos;
821 size_t fqdn_len;
822 xml_node_t *pps_node;
823 const char *name;
824
825 *value = NULL;
826
827 locuri = oma_dm_get_target_locuri(ctx, get);
828 if (locuri == NULL)
829 return DM_RESP_BAD_REQUEST;
830
831 wpa_printf(MSG_INFO, "Get command target LocURI: %s", locuri);
832 if (os_strncasecmp(locuri, "./Wi-Fi/", 8) != 0) {
833 wpa_printf(MSG_INFO, "Do not allow Get outside ./Wi-Fi");
834 os_free(locuri);
835 return DM_RESP_PERMISSION_DENIED;
836 }
837 pos = locuri + 8;
838
839 if (ctx->fqdn == NULL)
840 return DM_RESP_COMMAND_FAILED;
841 fqdn_len = os_strlen(ctx->fqdn);
842 if (os_strncasecmp(pos, ctx->fqdn, fqdn_len) != 0 ||
843 pos[fqdn_len] != '/') {
844 wpa_printf(MSG_INFO, "Do not allow Get outside ./Wi-Fi/%s",
845 ctx->fqdn);
846 os_free(locuri);
847 return DM_RESP_PERMISSION_DENIED;
848 }
849 pos += fqdn_len + 1;
850
851 if (os_strncasecmp(pos, "PerProviderSubscription/", 24) != 0) {
852 wpa_printf(MSG_INFO,
853 "Do not allow Get outside ./Wi-Fi/%s/PerProviderSubscription",
854 ctx->fqdn);
855 os_free(locuri);
856 return DM_RESP_PERMISSION_DENIED;
857 }
858 pos += 24;
859
860 wpa_printf(MSG_INFO, "Get command for PPS node %s", pos);
861
862 pps_node = get_node(ctx->xml, pps, pos);
863 if (pps_node == NULL) {
864 wpa_printf(MSG_INFO, "Specified PPS node not found");
865 os_free(locuri);
866 return DM_RESP_NOT_FOUND;
867 }
868
869 name = xml_node_get_localname(ctx->xml, pps_node);
870 wpa_printf(MSG_INFO, "Get command returned node with name '%s'", name);
871 if (os_strcasecmp(name, "Password") == 0) {
872 wpa_printf(MSG_INFO, "Do not allow Get for Password node");
873 os_free(locuri);
874 return DM_RESP_PERMISSION_DENIED;
875 }
876
877 /*
878 * TODO: No support for DMTNDS, so if interior node, reply with a
879 * list of children node names in Results element. The child list type is
880 * defined in [DMTND].
881 */
882
883 *value = xml_node_get_text(ctx->xml, pps_node);
884 if (*value == NULL)
885 return DM_RESP_COMMAND_FAILED;
886
887 return DM_RESP_OK;
888 }
889
890
oma_dm_get_cmdid(struct hs20_osu_client * ctx,xml_node_t * node)891 static int oma_dm_get_cmdid(struct hs20_osu_client *ctx, xml_node_t *node)
892 {
893 xml_node_t *cnode;
894 char *str;
895 int ret;
896
897 cnode = get_node(ctx->xml, node, "CmdID");
898 if (cnode == NULL)
899 return 0;
900
901 str = xml_node_get_text(ctx->xml, cnode);
902 if (str == NULL)
903 return 0;
904 ret = atoi(str);
905 xml_node_get_text_free(ctx->xml, str);
906 return ret;
907 }
908
909
oma_dm_send_recv(struct hs20_osu_client * ctx,const char * url,xml_node_t * syncml,const char * ext_hdr,const char * username,const char * password,const char * client_cert,const char * client_key)910 static xml_node_t * oma_dm_send_recv(struct hs20_osu_client *ctx,
911 const char *url, xml_node_t *syncml,
912 const char *ext_hdr,
913 const char *username, const char *password,
914 const char *client_cert,
915 const char *client_key)
916 {
917 xml_node_t *resp;
918 char *str, *res;
919 char *resp_uri = NULL;
920
921 str = xml_node_to_str(ctx->xml, syncml);
922 xml_node_free(ctx->xml, syncml);
923 if (str == NULL)
924 return NULL;
925
926 wpa_printf(MSG_INFO, "Send OMA DM Package");
927 write_summary(ctx, "Send OMA DM Package");
928 os_free(ctx->server_url);
929 ctx->server_url = os_strdup(url);
930 res = http_post(ctx->http, url, str, "application/vnd.syncml.dm+xml",
931 ext_hdr, ctx->ca_fname, username, password,
932 client_cert, client_key, NULL);
933 os_free(str);
934 os_free(resp_uri);
935 resp_uri = NULL;
936
937 if (res == NULL) {
938 const char *err = http_get_err(ctx->http);
939 if (err) {
940 wpa_printf(MSG_INFO, "HTTP error: %s", err);
941 write_result(ctx, "HTTP error: %s", err);
942 } else {
943 write_summary(ctx, "Failed to send OMA DM Package");
944 }
945 return NULL;
946 }
947 wpa_printf(MSG_DEBUG, "Server response: %s", res);
948
949 wpa_printf(MSG_INFO, "Process OMA DM Package");
950 write_summary(ctx, "Process received OMA DM Package");
951 resp = xml_node_from_buf(ctx->xml, res);
952 os_free(res);
953 if (resp == NULL) {
954 wpa_printf(MSG_INFO, "Failed to parse OMA DM response");
955 return NULL;
956 }
957
958 debug_dump_node(ctx, "OMA DM Package", resp);
959
960 return resp;
961 }
962
963
oma_dm_process(struct hs20_osu_client * ctx,const char * url,xml_node_t * resp,int msgid,char ** ret_resp_uri,xml_node_t * pps,const char * pps_fname)964 static xml_node_t * oma_dm_process(struct hs20_osu_client *ctx, const char *url,
965 xml_node_t *resp, int msgid,
966 char **ret_resp_uri,
967 xml_node_t *pps, const char *pps_fname)
968 {
969 xml_node_t *syncml, *syncbody, *hdr, *body, *child;
970 const char *name;
971 char *resp_uri = NULL;
972 int server_msgid = 0;
973 int cmdid = 0;
974 int server_cmdid;
975 int resp_needed = 0;
976 char *tmp;
977 int final = 0;
978 char *locuri;
979
980 *ret_resp_uri = NULL;
981
982 name = xml_node_get_localname(ctx->xml, resp);
983 if (name == NULL || os_strcasecmp(name, "SyncML") != 0) {
984 wpa_printf(MSG_INFO, "SyncML node not found");
985 return NULL;
986 }
987
988 hdr = get_node(ctx->xml, resp, "SyncHdr");
989 body = get_node(ctx->xml, resp, "SyncBody");
990 if (hdr == NULL || body == NULL) {
991 wpa_printf(MSG_INFO, "Could not find SyncHdr or SyncBody");
992 return NULL;
993 }
994
995 xml_node_for_each_child(ctx->xml, child, hdr) {
996 xml_node_for_each_check(ctx->xml, child);
997 name = xml_node_get_localname(ctx->xml, child);
998 wpa_printf(MSG_INFO, "SyncHdr %s", name);
999 if (os_strcasecmp(name, "RespURI") == 0) {
1000 tmp = xml_node_get_text(ctx->xml, child);
1001 if (tmp)
1002 resp_uri = os_strdup(tmp);
1003 xml_node_get_text_free(ctx->xml, tmp);
1004 } else if (os_strcasecmp(name, "MsgID") == 0) {
1005 tmp = xml_node_get_text(ctx->xml, child);
1006 if (tmp)
1007 server_msgid = atoi(tmp);
1008 xml_node_get_text_free(ctx->xml, tmp);
1009 }
1010 }
1011
1012 wpa_printf(MSG_INFO, "Server MsgID: %d", server_msgid);
1013 if (resp_uri)
1014 wpa_printf(MSG_INFO, "RespURI: %s", resp_uri);
1015
1016 syncml = oma_dm_build_hdr(ctx, resp_uri ? resp_uri : url, msgid);
1017 if (syncml == NULL) {
1018 os_free(resp_uri);
1019 return NULL;
1020 }
1021
1022 syncbody = xml_node_create(ctx->xml, syncml, NULL, "SyncBody");
1023 cmdid++;
1024 add_status(ctx, syncbody, server_msgid, 0, cmdid, "SyncHdr",
1025 DM_RESP_AUTH_ACCEPTED, NULL);
1026
1027 xml_node_for_each_child(ctx->xml, child, body) {
1028 xml_node_for_each_check(ctx->xml, child);
1029 server_cmdid = oma_dm_get_cmdid(ctx, child);
1030 name = xml_node_get_localname(ctx->xml, child);
1031 wpa_printf(MSG_INFO, "SyncBody CmdID=%d - %s",
1032 server_cmdid, name);
1033 if (os_strcasecmp(name, "Exec") == 0) {
1034 int res = oma_dm_exec(ctx, child);
1035 cmdid++;
1036 locuri = oma_dm_get_target_locuri(ctx, child);
1037 if (locuri == NULL)
1038 res = DM_RESP_BAD_REQUEST;
1039 add_status(ctx, syncbody, server_msgid, server_cmdid,
1040 cmdid, name, res, locuri);
1041 os_free(locuri);
1042 resp_needed = 1;
1043 } else if (os_strcasecmp(name, "Add") == 0) {
1044 int res = oma_dm_add(ctx, child, pps, pps_fname);
1045 cmdid++;
1046 locuri = oma_dm_get_target_locuri(ctx, child);
1047 if (locuri == NULL)
1048 res = DM_RESP_BAD_REQUEST;
1049 add_status(ctx, syncbody, server_msgid, server_cmdid,
1050 cmdid, name, res, locuri);
1051 os_free(locuri);
1052 resp_needed = 1;
1053 } else if (os_strcasecmp(name, "Replace") == 0) {
1054 int res;
1055 res = oma_dm_replace(ctx, child, pps, pps_fname);
1056 cmdid++;
1057 locuri = oma_dm_get_target_locuri(ctx, child);
1058 if (locuri == NULL)
1059 res = DM_RESP_BAD_REQUEST;
1060 add_status(ctx, syncbody, server_msgid, server_cmdid,
1061 cmdid, name, res, locuri);
1062 os_free(locuri);
1063 resp_needed = 1;
1064 } else if (os_strcasecmp(name, "Status") == 0) {
1065 /* TODO: Verify success */
1066 } else if (os_strcasecmp(name, "Get") == 0) {
1067 int res;
1068 char *value;
1069 res = oma_dm_get(ctx, child, pps, pps_fname, &value);
1070 cmdid++;
1071 locuri = oma_dm_get_target_locuri(ctx, child);
1072 if (locuri == NULL)
1073 res = DM_RESP_BAD_REQUEST;
1074 add_status(ctx, syncbody, server_msgid, server_cmdid,
1075 cmdid, name, res, locuri);
1076 if (res == DM_RESP_OK && value) {
1077 cmdid++;
1078 add_results(ctx, syncbody, server_msgid,
1079 server_cmdid, cmdid, locuri, value);
1080 }
1081 os_free(locuri);
1082 xml_node_get_text_free(ctx->xml, value);
1083 resp_needed = 1;
1084 #if 0 /* TODO: MUST support */
1085 } else if (os_strcasecmp(name, "Delete") == 0) {
1086 #endif
1087 #if 0 /* TODO: MUST support */
1088 } else if (os_strcasecmp(name, "Sequence") == 0) {
1089 #endif
1090 } else if (os_strcasecmp(name, "Final") == 0) {
1091 final = 1;
1092 break;
1093 } else {
1094 locuri = oma_dm_get_target_locuri(ctx, child);
1095 add_status(ctx, syncbody, server_msgid, server_cmdid,
1096 cmdid, name, DM_RESP_COMMAND_NOT_IMPLEMENTED,
1097 locuri);
1098 os_free(locuri);
1099 resp_needed = 1;
1100 }
1101 }
1102
1103 if (!final) {
1104 wpa_printf(MSG_INFO, "Final node not found");
1105 xml_node_free(ctx->xml, syncml);
1106 os_free(resp_uri);
1107 return NULL;
1108 }
1109
1110 if (!resp_needed) {
1111 wpa_printf(MSG_INFO, "Exchange completed - no response needed");
1112 xml_node_free(ctx->xml, syncml);
1113 os_free(resp_uri);
1114 return NULL;
1115 }
1116
1117 xml_node_create(ctx->xml, syncbody, NULL, "Final");
1118
1119 debug_dump_node(ctx, "OMA-DM Package 3", syncml);
1120
1121 *ret_resp_uri = resp_uri;
1122 return syncml;
1123 }
1124
1125
cmd_oma_dm_prov(struct hs20_osu_client * ctx,const char * url)1126 int cmd_oma_dm_prov(struct hs20_osu_client *ctx, const char *url)
1127 {
1128 xml_node_t *syncml, *resp;
1129 char *resp_uri = NULL;
1130 int msgid = 0;
1131
1132 if (url == NULL) {
1133 wpa_printf(MSG_INFO, "Invalid prov command (missing URL)");
1134 return -1;
1135 }
1136
1137 wpa_printf(MSG_INFO, "OMA-DM credential provisioning requested");
1138 write_summary(ctx, "OMA-DM credential provisioning");
1139
1140 msgid++;
1141 syncml = build_oma_dm_1_sub_reg(ctx, url, msgid);
1142 if (syncml == NULL)
1143 return -1;
1144
1145 while (syncml) {
1146 resp = oma_dm_send_recv(ctx, resp_uri ? resp_uri : url,
1147 syncml, NULL, NULL, NULL, NULL, NULL);
1148 if (resp == NULL)
1149 return -1;
1150
1151 msgid++;
1152 syncml = oma_dm_process(ctx, url, resp, msgid, &resp_uri,
1153 NULL, NULL);
1154 xml_node_free(ctx->xml, resp);
1155 }
1156
1157 os_free(resp_uri);
1158
1159 return ctx->pps_cred_set ? 0 : -1;
1160 }
1161
1162
cmd_oma_dm_sim_prov(struct hs20_osu_client * ctx,const char * url)1163 int cmd_oma_dm_sim_prov(struct hs20_osu_client *ctx, const char *url)
1164 {
1165 xml_node_t *syncml, *resp;
1166 char *resp_uri = NULL;
1167 int msgid = 0;
1168
1169 if (url == NULL) {
1170 wpa_printf(MSG_INFO, "Invalid prov command (missing URL)");
1171 return -1;
1172 }
1173
1174 wpa_printf(MSG_INFO, "OMA-DM SIM provisioning requested");
1175 ctx->no_reconnect = 2;
1176
1177 wpa_printf(MSG_INFO, "Wait for IP address before starting SIM provisioning");
1178 write_summary(ctx, "Wait for IP address before starting SIM provisioning");
1179
1180 if (wait_ip_addr(ctx->ifname, 15) < 0) {
1181 wpa_printf(MSG_INFO, "Could not get IP address for WLAN - try connection anyway");
1182 }
1183 write_summary(ctx, "OMA-DM SIM provisioning");
1184
1185 msgid++;
1186 syncml = build_oma_dm_1_sub_prov(ctx, url, msgid);
1187 if (syncml == NULL)
1188 return -1;
1189
1190 while (syncml) {
1191 resp = oma_dm_send_recv(ctx, resp_uri ? resp_uri : url,
1192 syncml, NULL, NULL, NULL, NULL, NULL);
1193 if (resp == NULL)
1194 return -1;
1195
1196 msgid++;
1197 syncml = oma_dm_process(ctx, url, resp, msgid, &resp_uri,
1198 NULL, NULL);
1199 xml_node_free(ctx->xml, resp);
1200 }
1201
1202 os_free(resp_uri);
1203
1204 if (ctx->pps_cred_set) {
1205 wpa_printf(MSG_INFO, "Updating wpa_supplicant credentials");
1206 cmd_set_pps(ctx, ctx->pps_fname);
1207
1208 wpa_printf(MSG_INFO, "Requesting reconnection with updated configuration");
1209 write_summary(ctx, "Requesting reconnection with updated configuration");
1210 if (wpa_command(ctx->ifname, "INTERWORKING_SELECT auto") < 0) {
1211 wpa_printf(MSG_INFO, "Failed to request wpa_supplicant to reconnect");
1212 write_summary(ctx, "Failed to request wpa_supplicant to reconnect");
1213 return -1;
1214 }
1215 }
1216
1217 return ctx->pps_cred_set ? 0 : -1;
1218 }
1219
1220
oma_dm_pol_upd(struct hs20_osu_client * ctx,const char * address,const char * pps_fname,const char * client_cert,const char * client_key,const char * cred_username,const char * cred_password,xml_node_t * pps)1221 void oma_dm_pol_upd(struct hs20_osu_client *ctx, const char *address,
1222 const char *pps_fname,
1223 const char *client_cert, const char *client_key,
1224 const char *cred_username, const char *cred_password,
1225 xml_node_t *pps)
1226 {
1227 xml_node_t *syncml, *resp;
1228 char *resp_uri = NULL;
1229 int msgid = 0;
1230
1231 wpa_printf(MSG_INFO, "OMA-DM policy update");
1232 write_summary(ctx, "OMA-DM policy update");
1233
1234 msgid++;
1235 syncml = build_oma_dm_1_pol_upd(ctx, address, msgid);
1236 if (syncml == NULL)
1237 return;
1238
1239 while (syncml) {
1240 resp = oma_dm_send_recv(ctx, resp_uri ? resp_uri : address,
1241 syncml, NULL, cred_username,
1242 cred_password, client_cert, client_key);
1243 if (resp == NULL)
1244 return;
1245
1246 msgid++;
1247 syncml = oma_dm_process(ctx, address, resp, msgid, &resp_uri,
1248 pps, pps_fname);
1249 xml_node_free(ctx->xml, resp);
1250 }
1251
1252 os_free(resp_uri);
1253
1254 if (ctx->pps_updated) {
1255 wpa_printf(MSG_INFO, "Update wpa_supplicant credential based on updated PPS MO");
1256 write_summary(ctx, "Update wpa_supplicant credential based on updated PPS MO and request connection");
1257 cmd_set_pps(ctx, pps_fname);
1258 if (wpa_command(ctx->ifname, "INTERWORKING_SELECT auto") < 0) {
1259 wpa_printf(MSG_INFO,
1260 "Failed to request wpa_supplicant to reconnect");
1261 write_summary(ctx,
1262 "Failed to request wpa_supplicant to reconnect");
1263 }
1264 }
1265 }
1266
1267
oma_dm_sub_rem(struct hs20_osu_client * ctx,const char * address,const char * pps_fname,const char * client_cert,const char * client_key,const char * cred_username,const char * cred_password,xml_node_t * pps)1268 void oma_dm_sub_rem(struct hs20_osu_client *ctx, const char *address,
1269 const char *pps_fname,
1270 const char *client_cert, const char *client_key,
1271 const char *cred_username, const char *cred_password,
1272 xml_node_t *pps)
1273 {
1274 xml_node_t *syncml, *resp;
1275 char *resp_uri = NULL;
1276 int msgid = 0;
1277
1278 wpa_printf(MSG_INFO, "OMA-DM subscription remediation");
1279 write_summary(ctx, "OMA-DM subscription remediation");
1280
1281 msgid++;
1282 syncml = build_oma_dm_1_sub_rem(ctx, address, msgid);
1283 if (syncml == NULL)
1284 return;
1285
1286 while (syncml) {
1287 resp = oma_dm_send_recv(ctx, resp_uri ? resp_uri : address,
1288 syncml, NULL, cred_username,
1289 cred_password, client_cert, client_key);
1290 if (resp == NULL)
1291 return;
1292
1293 msgid++;
1294 syncml = oma_dm_process(ctx, address, resp, msgid, &resp_uri,
1295 pps, pps_fname);
1296 xml_node_free(ctx->xml, resp);
1297 }
1298
1299 os_free(resp_uri);
1300
1301 wpa_printf(MSG_INFO, "Update wpa_supplicant credential based on updated PPS MO and request reconnection");
1302 write_summary(ctx, "Update wpa_supplicant credential based on updated PPS MO and request reconnection");
1303 cmd_set_pps(ctx, pps_fname);
1304 if (wpa_command(ctx->ifname, "INTERWORKING_SELECT auto") < 0) {
1305 wpa_printf(MSG_INFO, "Failed to request wpa_supplicant to reconnect");
1306 write_summary(ctx, "Failed to request wpa_supplicant to reconnect");
1307 }
1308 }
1309
1310
cmd_oma_dm_add(struct hs20_osu_client * ctx,const char * pps_fname,const char * add_fname)1311 void cmd_oma_dm_add(struct hs20_osu_client *ctx, const char *pps_fname,
1312 const char *add_fname)
1313 {
1314 xml_node_t *pps, *add;
1315 int res;
1316
1317 ctx->fqdn = os_strdup("wi-fi.org");
1318
1319 pps = node_from_file(ctx->xml, pps_fname);
1320 if (pps == NULL) {
1321 wpa_printf(MSG_INFO, "PPS file %s could not be parsed",
1322 pps_fname);
1323 return;
1324 }
1325
1326 add = node_from_file(ctx->xml, add_fname);
1327 if (add == NULL) {
1328 wpa_printf(MSG_INFO, "Add file %s could not be parsed",
1329 add_fname);
1330 xml_node_free(ctx->xml, pps);
1331 return;
1332 }
1333
1334 res = oma_dm_add(ctx, add, pps, pps_fname);
1335 wpa_printf(MSG_INFO, "oma_dm_add --> %d", res);
1336
1337 xml_node_free(ctx->xml, pps);
1338 xml_node_free(ctx->xml, add);
1339 }
1340
1341
cmd_oma_dm_replace(struct hs20_osu_client * ctx,const char * pps_fname,const char * replace_fname)1342 void cmd_oma_dm_replace(struct hs20_osu_client *ctx, const char *pps_fname,
1343 const char *replace_fname)
1344 {
1345 xml_node_t *pps, *replace;
1346 int res;
1347
1348 ctx->fqdn = os_strdup("wi-fi.org");
1349
1350 pps = node_from_file(ctx->xml, pps_fname);
1351 if (pps == NULL) {
1352 wpa_printf(MSG_INFO, "PPS file %s could not be parsed",
1353 pps_fname);
1354 return;
1355 }
1356
1357 replace = node_from_file(ctx->xml, replace_fname);
1358 if (replace == NULL) {
1359 wpa_printf(MSG_INFO, "Replace file %s could not be parsed",
1360 replace_fname);
1361 xml_node_free(ctx->xml, pps);
1362 return;
1363 }
1364
1365 res = oma_dm_replace(ctx, replace, pps, pps_fname);
1366 wpa_printf(MSG_INFO, "oma_dm_replace --> %d", res);
1367
1368 xml_node_free(ctx->xml, pps);
1369 xml_node_free(ctx->xml, replace);
1370 }
1371