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 if (data == NULL) {
398 wpa_printf(MSG_INFO, "Invalid data");
399 return DM_RESP_BAD_REQUEST;
400 }
401 wpa_printf(MSG_INFO, "Data: %s", data);
402 wpa_printf(MSG_INFO, "Launch browser to URI '%s'", data);
403 write_summary(ctx, "Launch browser to URI '%s'", data);
404 res = hs20_web_browser(data);
405 xml_node_get_text_free(ctx->xml, data);
406 if (res > 0) {
407 wpa_printf(MSG_INFO, "User response in browser completed successfully");
408 write_summary(ctx, "User response in browser completed successfully");
409 return DM_RESP_OK;
410 } else {
411 wpa_printf(MSG_INFO, "Failed to receive user response");
412 write_summary(ctx, "Failed to receive user response");
413 return DM_RESP_COMMAND_FAILED;
414 }
415 }
416
417
oma_dm_exec_get_cert(struct hs20_osu_client * ctx,xml_node_t * exec)418 static int oma_dm_exec_get_cert(struct hs20_osu_client *ctx, xml_node_t *exec)
419 {
420 xml_node_t *node, *getcert;
421 char *data;
422 const char *name;
423 int res;
424
425 wpa_printf(MSG_INFO, "Client certificate enrollment");
426 write_summary(ctx, "Client certificate enrollment");
427
428 node = get_node(ctx->xml, exec, "Item/Data");
429 if (node == NULL) {
430 wpa_printf(MSG_INFO, "No Data node found");
431 return DM_RESP_BAD_REQUEST;
432 }
433
434 data = xml_node_get_text(ctx->xml, node);
435 if (data == NULL) {
436 wpa_printf(MSG_INFO, "Invalid data");
437 return DM_RESP_BAD_REQUEST;
438 }
439 wpa_printf(MSG_INFO, "Data: %s", data);
440 getcert = xml_node_from_buf(ctx->xml, data);
441 xml_node_get_text_free(ctx->xml, data);
442
443 if (getcert == NULL) {
444 wpa_printf(MSG_INFO, "Could not parse Item/Data node contents");
445 return DM_RESP_BAD_REQUEST;
446 }
447
448 debug_dump_node(ctx, "OMA-DM getCertificate", getcert);
449
450 name = xml_node_get_localname(ctx->xml, getcert);
451 if (name == NULL || os_strcasecmp(name, "getCertificate") != 0) {
452 wpa_printf(MSG_INFO, "Unexpected getCertificate node name '%s'",
453 name);
454 return DM_RESP_BAD_REQUEST;
455 }
456
457 res = osu_get_certificate(ctx, getcert);
458
459 xml_node_free(ctx->xml, getcert);
460
461 return res == 0 ? DM_RESP_OK : DM_RESP_COMMAND_FAILED;
462 }
463
464
oma_dm_exec(struct hs20_osu_client * ctx,xml_node_t * exec)465 static int oma_dm_exec(struct hs20_osu_client *ctx, xml_node_t *exec)
466 {
467 char *locuri;
468 int ret;
469
470 locuri = oma_dm_get_target_locuri(ctx, exec);
471 if (locuri == NULL) {
472 wpa_printf(MSG_INFO, "No Target LocURI node found");
473 return DM_RESP_BAD_REQUEST;
474 }
475
476 wpa_printf(MSG_INFO, "Target LocURI: %s", locuri);
477
478 if (os_strcasecmp(locuri, "./DevDetail/Ext/org.wi-fi/Wi-Fi/Ops/"
479 "launchBrowserToURI") == 0) {
480 ret = oma_dm_exec_browser(ctx, exec);
481 } else if (os_strcasecmp(locuri, "./DevDetail/Ext/org.wi-fi/Wi-Fi/Ops/"
482 "getCertificate") == 0) {
483 ret = oma_dm_exec_get_cert(ctx, exec);
484 } else {
485 wpa_printf(MSG_INFO, "Unsupported exec Target LocURI");
486 ret = DM_RESP_NOT_FOUND;
487 }
488 os_free(locuri);
489
490 return ret;
491 }
492
493
oma_dm_run_add(struct hs20_osu_client * ctx,const char * locuri,xml_node_t * add,xml_node_t * pps,const char * pps_fname)494 static int oma_dm_run_add(struct hs20_osu_client *ctx, const char *locuri,
495 xml_node_t *add, xml_node_t *pps,
496 const char *pps_fname)
497 {
498 const char *pos;
499 size_t fqdn_len;
500 xml_node_t *node, *tnds, *unode, *pps_node;
501 char *data, *uri, *upos, *end;
502 int use_tnds = 0;
503 size_t uri_len;
504
505 wpa_printf(MSG_INFO, "Add command target LocURI: %s", locuri);
506
507 if (os_strncasecmp(locuri, "./Wi-Fi/", 8) != 0) {
508 wpa_printf(MSG_INFO, "Do not allow Add outside ./Wi-Fi");
509 return DM_RESP_PERMISSION_DENIED;
510 }
511 pos = locuri + 8;
512
513 if (ctx->fqdn == NULL)
514 return DM_RESP_COMMAND_FAILED;
515 fqdn_len = os_strlen(ctx->fqdn);
516 if (os_strncasecmp(pos, ctx->fqdn, fqdn_len) != 0 ||
517 pos[fqdn_len] != '/') {
518 wpa_printf(MSG_INFO, "Do not allow Add outside ./Wi-Fi/%s",
519 ctx->fqdn);
520 return DM_RESP_PERMISSION_DENIED;
521 }
522 pos += fqdn_len + 1;
523
524 if (os_strncasecmp(pos, "PerProviderSubscription/", 24) != 0) {
525 wpa_printf(MSG_INFO,
526 "Do not allow Add outside ./Wi-Fi/%s/PerProviderSubscription",
527 ctx->fqdn);
528 return DM_RESP_PERMISSION_DENIED;
529 }
530 pos += 24;
531
532 wpa_printf(MSG_INFO, "Add command for PPS node %s", pos);
533
534 pps_node = get_node(ctx->xml, pps, pos);
535 if (pps_node) {
536 wpa_printf(MSG_INFO, "Specified PPS node exists already");
537 return DM_RESP_ALREADY_EXISTS;
538 }
539
540 uri = os_strdup(pos);
541 if (uri == NULL)
542 return DM_RESP_COMMAND_FAILED;
543 while (!pps_node) {
544 upos = os_strrchr(uri, '/');
545 if (!upos)
546 break;
547 upos[0] = '\0';
548 pps_node = get_node(ctx->xml, pps, uri);
549 wpa_printf(MSG_INFO, "Node %s %s", uri,
550 pps_node ? "exists" : "does not exist");
551 }
552
553 wpa_printf(MSG_INFO, "Parent URI: %s", uri);
554
555 if (!pps_node) {
556 /* Add at root of PPS MO */
557 pps_node = pps;
558 }
559
560 uri_len = os_strlen(uri);
561 os_strlcpy(uri, pos + uri_len, os_strlen(pos));
562 upos = uri;
563 while (*upos == '/')
564 upos++;
565 wpa_printf(MSG_INFO, "Nodes to add: %s", upos);
566
567 for (;;) {
568 end = os_strchr(upos, '/');
569 if (!end)
570 break;
571 *end = '\0';
572 wpa_printf(MSG_INFO, "Adding interim node %s", upos);
573 pps_node = xml_node_create(ctx->xml, pps_node, NULL, upos);
574 if (pps_node == NULL) {
575 os_free(uri);
576 return DM_RESP_COMMAND_FAILED;
577 }
578 upos = end + 1;
579 }
580
581 wpa_printf(MSG_INFO, "Adding node %s", upos);
582
583 node = get_node(ctx->xml, add, "Item/Meta/Type");
584 if (node) {
585 char *type;
586 type = xml_node_get_text(ctx->xml, node);
587 if (type == NULL) {
588 wpa_printf(MSG_ERROR, "Could not find type text");
589 os_free(uri);
590 return DM_RESP_BAD_REQUEST;
591 }
592 use_tnds = node &&
593 os_strstr(type, "application/vnd.syncml.dmtnds+xml");
594 }
595
596 node = get_node(ctx->xml, add, "Item/Data");
597 if (node == NULL) {
598 wpa_printf(MSG_INFO, "No Add/Item/Data found");
599 os_free(uri);
600 return DM_RESP_BAD_REQUEST;
601 }
602
603 data = xml_node_get_text(ctx->xml, node);
604 if (data == NULL) {
605 wpa_printf(MSG_INFO, "Could not get Add/Item/Data text");
606 os_free(uri);
607 return DM_RESP_BAD_REQUEST;
608 }
609
610 wpa_printf(MSG_DEBUG, "Add/Item/Data: %s", data);
611
612 if (use_tnds) {
613 tnds = xml_node_from_buf(ctx->xml, data);
614 xml_node_get_text_free(ctx->xml, data);
615 if (tnds == NULL) {
616 wpa_printf(MSG_INFO,
617 "Could not parse Add/Item/Data text");
618 os_free(uri);
619 return DM_RESP_BAD_REQUEST;
620 }
621
622 unode = tnds_to_mo(ctx->xml, tnds);
623 xml_node_free(ctx->xml, tnds);
624 if (unode == NULL) {
625 wpa_printf(MSG_INFO, "Could not parse TNDS text");
626 os_free(uri);
627 return DM_RESP_BAD_REQUEST;
628 }
629
630 debug_dump_node(ctx, "Parsed TNDS", unode);
631
632 xml_node_add_child(ctx->xml, pps_node, unode);
633 } else {
634 /* TODO: What to do here? */
635 os_free(uri);
636 return DM_RESP_BAD_REQUEST;
637 }
638
639 os_free(uri);
640
641 if (update_pps_file(ctx, pps_fname, pps) < 0)
642 return DM_RESP_COMMAND_FAILED;
643
644 ctx->pps_updated = 1;
645
646 return DM_RESP_OK;
647 }
648
649
oma_dm_add(struct hs20_osu_client * ctx,xml_node_t * add,xml_node_t * pps,const char * pps_fname)650 static int oma_dm_add(struct hs20_osu_client *ctx, xml_node_t *add,
651 xml_node_t *pps, const char *pps_fname)
652 {
653 xml_node_t *node;
654 char *locuri;
655 char fname[300];
656 int ret;
657
658 node = get_node(ctx->xml, add, "Item/Target/LocURI");
659 if (node == NULL) {
660 wpa_printf(MSG_INFO, "No Target LocURI node found");
661 return DM_RESP_BAD_REQUEST;
662 }
663 locuri = xml_node_get_text(ctx->xml, node);
664 if (locuri == NULL) {
665 wpa_printf(MSG_ERROR, "No LocURI node text found");
666 return DM_RESP_BAD_REQUEST;
667 }
668 wpa_printf(MSG_INFO, "Target LocURI: %s", locuri);
669 if (os_strncasecmp(locuri, "./Wi-Fi/", 8) != 0) {
670 wpa_printf(MSG_INFO, "Unsupported Add Target LocURI");
671 xml_node_get_text_free(ctx->xml, locuri);
672 return DM_RESP_PERMISSION_DENIED;
673 }
674
675 node = get_node(ctx->xml, add, "Item/Data");
676 if (node == NULL) {
677 wpa_printf(MSG_INFO, "No Data node found");
678 xml_node_get_text_free(ctx->xml, locuri);
679 return DM_RESP_BAD_REQUEST;
680 }
681
682 if (pps_fname && os_file_exists(pps_fname)) {
683 ret = oma_dm_run_add(ctx, locuri, add, pps, pps_fname);
684 if (ret != DM_RESP_OK) {
685 xml_node_get_text_free(ctx->xml, locuri);
686 return ret;
687 }
688 ret = 0;
689 os_strlcpy(fname, pps_fname, sizeof(fname));
690 } else
691 ret = hs20_add_pps_mo(ctx, locuri, node, fname, sizeof(fname));
692 xml_node_get_text_free(ctx->xml, locuri);
693 if (ret < 0)
694 return ret == -2 ? DM_RESP_ALREADY_EXISTS :
695 DM_RESP_COMMAND_FAILED;
696
697 if (ctx->no_reconnect == 2) {
698 os_snprintf(ctx->pps_fname, sizeof(ctx->pps_fname), "%s",
699 fname);
700 ctx->pps_cred_set = 1;
701 return DM_RESP_OK;
702 }
703
704 wpa_printf(MSG_INFO, "Updating wpa_supplicant credentials");
705 cmd_set_pps(ctx, fname);
706
707 if (ctx->no_reconnect)
708 return DM_RESP_OK;
709
710 wpa_printf(MSG_INFO, "Requesting reconnection with updated configuration");
711 if (wpa_command(ctx->ifname, "INTERWORKING_SELECT auto") < 0)
712 wpa_printf(MSG_INFO, "Failed to request wpa_supplicant to reconnect");
713
714 return DM_RESP_OK;
715 }
716
717
oma_dm_replace(struct hs20_osu_client * ctx,xml_node_t * replace,xml_node_t * pps,const char * pps_fname)718 static int oma_dm_replace(struct hs20_osu_client *ctx, xml_node_t *replace,
719 xml_node_t *pps, const char *pps_fname)
720 {
721 char *locuri, *pos;
722 size_t fqdn_len;
723 xml_node_t *node, *tnds, *unode, *pps_node, *parent;
724 char *data;
725 int use_tnds = 0;
726
727 locuri = oma_dm_get_target_locuri(ctx, replace);
728 if (locuri == NULL)
729 return DM_RESP_BAD_REQUEST;
730
731 wpa_printf(MSG_INFO, "Replace command target LocURI: %s", locuri);
732 if (os_strncasecmp(locuri, "./Wi-Fi/", 8) != 0) {
733 wpa_printf(MSG_INFO, "Do not allow Replace outside ./Wi-Fi");
734 os_free(locuri);
735 return DM_RESP_PERMISSION_DENIED;
736 }
737 pos = locuri + 8;
738
739 if (ctx->fqdn == NULL) {
740 os_free(locuri);
741 return DM_RESP_COMMAND_FAILED;
742 }
743 fqdn_len = os_strlen(ctx->fqdn);
744 if (os_strncasecmp(pos, ctx->fqdn, fqdn_len) != 0 ||
745 pos[fqdn_len] != '/') {
746 wpa_printf(MSG_INFO, "Do not allow Replace outside ./Wi-Fi/%s",
747 ctx->fqdn);
748 os_free(locuri);
749 return DM_RESP_PERMISSION_DENIED;
750 }
751 pos += fqdn_len + 1;
752
753 if (os_strncasecmp(pos, "PerProviderSubscription/", 24) != 0) {
754 wpa_printf(MSG_INFO,
755 "Do not allow Replace outside ./Wi-Fi/%s/PerProviderSubscription",
756 ctx->fqdn);
757 os_free(locuri);
758 return DM_RESP_PERMISSION_DENIED;
759 }
760 pos += 24;
761
762 wpa_printf(MSG_INFO, "Replace command for PPS node %s", pos);
763
764 pps_node = get_node(ctx->xml, pps, pos);
765 if (pps_node == NULL) {
766 wpa_printf(MSG_INFO, "Specified PPS node not found");
767 os_free(locuri);
768 return DM_RESP_NOT_FOUND;
769 }
770
771 node = get_node(ctx->xml, replace, "Item/Meta/Type");
772 if (node) {
773 char *type;
774 type = xml_node_get_text(ctx->xml, node);
775 if (type == NULL) {
776 wpa_printf(MSG_INFO, "Could not find type text");
777 os_free(locuri);
778 return DM_RESP_BAD_REQUEST;
779 }
780 use_tnds = node &&
781 os_strstr(type, "application/vnd.syncml.dmtnds+xml");
782 }
783
784 node = get_node(ctx->xml, replace, "Item/Data");
785 if (node == NULL) {
786 wpa_printf(MSG_INFO, "No Replace/Item/Data found");
787 os_free(locuri);
788 return DM_RESP_BAD_REQUEST;
789 }
790
791 data = xml_node_get_text(ctx->xml, node);
792 if (data == NULL) {
793 wpa_printf(MSG_INFO, "Could not get Replace/Item/Data text");
794 os_free(locuri);
795 return DM_RESP_BAD_REQUEST;
796 }
797
798 wpa_printf(MSG_DEBUG, "Replace/Item/Data: %s", data);
799
800 if (use_tnds) {
801 tnds = xml_node_from_buf(ctx->xml, data);
802 xml_node_get_text_free(ctx->xml, data);
803 if (tnds == NULL) {
804 wpa_printf(MSG_INFO,
805 "Could not parse Replace/Item/Data text");
806 os_free(locuri);
807 return DM_RESP_BAD_REQUEST;
808 }
809
810 unode = tnds_to_mo(ctx->xml, tnds);
811 xml_node_free(ctx->xml, tnds);
812 if (unode == NULL) {
813 wpa_printf(MSG_INFO, "Could not parse TNDS text");
814 os_free(locuri);
815 return DM_RESP_BAD_REQUEST;
816 }
817
818 debug_dump_node(ctx, "Parsed TNDS", unode);
819
820 parent = xml_node_get_parent(ctx->xml, pps_node);
821 xml_node_detach(ctx->xml, pps_node);
822 xml_node_add_child(ctx->xml, parent, unode);
823 } else {
824 xml_node_set_text(ctx->xml, pps_node, data);
825 xml_node_get_text_free(ctx->xml, data);
826 }
827
828 os_free(locuri);
829
830 if (update_pps_file(ctx, pps_fname, pps) < 0)
831 return DM_RESP_COMMAND_FAILED;
832
833 ctx->pps_updated = 1;
834
835 return DM_RESP_OK;
836 }
837
838
oma_dm_get(struct hs20_osu_client * ctx,xml_node_t * get,xml_node_t * pps,const char * pps_fname,char ** value)839 static int oma_dm_get(struct hs20_osu_client *ctx, xml_node_t *get,
840 xml_node_t *pps, const char *pps_fname, char **value)
841 {
842 char *locuri, *pos;
843 size_t fqdn_len;
844 xml_node_t *pps_node;
845 const char *name;
846
847 *value = NULL;
848
849 locuri = oma_dm_get_target_locuri(ctx, get);
850 if (locuri == NULL)
851 return DM_RESP_BAD_REQUEST;
852
853 wpa_printf(MSG_INFO, "Get command target LocURI: %s", locuri);
854 if (os_strncasecmp(locuri, "./Wi-Fi/", 8) != 0) {
855 wpa_printf(MSG_INFO, "Do not allow Get outside ./Wi-Fi");
856 os_free(locuri);
857 return DM_RESP_PERMISSION_DENIED;
858 }
859 pos = locuri + 8;
860
861 if (ctx->fqdn == NULL)
862 return DM_RESP_COMMAND_FAILED;
863 fqdn_len = os_strlen(ctx->fqdn);
864 if (os_strncasecmp(pos, ctx->fqdn, fqdn_len) != 0 ||
865 pos[fqdn_len] != '/') {
866 wpa_printf(MSG_INFO, "Do not allow Get outside ./Wi-Fi/%s",
867 ctx->fqdn);
868 os_free(locuri);
869 return DM_RESP_PERMISSION_DENIED;
870 }
871 pos += fqdn_len + 1;
872
873 if (os_strncasecmp(pos, "PerProviderSubscription/", 24) != 0) {
874 wpa_printf(MSG_INFO,
875 "Do not allow Get outside ./Wi-Fi/%s/PerProviderSubscription",
876 ctx->fqdn);
877 os_free(locuri);
878 return DM_RESP_PERMISSION_DENIED;
879 }
880 pos += 24;
881
882 wpa_printf(MSG_INFO, "Get command for PPS node %s", pos);
883
884 pps_node = get_node(ctx->xml, pps, pos);
885 if (pps_node == NULL) {
886 wpa_printf(MSG_INFO, "Specified PPS node not found");
887 os_free(locuri);
888 return DM_RESP_NOT_FOUND;
889 }
890
891 name = xml_node_get_localname(ctx->xml, pps_node);
892 wpa_printf(MSG_INFO, "Get command returned node with name '%s'", name);
893 if (os_strcasecmp(name, "Password") == 0) {
894 wpa_printf(MSG_INFO, "Do not allow Get for Password node");
895 os_free(locuri);
896 return DM_RESP_PERMISSION_DENIED;
897 }
898
899 /*
900 * TODO: No support for DMTNDS, so if interior node, reply with a
901 * list of children node names in Results element. The child list type is
902 * defined in [DMTND].
903 */
904
905 *value = xml_node_get_text(ctx->xml, pps_node);
906 if (*value == NULL)
907 return DM_RESP_COMMAND_FAILED;
908
909 return DM_RESP_OK;
910 }
911
912
oma_dm_get_cmdid(struct hs20_osu_client * ctx,xml_node_t * node)913 static int oma_dm_get_cmdid(struct hs20_osu_client *ctx, xml_node_t *node)
914 {
915 xml_node_t *cnode;
916 char *str;
917 int ret;
918
919 cnode = get_node(ctx->xml, node, "CmdID");
920 if (cnode == NULL)
921 return 0;
922
923 str = xml_node_get_text(ctx->xml, cnode);
924 if (str == NULL)
925 return 0;
926 ret = atoi(str);
927 xml_node_get_text_free(ctx->xml, str);
928 return ret;
929 }
930
931
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)932 static xml_node_t * oma_dm_send_recv(struct hs20_osu_client *ctx,
933 const char *url, xml_node_t *syncml,
934 const char *ext_hdr,
935 const char *username, const char *password,
936 const char *client_cert,
937 const char *client_key)
938 {
939 xml_node_t *resp;
940 char *str, *res;
941 char *resp_uri = NULL;
942
943 str = xml_node_to_str(ctx->xml, syncml);
944 xml_node_free(ctx->xml, syncml);
945 if (str == NULL)
946 return NULL;
947
948 wpa_printf(MSG_INFO, "Send OMA DM Package");
949 write_summary(ctx, "Send OMA DM Package");
950 os_free(ctx->server_url);
951 ctx->server_url = os_strdup(url);
952 res = http_post(ctx->http, url, str, "application/vnd.syncml.dm+xml",
953 ext_hdr, ctx->ca_fname, username, password,
954 client_cert, client_key, NULL);
955 os_free(str);
956 os_free(resp_uri);
957 resp_uri = NULL;
958
959 if (res == NULL) {
960 const char *err = http_get_err(ctx->http);
961 if (err) {
962 wpa_printf(MSG_INFO, "HTTP error: %s", err);
963 write_result(ctx, "HTTP error: %s", err);
964 } else {
965 write_summary(ctx, "Failed to send OMA DM Package");
966 }
967 return NULL;
968 }
969 wpa_printf(MSG_DEBUG, "Server response: %s", res);
970
971 wpa_printf(MSG_INFO, "Process OMA DM Package");
972 write_summary(ctx, "Process received OMA DM Package");
973 resp = xml_node_from_buf(ctx->xml, res);
974 os_free(res);
975 if (resp == NULL) {
976 wpa_printf(MSG_INFO, "Failed to parse OMA DM response");
977 return NULL;
978 }
979
980 debug_dump_node(ctx, "OMA DM Package", resp);
981
982 return resp;
983 }
984
985
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)986 static xml_node_t * oma_dm_process(struct hs20_osu_client *ctx, const char *url,
987 xml_node_t *resp, int msgid,
988 char **ret_resp_uri,
989 xml_node_t *pps, const char *pps_fname)
990 {
991 xml_node_t *syncml, *syncbody, *hdr, *body, *child;
992 const char *name;
993 char *resp_uri = NULL;
994 int server_msgid = 0;
995 int cmdid = 0;
996 int server_cmdid;
997 int resp_needed = 0;
998 char *tmp;
999 int final = 0;
1000 char *locuri;
1001
1002 *ret_resp_uri = NULL;
1003
1004 name = xml_node_get_localname(ctx->xml, resp);
1005 if (name == NULL || os_strcasecmp(name, "SyncML") != 0) {
1006 wpa_printf(MSG_INFO, "SyncML node not found");
1007 return NULL;
1008 }
1009
1010 hdr = get_node(ctx->xml, resp, "SyncHdr");
1011 body = get_node(ctx->xml, resp, "SyncBody");
1012 if (hdr == NULL || body == NULL) {
1013 wpa_printf(MSG_INFO, "Could not find SyncHdr or SyncBody");
1014 return NULL;
1015 }
1016
1017 xml_node_for_each_child(ctx->xml, child, hdr) {
1018 xml_node_for_each_check(ctx->xml, child);
1019 name = xml_node_get_localname(ctx->xml, child);
1020 wpa_printf(MSG_INFO, "SyncHdr %s", name);
1021 if (os_strcasecmp(name, "RespURI") == 0) {
1022 tmp = xml_node_get_text(ctx->xml, child);
1023 if (tmp)
1024 resp_uri = os_strdup(tmp);
1025 xml_node_get_text_free(ctx->xml, tmp);
1026 } else if (os_strcasecmp(name, "MsgID") == 0) {
1027 tmp = xml_node_get_text(ctx->xml, child);
1028 if (tmp)
1029 server_msgid = atoi(tmp);
1030 xml_node_get_text_free(ctx->xml, tmp);
1031 }
1032 }
1033
1034 wpa_printf(MSG_INFO, "Server MsgID: %d", server_msgid);
1035 if (resp_uri)
1036 wpa_printf(MSG_INFO, "RespURI: %s", resp_uri);
1037
1038 syncml = oma_dm_build_hdr(ctx, resp_uri ? resp_uri : url, msgid);
1039 if (syncml == NULL) {
1040 os_free(resp_uri);
1041 return NULL;
1042 }
1043
1044 syncbody = xml_node_create(ctx->xml, syncml, NULL, "SyncBody");
1045 cmdid++;
1046 add_status(ctx, syncbody, server_msgid, 0, cmdid, "SyncHdr",
1047 DM_RESP_AUTH_ACCEPTED, NULL);
1048
1049 xml_node_for_each_child(ctx->xml, child, body) {
1050 xml_node_for_each_check(ctx->xml, child);
1051 server_cmdid = oma_dm_get_cmdid(ctx, child);
1052 name = xml_node_get_localname(ctx->xml, child);
1053 wpa_printf(MSG_INFO, "SyncBody CmdID=%d - %s",
1054 server_cmdid, name);
1055 if (os_strcasecmp(name, "Exec") == 0) {
1056 int res = oma_dm_exec(ctx, child);
1057 cmdid++;
1058 locuri = oma_dm_get_target_locuri(ctx, child);
1059 if (locuri == NULL)
1060 res = DM_RESP_BAD_REQUEST;
1061 add_status(ctx, syncbody, server_msgid, server_cmdid,
1062 cmdid, name, res, locuri);
1063 os_free(locuri);
1064 resp_needed = 1;
1065 } else if (os_strcasecmp(name, "Add") == 0) {
1066 int res = oma_dm_add(ctx, child, pps, pps_fname);
1067 cmdid++;
1068 locuri = oma_dm_get_target_locuri(ctx, child);
1069 if (locuri == NULL)
1070 res = DM_RESP_BAD_REQUEST;
1071 add_status(ctx, syncbody, server_msgid, server_cmdid,
1072 cmdid, name, res, locuri);
1073 os_free(locuri);
1074 resp_needed = 1;
1075 } else if (os_strcasecmp(name, "Replace") == 0) {
1076 int res;
1077 res = oma_dm_replace(ctx, child, pps, pps_fname);
1078 cmdid++;
1079 locuri = oma_dm_get_target_locuri(ctx, child);
1080 if (locuri == NULL)
1081 res = DM_RESP_BAD_REQUEST;
1082 add_status(ctx, syncbody, server_msgid, server_cmdid,
1083 cmdid, name, res, locuri);
1084 os_free(locuri);
1085 resp_needed = 1;
1086 } else if (os_strcasecmp(name, "Status") == 0) {
1087 /* TODO: Verify success */
1088 } else if (os_strcasecmp(name, "Get") == 0) {
1089 int res;
1090 char *value;
1091 res = oma_dm_get(ctx, child, pps, pps_fname, &value);
1092 cmdid++;
1093 locuri = oma_dm_get_target_locuri(ctx, child);
1094 if (locuri == NULL)
1095 res = DM_RESP_BAD_REQUEST;
1096 add_status(ctx, syncbody, server_msgid, server_cmdid,
1097 cmdid, name, res, locuri);
1098 if (res == DM_RESP_OK && value) {
1099 cmdid++;
1100 add_results(ctx, syncbody, server_msgid,
1101 server_cmdid, cmdid, locuri, value);
1102 }
1103 os_free(locuri);
1104 xml_node_get_text_free(ctx->xml, value);
1105 resp_needed = 1;
1106 #if 0 /* TODO: MUST support */
1107 } else if (os_strcasecmp(name, "Delete") == 0) {
1108 #endif
1109 #if 0 /* TODO: MUST support */
1110 } else if (os_strcasecmp(name, "Sequence") == 0) {
1111 #endif
1112 } else if (os_strcasecmp(name, "Final") == 0) {
1113 final = 1;
1114 break;
1115 } else {
1116 locuri = oma_dm_get_target_locuri(ctx, child);
1117 add_status(ctx, syncbody, server_msgid, server_cmdid,
1118 cmdid, name, DM_RESP_COMMAND_NOT_IMPLEMENTED,
1119 locuri);
1120 os_free(locuri);
1121 resp_needed = 1;
1122 }
1123 }
1124
1125 if (!final) {
1126 wpa_printf(MSG_INFO, "Final node not found");
1127 xml_node_free(ctx->xml, syncml);
1128 os_free(resp_uri);
1129 return NULL;
1130 }
1131
1132 if (!resp_needed) {
1133 wpa_printf(MSG_INFO, "Exchange completed - no response needed");
1134 xml_node_free(ctx->xml, syncml);
1135 os_free(resp_uri);
1136 return NULL;
1137 }
1138
1139 xml_node_create(ctx->xml, syncbody, NULL, "Final");
1140
1141 debug_dump_node(ctx, "OMA-DM Package 3", syncml);
1142
1143 *ret_resp_uri = resp_uri;
1144 return syncml;
1145 }
1146
1147
cmd_oma_dm_prov(struct hs20_osu_client * ctx,const char * url)1148 int cmd_oma_dm_prov(struct hs20_osu_client *ctx, const char *url)
1149 {
1150 xml_node_t *syncml, *resp;
1151 char *resp_uri = NULL;
1152 int msgid = 0;
1153
1154 if (url == NULL) {
1155 wpa_printf(MSG_INFO, "Invalid prov command (missing URL)");
1156 return -1;
1157 }
1158
1159 wpa_printf(MSG_INFO, "OMA-DM credential provisioning requested");
1160 write_summary(ctx, "OMA-DM credential provisioning");
1161
1162 msgid++;
1163 syncml = build_oma_dm_1_sub_reg(ctx, url, msgid);
1164 if (syncml == NULL)
1165 return -1;
1166
1167 while (syncml) {
1168 resp = oma_dm_send_recv(ctx, resp_uri ? resp_uri : url,
1169 syncml, NULL, NULL, NULL, NULL, NULL);
1170 if (resp == NULL)
1171 return -1;
1172
1173 msgid++;
1174 syncml = oma_dm_process(ctx, url, resp, msgid, &resp_uri,
1175 NULL, NULL);
1176 xml_node_free(ctx->xml, resp);
1177 }
1178
1179 os_free(resp_uri);
1180
1181 return ctx->pps_cred_set ? 0 : -1;
1182 }
1183
1184
cmd_oma_dm_sim_prov(struct hs20_osu_client * ctx,const char * url)1185 int cmd_oma_dm_sim_prov(struct hs20_osu_client *ctx, const char *url)
1186 {
1187 xml_node_t *syncml, *resp;
1188 char *resp_uri = NULL;
1189 int msgid = 0;
1190
1191 if (url == NULL) {
1192 wpa_printf(MSG_INFO, "Invalid prov command (missing URL)");
1193 return -1;
1194 }
1195
1196 wpa_printf(MSG_INFO, "OMA-DM SIM provisioning requested");
1197 ctx->no_reconnect = 2;
1198
1199 wpa_printf(MSG_INFO, "Wait for IP address before starting SIM provisioning");
1200 write_summary(ctx, "Wait for IP address before starting SIM provisioning");
1201
1202 if (wait_ip_addr(ctx->ifname, 15) < 0) {
1203 wpa_printf(MSG_INFO, "Could not get IP address for WLAN - try connection anyway");
1204 }
1205 write_summary(ctx, "OMA-DM SIM provisioning");
1206
1207 msgid++;
1208 syncml = build_oma_dm_1_sub_prov(ctx, url, msgid);
1209 if (syncml == NULL)
1210 return -1;
1211
1212 while (syncml) {
1213 resp = oma_dm_send_recv(ctx, resp_uri ? resp_uri : url,
1214 syncml, NULL, NULL, NULL, NULL, NULL);
1215 if (resp == NULL)
1216 return -1;
1217
1218 msgid++;
1219 syncml = oma_dm_process(ctx, url, resp, msgid, &resp_uri,
1220 NULL, NULL);
1221 xml_node_free(ctx->xml, resp);
1222 }
1223
1224 os_free(resp_uri);
1225
1226 if (ctx->pps_cred_set) {
1227 wpa_printf(MSG_INFO, "Updating wpa_supplicant credentials");
1228 cmd_set_pps(ctx, ctx->pps_fname);
1229
1230 wpa_printf(MSG_INFO, "Requesting reconnection with updated configuration");
1231 write_summary(ctx, "Requesting reconnection with updated configuration");
1232 if (wpa_command(ctx->ifname, "INTERWORKING_SELECT auto") < 0) {
1233 wpa_printf(MSG_INFO, "Failed to request wpa_supplicant to reconnect");
1234 write_summary(ctx, "Failed to request wpa_supplicant to reconnect");
1235 return -1;
1236 }
1237 }
1238
1239 return ctx->pps_cred_set ? 0 : -1;
1240 }
1241
1242
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)1243 void oma_dm_pol_upd(struct hs20_osu_client *ctx, const char *address,
1244 const char *pps_fname,
1245 const char *client_cert, const char *client_key,
1246 const char *cred_username, const char *cred_password,
1247 xml_node_t *pps)
1248 {
1249 xml_node_t *syncml, *resp;
1250 char *resp_uri = NULL;
1251 int msgid = 0;
1252
1253 wpa_printf(MSG_INFO, "OMA-DM policy update");
1254 write_summary(ctx, "OMA-DM policy update");
1255
1256 msgid++;
1257 syncml = build_oma_dm_1_pol_upd(ctx, address, msgid);
1258 if (syncml == NULL)
1259 return;
1260
1261 while (syncml) {
1262 resp = oma_dm_send_recv(ctx, resp_uri ? resp_uri : address,
1263 syncml, NULL, cred_username,
1264 cred_password, client_cert, client_key);
1265 if (resp == NULL)
1266 return;
1267
1268 msgid++;
1269 syncml = oma_dm_process(ctx, address, resp, msgid, &resp_uri,
1270 pps, pps_fname);
1271 xml_node_free(ctx->xml, resp);
1272 }
1273
1274 os_free(resp_uri);
1275
1276 if (ctx->pps_updated) {
1277 wpa_printf(MSG_INFO, "Update wpa_supplicant credential based on updated PPS MO");
1278 write_summary(ctx, "Update wpa_supplicant credential based on updated PPS MO and request connection");
1279 cmd_set_pps(ctx, pps_fname);
1280 if (wpa_command(ctx->ifname, "INTERWORKING_SELECT auto") < 0) {
1281 wpa_printf(MSG_INFO,
1282 "Failed to request wpa_supplicant to reconnect");
1283 write_summary(ctx,
1284 "Failed to request wpa_supplicant to reconnect");
1285 }
1286 }
1287 }
1288
1289
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)1290 void oma_dm_sub_rem(struct hs20_osu_client *ctx, const char *address,
1291 const char *pps_fname,
1292 const char *client_cert, const char *client_key,
1293 const char *cred_username, const char *cred_password,
1294 xml_node_t *pps)
1295 {
1296 xml_node_t *syncml, *resp;
1297 char *resp_uri = NULL;
1298 int msgid = 0;
1299
1300 wpa_printf(MSG_INFO, "OMA-DM subscription remediation");
1301 write_summary(ctx, "OMA-DM subscription remediation");
1302
1303 msgid++;
1304 syncml = build_oma_dm_1_sub_rem(ctx, address, msgid);
1305 if (syncml == NULL)
1306 return;
1307
1308 while (syncml) {
1309 resp = oma_dm_send_recv(ctx, resp_uri ? resp_uri : address,
1310 syncml, NULL, cred_username,
1311 cred_password, client_cert, client_key);
1312 if (resp == NULL)
1313 return;
1314
1315 msgid++;
1316 syncml = oma_dm_process(ctx, address, resp, msgid, &resp_uri,
1317 pps, pps_fname);
1318 xml_node_free(ctx->xml, resp);
1319 }
1320
1321 os_free(resp_uri);
1322
1323 wpa_printf(MSG_INFO, "Update wpa_supplicant credential based on updated PPS MO and request reconnection");
1324 write_summary(ctx, "Update wpa_supplicant credential based on updated PPS MO and request reconnection");
1325 cmd_set_pps(ctx, pps_fname);
1326 if (wpa_command(ctx->ifname, "INTERWORKING_SELECT auto") < 0) {
1327 wpa_printf(MSG_INFO, "Failed to request wpa_supplicant to reconnect");
1328 write_summary(ctx, "Failed to request wpa_supplicant to reconnect");
1329 }
1330 }
1331
1332
cmd_oma_dm_add(struct hs20_osu_client * ctx,const char * pps_fname,const char * add_fname)1333 void cmd_oma_dm_add(struct hs20_osu_client *ctx, const char *pps_fname,
1334 const char *add_fname)
1335 {
1336 xml_node_t *pps, *add;
1337 int res;
1338
1339 ctx->fqdn = os_strdup("wi-fi.org");
1340
1341 pps = node_from_file(ctx->xml, pps_fname);
1342 if (pps == NULL) {
1343 wpa_printf(MSG_INFO, "PPS file %s could not be parsed",
1344 pps_fname);
1345 return;
1346 }
1347
1348 add = node_from_file(ctx->xml, add_fname);
1349 if (add == NULL) {
1350 wpa_printf(MSG_INFO, "Add file %s could not be parsed",
1351 add_fname);
1352 xml_node_free(ctx->xml, pps);
1353 return;
1354 }
1355
1356 res = oma_dm_add(ctx, add, pps, pps_fname);
1357 wpa_printf(MSG_INFO, "oma_dm_add --> %d", res);
1358
1359 xml_node_free(ctx->xml, pps);
1360 xml_node_free(ctx->xml, add);
1361 }
1362
1363
cmd_oma_dm_replace(struct hs20_osu_client * ctx,const char * pps_fname,const char * replace_fname)1364 void cmd_oma_dm_replace(struct hs20_osu_client *ctx, const char *pps_fname,
1365 const char *replace_fname)
1366 {
1367 xml_node_t *pps, *replace;
1368 int res;
1369
1370 ctx->fqdn = os_strdup("wi-fi.org");
1371
1372 pps = node_from_file(ctx->xml, pps_fname);
1373 if (pps == NULL) {
1374 wpa_printf(MSG_INFO, "PPS file %s could not be parsed",
1375 pps_fname);
1376 return;
1377 }
1378
1379 replace = node_from_file(ctx->xml, replace_fname);
1380 if (replace == NULL) {
1381 wpa_printf(MSG_INFO, "Replace file %s could not be parsed",
1382 replace_fname);
1383 xml_node_free(ctx->xml, pps);
1384 return;
1385 }
1386
1387 res = oma_dm_replace(ctx, replace, pps, pps_fname);
1388 wpa_printf(MSG_INFO, "oma_dm_replace --> %d", res);
1389
1390 xml_node_free(ctx->xml, pps);
1391 xml_node_free(ctx->xml, replace);
1392 }
1393