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