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