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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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