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