15b9c547cSRui Paulo /* 25b9c547cSRui Paulo * Hotspot 2.0 - OMA DM client 35b9c547cSRui Paulo * Copyright (c) 2013-2014, Qualcomm Atheros, Inc. 45b9c547cSRui Paulo * 55b9c547cSRui Paulo * This software may be distributed under the terms of the BSD license. 65b9c547cSRui Paulo * See README for more details. 75b9c547cSRui Paulo */ 85b9c547cSRui Paulo 95b9c547cSRui Paulo #include "includes.h" 105b9c547cSRui Paulo 115b9c547cSRui Paulo #include "common.h" 125b9c547cSRui Paulo #include "wpa_helpers.h" 135b9c547cSRui Paulo #include "xml-utils.h" 145b9c547cSRui Paulo #include "http-utils.h" 155b9c547cSRui Paulo #include "utils/browser.h" 165b9c547cSRui Paulo #include "osu_client.h" 175b9c547cSRui Paulo 185b9c547cSRui Paulo 195b9c547cSRui Paulo #define DM_SERVER_INITIATED_MGMT 1200 205b9c547cSRui Paulo #define DM_CLIENT_INITIATED_MGMT 1201 215b9c547cSRui Paulo #define DM_GENERIC_ALERT 1226 225b9c547cSRui Paulo 235b9c547cSRui Paulo /* OMA-TS-SyncML-RepPro-V1_2_2 - 10. Response Status Codes */ 245b9c547cSRui Paulo #define DM_RESP_OK 200 255b9c547cSRui Paulo #define DM_RESP_AUTH_ACCEPTED 212 265b9c547cSRui Paulo #define DM_RESP_CHUNKED_ITEM_ACCEPTED 213 275b9c547cSRui Paulo #define DM_RESP_NOT_EXECUTED 215 285b9c547cSRui Paulo #define DM_RESP_ATOMIC_ROLL_BACK_OK 216 295b9c547cSRui Paulo #define DM_RESP_NOT_MODIFIED 304 305b9c547cSRui Paulo #define DM_RESP_BAD_REQUEST 400 315b9c547cSRui Paulo #define DM_RESP_UNAUTHORIZED 401 325b9c547cSRui Paulo #define DM_RESP_FORBIDDEN 403 335b9c547cSRui Paulo #define DM_RESP_NOT_FOUND 404 345b9c547cSRui Paulo #define DM_RESP_COMMAND_NOT_ALLOWED 405 355b9c547cSRui Paulo #define DM_RESP_OPTIONAL_FEATURE_NOT_SUPPORTED 406 365b9c547cSRui Paulo #define DM_RESP_MISSING_CREDENTIALS 407 375b9c547cSRui Paulo #define DM_RESP_CONFLICT 409 385b9c547cSRui Paulo #define DM_RESP_GONE 410 395b9c547cSRui Paulo #define DM_RESP_INCOMPLETE_COMMAND 412 405b9c547cSRui Paulo #define DM_RESP_REQ_ENTITY_TOO_LARGE 413 415b9c547cSRui Paulo #define DM_RESP_URI_TOO_LONG 414 425b9c547cSRui Paulo #define DM_RESP_UNSUPPORTED_MEDIA_TYPE_OR_FORMAT 415 435b9c547cSRui Paulo #define DM_RESP_REQ_TOO_BIG 416 445b9c547cSRui Paulo #define DM_RESP_ALREADY_EXISTS 418 455b9c547cSRui Paulo #define DM_RESP_DEVICE_FULL 420 465b9c547cSRui Paulo #define DM_RESP_SIZE_MISMATCH 424 475b9c547cSRui Paulo #define DM_RESP_PERMISSION_DENIED 425 485b9c547cSRui Paulo #define DM_RESP_COMMAND_FAILED 500 495b9c547cSRui Paulo #define DM_RESP_COMMAND_NOT_IMPLEMENTED 501 505b9c547cSRui Paulo #define DM_RESP_ATOMIC_ROLL_BACK_FAILED 516 515b9c547cSRui Paulo 525b9c547cSRui Paulo #define DM_HS20_SUBSCRIPTION_CREATION \ 535b9c547cSRui Paulo "org.wi-fi.hotspot2dot0.SubscriptionCreation" 545b9c547cSRui Paulo #define DM_HS20_SUBSCRIPTION_PROVISIONING \ 555b9c547cSRui Paulo "org.wi-fi.hotspot2dot0.SubscriptionProvisioning" 565b9c547cSRui Paulo #define DM_HS20_SUBSCRIPTION_REMEDIATION \ 575b9c547cSRui Paulo "org.wi-fi.hotspot2dot0.SubscriptionRemediation" 585b9c547cSRui Paulo #define DM_HS20_POLICY_UPDATE \ 595b9c547cSRui Paulo "org.wi-fi.hotspot2dot0.PolicyUpdate" 605b9c547cSRui Paulo 615b9c547cSRui Paulo #define DM_URI_PPS "./Wi-Fi/org.wi-fi/PerProviderSubscription" 625b9c547cSRui Paulo #define DM_URI_LAUNCH_BROWSER \ 635b9c547cSRui Paulo "./DevDetail/Ext/org.wi-fi/Wi-Fi/Ops/launchBrowserToURI" 645b9c547cSRui Paulo 655b9c547cSRui Paulo 665b9c547cSRui Paulo static void add_item(struct hs20_osu_client *ctx, xml_node_t *parent, 675b9c547cSRui Paulo const char *locuri, const char *data); 685b9c547cSRui Paulo 695b9c547cSRui Paulo 705b9c547cSRui Paulo static const char * int2str(int val) 715b9c547cSRui Paulo { 725b9c547cSRui Paulo static char buf[20]; 735b9c547cSRui Paulo snprintf(buf, sizeof(buf), "%d", val); 745b9c547cSRui Paulo return buf; 755b9c547cSRui Paulo } 765b9c547cSRui Paulo 775b9c547cSRui Paulo 785b9c547cSRui Paulo static char * oma_dm_get_target_locuri(struct hs20_osu_client *ctx, 795b9c547cSRui Paulo xml_node_t *node) 805b9c547cSRui Paulo { 815b9c547cSRui Paulo xml_node_t *locuri; 825b9c547cSRui Paulo char *uri, *ret = NULL; 835b9c547cSRui Paulo 845b9c547cSRui Paulo locuri = get_node(ctx->xml, node, "Item/Target/LocURI"); 855b9c547cSRui Paulo if (locuri == NULL) 865b9c547cSRui Paulo return NULL; 875b9c547cSRui Paulo 885b9c547cSRui Paulo uri = xml_node_get_text(ctx->xml, locuri); 895b9c547cSRui Paulo if (uri) 905b9c547cSRui Paulo ret = os_strdup(uri); 915b9c547cSRui Paulo xml_node_get_text_free(ctx->xml, uri); 925b9c547cSRui Paulo return ret; 935b9c547cSRui Paulo } 945b9c547cSRui Paulo 955b9c547cSRui Paulo 965b9c547cSRui Paulo static void oma_dm_add_locuri(struct hs20_osu_client *ctx, xml_node_t *parent, 975b9c547cSRui Paulo const char *element, const char *uri) 985b9c547cSRui Paulo { 995b9c547cSRui Paulo xml_node_t *node; 1005b9c547cSRui Paulo 1015b9c547cSRui Paulo node = xml_node_create(ctx->xml, parent, NULL, element); 1025b9c547cSRui Paulo if (node == NULL) 1035b9c547cSRui Paulo return; 1045b9c547cSRui Paulo xml_node_create_text(ctx->xml, node, NULL, "LocURI", uri); 1055b9c547cSRui Paulo } 1065b9c547cSRui Paulo 1075b9c547cSRui Paulo 1085b9c547cSRui Paulo static xml_node_t * oma_dm_build_hdr(struct hs20_osu_client *ctx, 1095b9c547cSRui Paulo const char *url, int msgid) 1105b9c547cSRui Paulo { 1115b9c547cSRui Paulo xml_node_t *syncml, *synchdr; 1125b9c547cSRui Paulo xml_namespace_t *ns; 1135b9c547cSRui Paulo 114*85732ac8SCy Schubert if (!ctx->devid) { 115*85732ac8SCy Schubert wpa_printf(MSG_ERROR, 116*85732ac8SCy Schubert "DevId from devinfo.xml is not available - cannot use OMA DM"); 117*85732ac8SCy Schubert return NULL; 118*85732ac8SCy Schubert } 119*85732ac8SCy Schubert 1205b9c547cSRui Paulo syncml = xml_node_create_root(ctx->xml, "SYNCML:SYNCML1.2", NULL, &ns, 1215b9c547cSRui Paulo "SyncML"); 1225b9c547cSRui Paulo 1235b9c547cSRui Paulo synchdr = xml_node_create(ctx->xml, syncml, NULL, "SyncHdr"); 1245b9c547cSRui Paulo xml_node_create_text(ctx->xml, synchdr, NULL, "VerDTD", "1.2"); 1255b9c547cSRui Paulo xml_node_create_text(ctx->xml, synchdr, NULL, "VerProto", "DM/1.2"); 1265b9c547cSRui Paulo xml_node_create_text(ctx->xml, synchdr, NULL, "SessionID", "1"); 1275b9c547cSRui Paulo xml_node_create_text(ctx->xml, synchdr, NULL, "MsgID", int2str(msgid)); 1285b9c547cSRui Paulo 1295b9c547cSRui Paulo oma_dm_add_locuri(ctx, synchdr, "Target", url); 1305b9c547cSRui Paulo oma_dm_add_locuri(ctx, synchdr, "Source", ctx->devid); 1315b9c547cSRui Paulo 1325b9c547cSRui Paulo return syncml; 1335b9c547cSRui Paulo } 1345b9c547cSRui Paulo 1355b9c547cSRui Paulo 1365b9c547cSRui Paulo static void oma_dm_add_cmdid(struct hs20_osu_client *ctx, xml_node_t *parent, 1375b9c547cSRui Paulo int cmdid) 1385b9c547cSRui Paulo { 1395b9c547cSRui Paulo xml_node_create_text(ctx->xml, parent, NULL, "CmdID", int2str(cmdid)); 1405b9c547cSRui Paulo } 1415b9c547cSRui Paulo 1425b9c547cSRui Paulo 1435b9c547cSRui Paulo static xml_node_t * add_alert(struct hs20_osu_client *ctx, xml_node_t *parent, 1445b9c547cSRui Paulo int cmdid, int data) 1455b9c547cSRui Paulo { 1465b9c547cSRui Paulo xml_node_t *node; 1475b9c547cSRui Paulo 1485b9c547cSRui Paulo node = xml_node_create(ctx->xml, parent, NULL, "Alert"); 1495b9c547cSRui Paulo if (node == NULL) 1505b9c547cSRui Paulo return NULL; 1515b9c547cSRui Paulo oma_dm_add_cmdid(ctx, node, cmdid); 1525b9c547cSRui Paulo xml_node_create_text(ctx->xml, node, NULL, "Data", int2str(data)); 1535b9c547cSRui Paulo 1545b9c547cSRui Paulo return node; 1555b9c547cSRui Paulo } 1565b9c547cSRui Paulo 1575b9c547cSRui Paulo 1585b9c547cSRui Paulo static xml_node_t * add_status(struct hs20_osu_client *ctx, xml_node_t *parent, 1595b9c547cSRui Paulo int msgref, int cmdref, int cmdid, 1605b9c547cSRui Paulo const char *cmd, int data, const char *targetref) 1615b9c547cSRui Paulo { 1625b9c547cSRui Paulo xml_node_t *node; 1635b9c547cSRui Paulo 1645b9c547cSRui Paulo node = xml_node_create(ctx->xml, parent, NULL, "Status"); 1655b9c547cSRui Paulo if (node == NULL) 1665b9c547cSRui Paulo return NULL; 1675b9c547cSRui Paulo oma_dm_add_cmdid(ctx, node, cmdid); 1685b9c547cSRui Paulo xml_node_create_text(ctx->xml, node, NULL, "MsgRef", int2str(msgref)); 1695b9c547cSRui Paulo if (cmdref) 1705b9c547cSRui Paulo xml_node_create_text(ctx->xml, node, NULL, "CmdRef", 1715b9c547cSRui Paulo int2str(cmdref)); 1725b9c547cSRui Paulo xml_node_create_text(ctx->xml, node, NULL, "Cmd", cmd); 1735b9c547cSRui Paulo xml_node_create_text(ctx->xml, node, NULL, "Data", int2str(data)); 1745b9c547cSRui Paulo if (targetref) { 1755b9c547cSRui Paulo xml_node_create_text(ctx->xml, node, NULL, "TargetRef", 1765b9c547cSRui Paulo targetref); 1775b9c547cSRui Paulo } 1785b9c547cSRui Paulo 1795b9c547cSRui Paulo return node; 1805b9c547cSRui Paulo } 1815b9c547cSRui Paulo 1825b9c547cSRui Paulo 1835b9c547cSRui Paulo static xml_node_t * add_results(struct hs20_osu_client *ctx, xml_node_t *parent, 1845b9c547cSRui Paulo int msgref, int cmdref, int cmdid, 1855b9c547cSRui Paulo const char *locuri, const char *data) 1865b9c547cSRui Paulo { 1875b9c547cSRui Paulo xml_node_t *node; 1885b9c547cSRui Paulo 1895b9c547cSRui Paulo node = xml_node_create(ctx->xml, parent, NULL, "Results"); 1905b9c547cSRui Paulo if (node == NULL) 1915b9c547cSRui Paulo return NULL; 1925b9c547cSRui Paulo 1935b9c547cSRui Paulo oma_dm_add_cmdid(ctx, node, cmdid); 1945b9c547cSRui Paulo xml_node_create_text(ctx->xml, node, NULL, "MsgRef", int2str(msgref)); 1955b9c547cSRui Paulo xml_node_create_text(ctx->xml, node, NULL, "CmdRef", int2str(cmdref)); 1965b9c547cSRui Paulo add_item(ctx, node, locuri, data); 1975b9c547cSRui Paulo 1985b9c547cSRui Paulo return node; 1995b9c547cSRui Paulo } 2005b9c547cSRui Paulo 2015b9c547cSRui Paulo 2025b9c547cSRui Paulo static char * mo_str(struct hs20_osu_client *ctx, const char *urn, 2035b9c547cSRui Paulo const char *fname) 2045b9c547cSRui Paulo { 2055b9c547cSRui Paulo xml_node_t *fnode, *tnds; 2065b9c547cSRui Paulo char *str; 2075b9c547cSRui Paulo 2085b9c547cSRui Paulo fnode = node_from_file(ctx->xml, fname); 2095b9c547cSRui Paulo if (!fnode) 2105b9c547cSRui Paulo return NULL; 2115b9c547cSRui Paulo tnds = mo_to_tnds(ctx->xml, fnode, 0, urn, "syncml:dmddf1.2"); 2125b9c547cSRui Paulo xml_node_free(ctx->xml, fnode); 2135b9c547cSRui Paulo if (!tnds) 2145b9c547cSRui Paulo return NULL; 2155b9c547cSRui Paulo 2165b9c547cSRui Paulo str = xml_node_to_str(ctx->xml, tnds); 2175b9c547cSRui Paulo xml_node_free(ctx->xml, tnds); 2185b9c547cSRui Paulo if (str == NULL) 2195b9c547cSRui Paulo return NULL; 2205b9c547cSRui Paulo wpa_printf(MSG_INFO, "MgmtTree: %s", str); 2215b9c547cSRui Paulo 2225b9c547cSRui Paulo return str; 2235b9c547cSRui Paulo } 2245b9c547cSRui Paulo 2255b9c547cSRui Paulo 2265b9c547cSRui Paulo static void add_item(struct hs20_osu_client *ctx, xml_node_t *parent, 2275b9c547cSRui Paulo const char *locuri, const char *data) 2285b9c547cSRui Paulo { 2295b9c547cSRui Paulo xml_node_t *item, *node; 2305b9c547cSRui Paulo 2315b9c547cSRui Paulo item = xml_node_create(ctx->xml, parent, NULL, "Item"); 2325b9c547cSRui Paulo oma_dm_add_locuri(ctx, item, "Source", locuri); 2335b9c547cSRui Paulo node = xml_node_create(ctx->xml, item, NULL, "Meta"); 2345b9c547cSRui Paulo xml_node_create_text_ns(ctx->xml, node, "syncml:metinf", "Format", 2355b9c547cSRui Paulo "Chr"); 2365b9c547cSRui Paulo xml_node_create_text_ns(ctx->xml, node, "syncml:metinf", "Type", 2375b9c547cSRui Paulo "text/plain"); 2385b9c547cSRui Paulo xml_node_create_text(ctx->xml, item, NULL, "Data", data); 2395b9c547cSRui Paulo } 2405b9c547cSRui Paulo 2415b9c547cSRui Paulo 2425b9c547cSRui Paulo static void add_replace_devinfo(struct hs20_osu_client *ctx, xml_node_t *parent, 2435b9c547cSRui Paulo int cmdid) 2445b9c547cSRui Paulo { 2455b9c547cSRui Paulo xml_node_t *info, *child, *replace; 2465b9c547cSRui Paulo const char *name; 2475b9c547cSRui Paulo char locuri[200], *txt; 2485b9c547cSRui Paulo 2495b9c547cSRui Paulo info = node_from_file(ctx->xml, "devinfo.xml"); 2505b9c547cSRui Paulo if (info == NULL) { 2515b9c547cSRui Paulo wpa_printf(MSG_INFO, "Could not read devinfo.xml"); 2525b9c547cSRui Paulo return; 2535b9c547cSRui Paulo } 2545b9c547cSRui Paulo 2555b9c547cSRui Paulo replace = xml_node_create(ctx->xml, parent, NULL, "Replace"); 2565b9c547cSRui Paulo if (replace == NULL) { 2575b9c547cSRui Paulo xml_node_free(ctx->xml, info); 2585b9c547cSRui Paulo return; 2595b9c547cSRui Paulo } 2605b9c547cSRui Paulo oma_dm_add_cmdid(ctx, replace, cmdid); 2615b9c547cSRui Paulo 2625b9c547cSRui Paulo xml_node_for_each_child(ctx->xml, child, info) { 2635b9c547cSRui Paulo xml_node_for_each_check(ctx->xml, child); 2645b9c547cSRui Paulo name = xml_node_get_localname(ctx->xml, child); 2655b9c547cSRui Paulo os_snprintf(locuri, sizeof(locuri), "./DevInfo/%s", name); 2665b9c547cSRui Paulo txt = xml_node_get_text(ctx->xml, child); 2675b9c547cSRui Paulo if (txt) { 2685b9c547cSRui Paulo add_item(ctx, replace, locuri, txt); 2695b9c547cSRui Paulo xml_node_get_text_free(ctx->xml, txt); 2705b9c547cSRui Paulo } 2715b9c547cSRui Paulo } 2725b9c547cSRui Paulo 2735b9c547cSRui Paulo xml_node_free(ctx->xml, info); 2745b9c547cSRui Paulo } 2755b9c547cSRui Paulo 2765b9c547cSRui Paulo 2775b9c547cSRui Paulo static void oma_dm_add_hs20_generic_alert(struct hs20_osu_client *ctx, 2785b9c547cSRui Paulo xml_node_t *syncbody, 2795b9c547cSRui Paulo int cmdid, const char *oper, 2805b9c547cSRui Paulo const char *data) 2815b9c547cSRui Paulo { 2825b9c547cSRui Paulo xml_node_t *node, *item; 2835b9c547cSRui Paulo char buf[200]; 2845b9c547cSRui Paulo 2855b9c547cSRui Paulo node = add_alert(ctx, syncbody, cmdid, DM_GENERIC_ALERT); 2865b9c547cSRui Paulo 2875b9c547cSRui Paulo item = xml_node_create(ctx->xml, node, NULL, "Item"); 2885b9c547cSRui Paulo oma_dm_add_locuri(ctx, item, "Source", DM_URI_PPS); 2895b9c547cSRui Paulo node = xml_node_create(ctx->xml, item, NULL, "Meta"); 2905b9c547cSRui Paulo snprintf(buf, sizeof(buf), "Reversed-Domain-Name: %s", oper); 2915b9c547cSRui Paulo xml_node_create_text_ns(ctx->xml, node, "syncml:metinf", "Type", buf); 2925b9c547cSRui Paulo xml_node_create_text_ns(ctx->xml, node, "syncml:metinf", "Format", 2935b9c547cSRui Paulo "xml"); 2945b9c547cSRui Paulo xml_node_create_text(ctx->xml, item, NULL, "Data", data); 2955b9c547cSRui Paulo } 2965b9c547cSRui Paulo 2975b9c547cSRui Paulo 2985b9c547cSRui Paulo static xml_node_t * build_oma_dm_1(struct hs20_osu_client *ctx, 2995b9c547cSRui Paulo const char *url, int msgid, const char *oper) 3005b9c547cSRui Paulo { 3015b9c547cSRui Paulo xml_node_t *syncml, *syncbody; 3025b9c547cSRui Paulo char *str; 3035b9c547cSRui Paulo int cmdid = 0; 3045b9c547cSRui Paulo 3055b9c547cSRui Paulo syncml = oma_dm_build_hdr(ctx, url, msgid); 3065b9c547cSRui Paulo if (syncml == NULL) 3075b9c547cSRui Paulo return NULL; 3085b9c547cSRui Paulo 3095b9c547cSRui Paulo syncbody = xml_node_create(ctx->xml, syncml, NULL, "SyncBody"); 3105b9c547cSRui Paulo if (syncbody == NULL) { 3115b9c547cSRui Paulo xml_node_free(ctx->xml, syncml); 3125b9c547cSRui Paulo return NULL; 3135b9c547cSRui Paulo } 3145b9c547cSRui Paulo 3155b9c547cSRui Paulo cmdid++; 3165b9c547cSRui Paulo add_alert(ctx, syncbody, cmdid, DM_CLIENT_INITIATED_MGMT); 3175b9c547cSRui Paulo 3185b9c547cSRui Paulo str = mo_str(ctx, NULL, "devdetail.xml"); 3195b9c547cSRui Paulo if (str == NULL) { 3205b9c547cSRui Paulo xml_node_free(ctx->xml, syncml); 3215b9c547cSRui Paulo return NULL; 3225b9c547cSRui Paulo } 3235b9c547cSRui Paulo cmdid++; 3245b9c547cSRui Paulo oma_dm_add_hs20_generic_alert(ctx, syncbody, cmdid, oper, str); 3255b9c547cSRui Paulo os_free(str); 3265b9c547cSRui Paulo 3275b9c547cSRui Paulo cmdid++; 3285b9c547cSRui Paulo add_replace_devinfo(ctx, syncbody, cmdid); 3295b9c547cSRui Paulo 3305b9c547cSRui Paulo xml_node_create(ctx->xml, syncbody, NULL, "Final"); 3315b9c547cSRui Paulo 3325b9c547cSRui Paulo return syncml; 3335b9c547cSRui Paulo } 3345b9c547cSRui Paulo 3355b9c547cSRui Paulo 3365b9c547cSRui Paulo static xml_node_t * build_oma_dm_1_sub_reg(struct hs20_osu_client *ctx, 3375b9c547cSRui Paulo const char *url, int msgid) 3385b9c547cSRui Paulo { 3395b9c547cSRui Paulo xml_node_t *syncml; 3405b9c547cSRui Paulo 3415b9c547cSRui Paulo syncml = build_oma_dm_1(ctx, url, msgid, DM_HS20_SUBSCRIPTION_CREATION); 3425b9c547cSRui Paulo if (syncml) 3435b9c547cSRui Paulo debug_dump_node(ctx, "OMA-DM Package 1 (sub reg)", syncml); 3445b9c547cSRui Paulo 3455b9c547cSRui Paulo return syncml; 3465b9c547cSRui Paulo } 3475b9c547cSRui Paulo 3485b9c547cSRui Paulo 3495b9c547cSRui Paulo static xml_node_t * build_oma_dm_1_sub_prov(struct hs20_osu_client *ctx, 3505b9c547cSRui Paulo const char *url, int msgid) 3515b9c547cSRui Paulo { 3525b9c547cSRui Paulo xml_node_t *syncml; 3535b9c547cSRui Paulo 3545b9c547cSRui Paulo syncml = build_oma_dm_1(ctx, url, msgid, 3555b9c547cSRui Paulo DM_HS20_SUBSCRIPTION_PROVISIONING); 3565b9c547cSRui Paulo if (syncml) 3575b9c547cSRui Paulo debug_dump_node(ctx, "OMA-DM Package 1 (sub prov)", syncml); 3585b9c547cSRui Paulo 3595b9c547cSRui Paulo return syncml; 3605b9c547cSRui Paulo } 3615b9c547cSRui Paulo 3625b9c547cSRui Paulo 3635b9c547cSRui Paulo static xml_node_t * build_oma_dm_1_pol_upd(struct hs20_osu_client *ctx, 3645b9c547cSRui Paulo const char *url, int msgid) 3655b9c547cSRui Paulo { 3665b9c547cSRui Paulo xml_node_t *syncml; 3675b9c547cSRui Paulo 3685b9c547cSRui Paulo syncml = build_oma_dm_1(ctx, url, msgid, DM_HS20_POLICY_UPDATE); 3695b9c547cSRui Paulo if (syncml) 3705b9c547cSRui Paulo debug_dump_node(ctx, "OMA-DM Package 1 (pol upd)", syncml); 3715b9c547cSRui Paulo 3725b9c547cSRui Paulo return syncml; 3735b9c547cSRui Paulo } 3745b9c547cSRui Paulo 3755b9c547cSRui Paulo 3765b9c547cSRui Paulo static xml_node_t * build_oma_dm_1_sub_rem(struct hs20_osu_client *ctx, 3775b9c547cSRui Paulo const char *url, int msgid) 3785b9c547cSRui Paulo { 3795b9c547cSRui Paulo xml_node_t *syncml; 3805b9c547cSRui Paulo 3815b9c547cSRui Paulo syncml = build_oma_dm_1(ctx, url, msgid, 3825b9c547cSRui Paulo DM_HS20_SUBSCRIPTION_REMEDIATION); 3835b9c547cSRui Paulo if (syncml) 3845b9c547cSRui Paulo debug_dump_node(ctx, "OMA-DM Package 1 (sub rem)", syncml); 3855b9c547cSRui Paulo 3865b9c547cSRui Paulo return syncml; 3875b9c547cSRui Paulo } 3885b9c547cSRui Paulo 3895b9c547cSRui Paulo 3905b9c547cSRui Paulo static int oma_dm_exec_browser(struct hs20_osu_client *ctx, xml_node_t *exec) 3915b9c547cSRui Paulo { 3925b9c547cSRui Paulo xml_node_t *node; 3935b9c547cSRui Paulo char *data; 3945b9c547cSRui Paulo int res; 3955b9c547cSRui Paulo 3965b9c547cSRui Paulo node = get_node(ctx->xml, exec, "Item/Data"); 3975b9c547cSRui Paulo if (node == NULL) { 3985b9c547cSRui Paulo wpa_printf(MSG_INFO, "No Data node found"); 3995b9c547cSRui Paulo return DM_RESP_BAD_REQUEST; 4005b9c547cSRui Paulo } 4015b9c547cSRui Paulo 4025b9c547cSRui Paulo data = xml_node_get_text(ctx->xml, node); 4035b9c547cSRui Paulo if (data == NULL) { 4045b9c547cSRui Paulo wpa_printf(MSG_INFO, "Invalid data"); 4055b9c547cSRui Paulo return DM_RESP_BAD_REQUEST; 4065b9c547cSRui Paulo } 4075b9c547cSRui Paulo wpa_printf(MSG_INFO, "Data: %s", data); 4085b9c547cSRui Paulo wpa_printf(MSG_INFO, "Launch browser to URI '%s'", data); 4095b9c547cSRui Paulo write_summary(ctx, "Launch browser to URI '%s'", data); 4105b9c547cSRui Paulo res = hs20_web_browser(data); 4115b9c547cSRui Paulo xml_node_get_text_free(ctx->xml, data); 4125b9c547cSRui Paulo if (res > 0) { 4135b9c547cSRui Paulo wpa_printf(MSG_INFO, "User response in browser completed successfully"); 4145b9c547cSRui Paulo write_summary(ctx, "User response in browser completed successfully"); 4155b9c547cSRui Paulo return DM_RESP_OK; 4165b9c547cSRui Paulo } else { 4175b9c547cSRui Paulo wpa_printf(MSG_INFO, "Failed to receive user response"); 4185b9c547cSRui Paulo write_summary(ctx, "Failed to receive user response"); 4195b9c547cSRui Paulo return DM_RESP_COMMAND_FAILED; 4205b9c547cSRui Paulo } 4215b9c547cSRui Paulo } 4225b9c547cSRui Paulo 4235b9c547cSRui Paulo 4245b9c547cSRui Paulo static int oma_dm_exec_get_cert(struct hs20_osu_client *ctx, xml_node_t *exec) 4255b9c547cSRui Paulo { 4265b9c547cSRui Paulo xml_node_t *node, *getcert; 4275b9c547cSRui Paulo char *data; 4285b9c547cSRui Paulo const char *name; 4295b9c547cSRui Paulo int res; 4305b9c547cSRui Paulo 4315b9c547cSRui Paulo wpa_printf(MSG_INFO, "Client certificate enrollment"); 4325b9c547cSRui Paulo write_summary(ctx, "Client certificate enrollment"); 4335b9c547cSRui Paulo 4345b9c547cSRui Paulo node = get_node(ctx->xml, exec, "Item/Data"); 4355b9c547cSRui Paulo if (node == NULL) { 4365b9c547cSRui Paulo wpa_printf(MSG_INFO, "No Data node found"); 4375b9c547cSRui Paulo return DM_RESP_BAD_REQUEST; 4385b9c547cSRui Paulo } 4395b9c547cSRui Paulo 4405b9c547cSRui Paulo data = xml_node_get_text(ctx->xml, node); 4415b9c547cSRui Paulo if (data == NULL) { 4425b9c547cSRui Paulo wpa_printf(MSG_INFO, "Invalid data"); 4435b9c547cSRui Paulo return DM_RESP_BAD_REQUEST; 4445b9c547cSRui Paulo } 4455b9c547cSRui Paulo wpa_printf(MSG_INFO, "Data: %s", data); 4465b9c547cSRui Paulo getcert = xml_node_from_buf(ctx->xml, data); 4475b9c547cSRui Paulo xml_node_get_text_free(ctx->xml, data); 4485b9c547cSRui Paulo 4495b9c547cSRui Paulo if (getcert == NULL) { 4505b9c547cSRui Paulo wpa_printf(MSG_INFO, "Could not parse Item/Data node contents"); 4515b9c547cSRui Paulo return DM_RESP_BAD_REQUEST; 4525b9c547cSRui Paulo } 4535b9c547cSRui Paulo 4545b9c547cSRui Paulo debug_dump_node(ctx, "OMA-DM getCertificate", getcert); 4555b9c547cSRui Paulo 4565b9c547cSRui Paulo name = xml_node_get_localname(ctx->xml, getcert); 4575b9c547cSRui Paulo if (name == NULL || os_strcasecmp(name, "getCertificate") != 0) { 4585b9c547cSRui Paulo wpa_printf(MSG_INFO, "Unexpected getCertificate node name '%s'", 4595b9c547cSRui Paulo name); 4605b9c547cSRui Paulo return DM_RESP_BAD_REQUEST; 4615b9c547cSRui Paulo } 4625b9c547cSRui Paulo 4635b9c547cSRui Paulo res = osu_get_certificate(ctx, getcert); 4645b9c547cSRui Paulo 4655b9c547cSRui Paulo xml_node_free(ctx->xml, getcert); 4665b9c547cSRui Paulo 4675b9c547cSRui Paulo return res == 0 ? DM_RESP_OK : DM_RESP_COMMAND_FAILED; 4685b9c547cSRui Paulo } 4695b9c547cSRui Paulo 4705b9c547cSRui Paulo 4715b9c547cSRui Paulo static int oma_dm_exec(struct hs20_osu_client *ctx, xml_node_t *exec) 4725b9c547cSRui Paulo { 4735b9c547cSRui Paulo char *locuri; 4745b9c547cSRui Paulo int ret; 4755b9c547cSRui Paulo 4765b9c547cSRui Paulo locuri = oma_dm_get_target_locuri(ctx, exec); 4775b9c547cSRui Paulo if (locuri == NULL) { 4785b9c547cSRui Paulo wpa_printf(MSG_INFO, "No Target LocURI node found"); 4795b9c547cSRui Paulo return DM_RESP_BAD_REQUEST; 4805b9c547cSRui Paulo } 4815b9c547cSRui Paulo 4825b9c547cSRui Paulo wpa_printf(MSG_INFO, "Target LocURI: %s", locuri); 4835b9c547cSRui Paulo 4845b9c547cSRui Paulo if (os_strcasecmp(locuri, "./DevDetail/Ext/org.wi-fi/Wi-Fi/Ops/" 4855b9c547cSRui Paulo "launchBrowserToURI") == 0) { 4865b9c547cSRui Paulo ret = oma_dm_exec_browser(ctx, exec); 4875b9c547cSRui Paulo } else if (os_strcasecmp(locuri, "./DevDetail/Ext/org.wi-fi/Wi-Fi/Ops/" 4885b9c547cSRui Paulo "getCertificate") == 0) { 4895b9c547cSRui Paulo ret = oma_dm_exec_get_cert(ctx, exec); 4905b9c547cSRui Paulo } else { 4915b9c547cSRui Paulo wpa_printf(MSG_INFO, "Unsupported exec Target LocURI"); 4925b9c547cSRui Paulo ret = DM_RESP_NOT_FOUND; 4935b9c547cSRui Paulo } 4945b9c547cSRui Paulo os_free(locuri); 4955b9c547cSRui Paulo 4965b9c547cSRui Paulo return ret; 4975b9c547cSRui Paulo } 4985b9c547cSRui Paulo 4995b9c547cSRui Paulo 5005b9c547cSRui Paulo static int oma_dm_run_add(struct hs20_osu_client *ctx, const char *locuri, 5015b9c547cSRui Paulo xml_node_t *add, xml_node_t *pps, 5025b9c547cSRui Paulo const char *pps_fname) 5035b9c547cSRui Paulo { 5045b9c547cSRui Paulo const char *pos; 5055b9c547cSRui Paulo size_t fqdn_len; 5065b9c547cSRui Paulo xml_node_t *node, *tnds, *unode, *pps_node; 5075b9c547cSRui Paulo char *data, *uri, *upos, *end; 5085b9c547cSRui Paulo int use_tnds = 0; 5095b9c547cSRui Paulo size_t uri_len; 5105b9c547cSRui Paulo 5115b9c547cSRui Paulo wpa_printf(MSG_INFO, "Add command target LocURI: %s", locuri); 5125b9c547cSRui Paulo 5135b9c547cSRui Paulo if (os_strncasecmp(locuri, "./Wi-Fi/", 8) != 0) { 5145b9c547cSRui Paulo wpa_printf(MSG_INFO, "Do not allow Add outside ./Wi-Fi"); 5155b9c547cSRui Paulo return DM_RESP_PERMISSION_DENIED; 5165b9c547cSRui Paulo } 5175b9c547cSRui Paulo pos = locuri + 8; 5185b9c547cSRui Paulo 5195b9c547cSRui Paulo if (ctx->fqdn == NULL) 5205b9c547cSRui Paulo return DM_RESP_COMMAND_FAILED; 5215b9c547cSRui Paulo fqdn_len = os_strlen(ctx->fqdn); 5225b9c547cSRui Paulo if (os_strncasecmp(pos, ctx->fqdn, fqdn_len) != 0 || 5235b9c547cSRui Paulo pos[fqdn_len] != '/') { 5245b9c547cSRui Paulo wpa_printf(MSG_INFO, "Do not allow Add outside ./Wi-Fi/%s", 5255b9c547cSRui Paulo ctx->fqdn); 5265b9c547cSRui Paulo return DM_RESP_PERMISSION_DENIED; 5275b9c547cSRui Paulo } 5285b9c547cSRui Paulo pos += fqdn_len + 1; 5295b9c547cSRui Paulo 5305b9c547cSRui Paulo if (os_strncasecmp(pos, "PerProviderSubscription/", 24) != 0) { 5315b9c547cSRui Paulo wpa_printf(MSG_INFO, 5325b9c547cSRui Paulo "Do not allow Add outside ./Wi-Fi/%s/PerProviderSubscription", 5335b9c547cSRui Paulo ctx->fqdn); 5345b9c547cSRui Paulo return DM_RESP_PERMISSION_DENIED; 5355b9c547cSRui Paulo } 5365b9c547cSRui Paulo pos += 24; 5375b9c547cSRui Paulo 5385b9c547cSRui Paulo wpa_printf(MSG_INFO, "Add command for PPS node %s", pos); 5395b9c547cSRui Paulo 5405b9c547cSRui Paulo pps_node = get_node(ctx->xml, pps, pos); 5415b9c547cSRui Paulo if (pps_node) { 5425b9c547cSRui Paulo wpa_printf(MSG_INFO, "Specified PPS node exists already"); 5435b9c547cSRui Paulo return DM_RESP_ALREADY_EXISTS; 5445b9c547cSRui Paulo } 5455b9c547cSRui Paulo 5465b9c547cSRui Paulo uri = os_strdup(pos); 5475b9c547cSRui Paulo if (uri == NULL) 5485b9c547cSRui Paulo return DM_RESP_COMMAND_FAILED; 5495b9c547cSRui Paulo while (!pps_node) { 5505b9c547cSRui Paulo upos = os_strrchr(uri, '/'); 5515b9c547cSRui Paulo if (!upos) 5525b9c547cSRui Paulo break; 5535b9c547cSRui Paulo upos[0] = '\0'; 5545b9c547cSRui Paulo pps_node = get_node(ctx->xml, pps, uri); 5555b9c547cSRui Paulo wpa_printf(MSG_INFO, "Node %s %s", uri, 5565b9c547cSRui Paulo pps_node ? "exists" : "does not exist"); 5575b9c547cSRui Paulo } 5585b9c547cSRui Paulo 5595b9c547cSRui Paulo wpa_printf(MSG_INFO, "Parent URI: %s", uri); 5605b9c547cSRui Paulo 5615b9c547cSRui Paulo if (!pps_node) { 5625b9c547cSRui Paulo /* Add at root of PPS MO */ 5635b9c547cSRui Paulo pps_node = pps; 5645b9c547cSRui Paulo } 5655b9c547cSRui Paulo 5665b9c547cSRui Paulo uri_len = os_strlen(uri); 5675b9c547cSRui Paulo os_strlcpy(uri, pos + uri_len, os_strlen(pos)); 5685b9c547cSRui Paulo upos = uri; 5695b9c547cSRui Paulo while (*upos == '/') 5705b9c547cSRui Paulo upos++; 5715b9c547cSRui Paulo wpa_printf(MSG_INFO, "Nodes to add: %s", upos); 5725b9c547cSRui Paulo 5735b9c547cSRui Paulo for (;;) { 5745b9c547cSRui Paulo end = os_strchr(upos, '/'); 5755b9c547cSRui Paulo if (!end) 5765b9c547cSRui Paulo break; 5775b9c547cSRui Paulo *end = '\0'; 5785b9c547cSRui Paulo wpa_printf(MSG_INFO, "Adding interim node %s", upos); 5795b9c547cSRui Paulo pps_node = xml_node_create(ctx->xml, pps_node, NULL, upos); 5805b9c547cSRui Paulo if (pps_node == NULL) { 5815b9c547cSRui Paulo os_free(uri); 5825b9c547cSRui Paulo return DM_RESP_COMMAND_FAILED; 5835b9c547cSRui Paulo } 5845b9c547cSRui Paulo upos = end + 1; 5855b9c547cSRui Paulo } 5865b9c547cSRui Paulo 5875b9c547cSRui Paulo wpa_printf(MSG_INFO, "Adding node %s", upos); 5885b9c547cSRui Paulo 5895b9c547cSRui Paulo node = get_node(ctx->xml, add, "Item/Meta/Type"); 5905b9c547cSRui Paulo if (node) { 5915b9c547cSRui Paulo char *type; 5925b9c547cSRui Paulo type = xml_node_get_text(ctx->xml, node); 5935b9c547cSRui Paulo if (type == NULL) { 5945b9c547cSRui Paulo wpa_printf(MSG_ERROR, "Could not find type text"); 5955b9c547cSRui Paulo os_free(uri); 5965b9c547cSRui Paulo return DM_RESP_BAD_REQUEST; 5975b9c547cSRui Paulo } 5985b9c547cSRui Paulo use_tnds = node && 5995b9c547cSRui Paulo os_strstr(type, "application/vnd.syncml.dmtnds+xml"); 6005b9c547cSRui Paulo } 6015b9c547cSRui Paulo 6025b9c547cSRui Paulo node = get_node(ctx->xml, add, "Item/Data"); 6035b9c547cSRui Paulo if (node == NULL) { 6045b9c547cSRui Paulo wpa_printf(MSG_INFO, "No Add/Item/Data found"); 6055b9c547cSRui Paulo os_free(uri); 6065b9c547cSRui Paulo return DM_RESP_BAD_REQUEST; 6075b9c547cSRui Paulo } 6085b9c547cSRui Paulo 6095b9c547cSRui Paulo data = xml_node_get_text(ctx->xml, node); 6105b9c547cSRui Paulo if (data == NULL) { 6115b9c547cSRui Paulo wpa_printf(MSG_INFO, "Could not get Add/Item/Data text"); 6125b9c547cSRui Paulo os_free(uri); 6135b9c547cSRui Paulo return DM_RESP_BAD_REQUEST; 6145b9c547cSRui Paulo } 6155b9c547cSRui Paulo 6165b9c547cSRui Paulo wpa_printf(MSG_DEBUG, "Add/Item/Data: %s", data); 6175b9c547cSRui Paulo 6185b9c547cSRui Paulo if (use_tnds) { 6195b9c547cSRui Paulo tnds = xml_node_from_buf(ctx->xml, data); 6205b9c547cSRui Paulo xml_node_get_text_free(ctx->xml, data); 6215b9c547cSRui Paulo if (tnds == NULL) { 6225b9c547cSRui Paulo wpa_printf(MSG_INFO, 6235b9c547cSRui Paulo "Could not parse Add/Item/Data text"); 6245b9c547cSRui Paulo os_free(uri); 6255b9c547cSRui Paulo return DM_RESP_BAD_REQUEST; 6265b9c547cSRui Paulo } 6275b9c547cSRui Paulo 6285b9c547cSRui Paulo unode = tnds_to_mo(ctx->xml, tnds); 6295b9c547cSRui Paulo xml_node_free(ctx->xml, tnds); 6305b9c547cSRui Paulo if (unode == NULL) { 6315b9c547cSRui Paulo wpa_printf(MSG_INFO, "Could not parse TNDS text"); 6325b9c547cSRui Paulo os_free(uri); 6335b9c547cSRui Paulo return DM_RESP_BAD_REQUEST; 6345b9c547cSRui Paulo } 6355b9c547cSRui Paulo 6365b9c547cSRui Paulo debug_dump_node(ctx, "Parsed TNDS", unode); 6375b9c547cSRui Paulo 6385b9c547cSRui Paulo xml_node_add_child(ctx->xml, pps_node, unode); 6395b9c547cSRui Paulo } else { 6405b9c547cSRui Paulo /* TODO: What to do here? */ 6415b9c547cSRui Paulo os_free(uri); 6425b9c547cSRui Paulo return DM_RESP_BAD_REQUEST; 6435b9c547cSRui Paulo } 6445b9c547cSRui Paulo 6455b9c547cSRui Paulo os_free(uri); 6465b9c547cSRui Paulo 6475b9c547cSRui Paulo if (update_pps_file(ctx, pps_fname, pps) < 0) 6485b9c547cSRui Paulo return DM_RESP_COMMAND_FAILED; 6495b9c547cSRui Paulo 6505b9c547cSRui Paulo ctx->pps_updated = 1; 6515b9c547cSRui Paulo 6525b9c547cSRui Paulo return DM_RESP_OK; 6535b9c547cSRui Paulo } 6545b9c547cSRui Paulo 6555b9c547cSRui Paulo 6565b9c547cSRui Paulo static int oma_dm_add(struct hs20_osu_client *ctx, xml_node_t *add, 6575b9c547cSRui Paulo xml_node_t *pps, const char *pps_fname) 6585b9c547cSRui Paulo { 6595b9c547cSRui Paulo xml_node_t *node; 6605b9c547cSRui Paulo char *locuri; 6615b9c547cSRui Paulo char fname[300]; 6625b9c547cSRui Paulo int ret; 6635b9c547cSRui Paulo 6645b9c547cSRui Paulo node = get_node(ctx->xml, add, "Item/Target/LocURI"); 6655b9c547cSRui Paulo if (node == NULL) { 6665b9c547cSRui Paulo wpa_printf(MSG_INFO, "No Target LocURI node found"); 6675b9c547cSRui Paulo return DM_RESP_BAD_REQUEST; 6685b9c547cSRui Paulo } 6695b9c547cSRui Paulo locuri = xml_node_get_text(ctx->xml, node); 6705b9c547cSRui Paulo if (locuri == NULL) { 6715b9c547cSRui Paulo wpa_printf(MSG_ERROR, "No LocURI node text found"); 6725b9c547cSRui Paulo return DM_RESP_BAD_REQUEST; 6735b9c547cSRui Paulo } 6745b9c547cSRui Paulo wpa_printf(MSG_INFO, "Target LocURI: %s", locuri); 6755b9c547cSRui Paulo if (os_strncasecmp(locuri, "./Wi-Fi/", 8) != 0) { 6765b9c547cSRui Paulo wpa_printf(MSG_INFO, "Unsupported Add Target LocURI"); 6775b9c547cSRui Paulo xml_node_get_text_free(ctx->xml, locuri); 6785b9c547cSRui Paulo return DM_RESP_PERMISSION_DENIED; 6795b9c547cSRui Paulo } 6805b9c547cSRui Paulo 6815b9c547cSRui Paulo node = get_node(ctx->xml, add, "Item/Data"); 6825b9c547cSRui Paulo if (node == NULL) { 6835b9c547cSRui Paulo wpa_printf(MSG_INFO, "No Data node found"); 6845b9c547cSRui Paulo xml_node_get_text_free(ctx->xml, locuri); 6855b9c547cSRui Paulo return DM_RESP_BAD_REQUEST; 6865b9c547cSRui Paulo } 6875b9c547cSRui Paulo 6885b9c547cSRui Paulo if (pps_fname && os_file_exists(pps_fname)) { 6895b9c547cSRui Paulo ret = oma_dm_run_add(ctx, locuri, add, pps, pps_fname); 6905b9c547cSRui Paulo if (ret != DM_RESP_OK) { 6915b9c547cSRui Paulo xml_node_get_text_free(ctx->xml, locuri); 6925b9c547cSRui Paulo return ret; 6935b9c547cSRui Paulo } 6945b9c547cSRui Paulo ret = 0; 6955b9c547cSRui Paulo os_strlcpy(fname, pps_fname, sizeof(fname)); 6965b9c547cSRui Paulo } else 6975b9c547cSRui Paulo ret = hs20_add_pps_mo(ctx, locuri, node, fname, sizeof(fname)); 6985b9c547cSRui Paulo xml_node_get_text_free(ctx->xml, locuri); 6995b9c547cSRui Paulo if (ret < 0) 7005b9c547cSRui Paulo return ret == -2 ? DM_RESP_ALREADY_EXISTS : 7015b9c547cSRui Paulo DM_RESP_COMMAND_FAILED; 7025b9c547cSRui Paulo 7035b9c547cSRui Paulo if (ctx->no_reconnect == 2) { 7045b9c547cSRui Paulo os_snprintf(ctx->pps_fname, sizeof(ctx->pps_fname), "%s", 7055b9c547cSRui Paulo fname); 7065b9c547cSRui Paulo ctx->pps_cred_set = 1; 7075b9c547cSRui Paulo return DM_RESP_OK; 7085b9c547cSRui Paulo } 7095b9c547cSRui Paulo 7105b9c547cSRui Paulo wpa_printf(MSG_INFO, "Updating wpa_supplicant credentials"); 7115b9c547cSRui Paulo cmd_set_pps(ctx, fname); 7125b9c547cSRui Paulo 7135b9c547cSRui Paulo if (ctx->no_reconnect) 7145b9c547cSRui Paulo return DM_RESP_OK; 7155b9c547cSRui Paulo 7165b9c547cSRui Paulo wpa_printf(MSG_INFO, "Requesting reconnection with updated configuration"); 7175b9c547cSRui Paulo if (wpa_command(ctx->ifname, "INTERWORKING_SELECT auto") < 0) 7185b9c547cSRui Paulo wpa_printf(MSG_INFO, "Failed to request wpa_supplicant to reconnect"); 7195b9c547cSRui Paulo 7205b9c547cSRui Paulo return DM_RESP_OK; 7215b9c547cSRui Paulo } 7225b9c547cSRui Paulo 7235b9c547cSRui Paulo 7245b9c547cSRui Paulo static int oma_dm_replace(struct hs20_osu_client *ctx, xml_node_t *replace, 7255b9c547cSRui Paulo xml_node_t *pps, const char *pps_fname) 7265b9c547cSRui Paulo { 7275b9c547cSRui Paulo char *locuri, *pos; 7285b9c547cSRui Paulo size_t fqdn_len; 7295b9c547cSRui Paulo xml_node_t *node, *tnds, *unode, *pps_node, *parent; 7305b9c547cSRui Paulo char *data; 7315b9c547cSRui Paulo int use_tnds = 0; 7325b9c547cSRui Paulo 7335b9c547cSRui Paulo locuri = oma_dm_get_target_locuri(ctx, replace); 7345b9c547cSRui Paulo if (locuri == NULL) 7355b9c547cSRui Paulo return DM_RESP_BAD_REQUEST; 7365b9c547cSRui Paulo 7375b9c547cSRui Paulo wpa_printf(MSG_INFO, "Replace command target LocURI: %s", locuri); 7385b9c547cSRui Paulo if (os_strncasecmp(locuri, "./Wi-Fi/", 8) != 0) { 7395b9c547cSRui Paulo wpa_printf(MSG_INFO, "Do not allow Replace outside ./Wi-Fi"); 7405b9c547cSRui Paulo os_free(locuri); 7415b9c547cSRui Paulo return DM_RESP_PERMISSION_DENIED; 7425b9c547cSRui Paulo } 7435b9c547cSRui Paulo pos = locuri + 8; 7445b9c547cSRui Paulo 7455b9c547cSRui Paulo if (ctx->fqdn == NULL) { 7465b9c547cSRui Paulo os_free(locuri); 7475b9c547cSRui Paulo return DM_RESP_COMMAND_FAILED; 7485b9c547cSRui Paulo } 7495b9c547cSRui Paulo fqdn_len = os_strlen(ctx->fqdn); 7505b9c547cSRui Paulo if (os_strncasecmp(pos, ctx->fqdn, fqdn_len) != 0 || 7515b9c547cSRui Paulo pos[fqdn_len] != '/') { 7525b9c547cSRui Paulo wpa_printf(MSG_INFO, "Do not allow Replace outside ./Wi-Fi/%s", 7535b9c547cSRui Paulo ctx->fqdn); 7545b9c547cSRui Paulo os_free(locuri); 7555b9c547cSRui Paulo return DM_RESP_PERMISSION_DENIED; 7565b9c547cSRui Paulo } 7575b9c547cSRui Paulo pos += fqdn_len + 1; 7585b9c547cSRui Paulo 7595b9c547cSRui Paulo if (os_strncasecmp(pos, "PerProviderSubscription/", 24) != 0) { 7605b9c547cSRui Paulo wpa_printf(MSG_INFO, 7615b9c547cSRui Paulo "Do not allow Replace outside ./Wi-Fi/%s/PerProviderSubscription", 7625b9c547cSRui Paulo ctx->fqdn); 7635b9c547cSRui Paulo os_free(locuri); 7645b9c547cSRui Paulo return DM_RESP_PERMISSION_DENIED; 7655b9c547cSRui Paulo } 7665b9c547cSRui Paulo pos += 24; 7675b9c547cSRui Paulo 7685b9c547cSRui Paulo wpa_printf(MSG_INFO, "Replace command for PPS node %s", pos); 7695b9c547cSRui Paulo 7705b9c547cSRui Paulo pps_node = get_node(ctx->xml, pps, pos); 7715b9c547cSRui Paulo if (pps_node == NULL) { 7725b9c547cSRui Paulo wpa_printf(MSG_INFO, "Specified PPS node not found"); 7735b9c547cSRui Paulo os_free(locuri); 7745b9c547cSRui Paulo return DM_RESP_NOT_FOUND; 7755b9c547cSRui Paulo } 7765b9c547cSRui Paulo 7775b9c547cSRui Paulo node = get_node(ctx->xml, replace, "Item/Meta/Type"); 7785b9c547cSRui Paulo if (node) { 7795b9c547cSRui Paulo char *type; 7805b9c547cSRui Paulo type = xml_node_get_text(ctx->xml, node); 7815b9c547cSRui Paulo if (type == NULL) { 7825b9c547cSRui Paulo wpa_printf(MSG_INFO, "Could not find type text"); 7835b9c547cSRui Paulo os_free(locuri); 7845b9c547cSRui Paulo return DM_RESP_BAD_REQUEST; 7855b9c547cSRui Paulo } 7865b9c547cSRui Paulo use_tnds = node && 7875b9c547cSRui Paulo os_strstr(type, "application/vnd.syncml.dmtnds+xml"); 7885b9c547cSRui Paulo } 7895b9c547cSRui Paulo 7905b9c547cSRui Paulo node = get_node(ctx->xml, replace, "Item/Data"); 7915b9c547cSRui Paulo if (node == NULL) { 7925b9c547cSRui Paulo wpa_printf(MSG_INFO, "No Replace/Item/Data found"); 7935b9c547cSRui Paulo os_free(locuri); 7945b9c547cSRui Paulo return DM_RESP_BAD_REQUEST; 7955b9c547cSRui Paulo } 7965b9c547cSRui Paulo 7975b9c547cSRui Paulo data = xml_node_get_text(ctx->xml, node); 7985b9c547cSRui Paulo if (data == NULL) { 7995b9c547cSRui Paulo wpa_printf(MSG_INFO, "Could not get Replace/Item/Data text"); 8005b9c547cSRui Paulo os_free(locuri); 8015b9c547cSRui Paulo return DM_RESP_BAD_REQUEST; 8025b9c547cSRui Paulo } 8035b9c547cSRui Paulo 8045b9c547cSRui Paulo wpa_printf(MSG_DEBUG, "Replace/Item/Data: %s", data); 8055b9c547cSRui Paulo 8065b9c547cSRui Paulo if (use_tnds) { 8075b9c547cSRui Paulo tnds = xml_node_from_buf(ctx->xml, data); 8085b9c547cSRui Paulo xml_node_get_text_free(ctx->xml, data); 8095b9c547cSRui Paulo if (tnds == NULL) { 8105b9c547cSRui Paulo wpa_printf(MSG_INFO, 8115b9c547cSRui Paulo "Could not parse Replace/Item/Data text"); 8125b9c547cSRui Paulo os_free(locuri); 8135b9c547cSRui Paulo return DM_RESP_BAD_REQUEST; 8145b9c547cSRui Paulo } 8155b9c547cSRui Paulo 8165b9c547cSRui Paulo unode = tnds_to_mo(ctx->xml, tnds); 8175b9c547cSRui Paulo xml_node_free(ctx->xml, tnds); 8185b9c547cSRui Paulo if (unode == NULL) { 8195b9c547cSRui Paulo wpa_printf(MSG_INFO, "Could not parse TNDS text"); 8205b9c547cSRui Paulo os_free(locuri); 8215b9c547cSRui Paulo return DM_RESP_BAD_REQUEST; 8225b9c547cSRui Paulo } 8235b9c547cSRui Paulo 8245b9c547cSRui Paulo debug_dump_node(ctx, "Parsed TNDS", unode); 8255b9c547cSRui Paulo 8265b9c547cSRui Paulo parent = xml_node_get_parent(ctx->xml, pps_node); 8275b9c547cSRui Paulo xml_node_detach(ctx->xml, pps_node); 8285b9c547cSRui Paulo xml_node_add_child(ctx->xml, parent, unode); 8295b9c547cSRui Paulo } else { 8305b9c547cSRui Paulo xml_node_set_text(ctx->xml, pps_node, data); 8315b9c547cSRui Paulo xml_node_get_text_free(ctx->xml, data); 8325b9c547cSRui Paulo } 8335b9c547cSRui Paulo 8345b9c547cSRui Paulo os_free(locuri); 8355b9c547cSRui Paulo 8365b9c547cSRui Paulo if (update_pps_file(ctx, pps_fname, pps) < 0) 8375b9c547cSRui Paulo return DM_RESP_COMMAND_FAILED; 8385b9c547cSRui Paulo 8395b9c547cSRui Paulo ctx->pps_updated = 1; 8405b9c547cSRui Paulo 8415b9c547cSRui Paulo return DM_RESP_OK; 8425b9c547cSRui Paulo } 8435b9c547cSRui Paulo 8445b9c547cSRui Paulo 8455b9c547cSRui Paulo static int oma_dm_get(struct hs20_osu_client *ctx, xml_node_t *get, 8465b9c547cSRui Paulo xml_node_t *pps, const char *pps_fname, char **value) 8475b9c547cSRui Paulo { 8485b9c547cSRui Paulo char *locuri, *pos; 8495b9c547cSRui Paulo size_t fqdn_len; 8505b9c547cSRui Paulo xml_node_t *pps_node; 8515b9c547cSRui Paulo const char *name; 8525b9c547cSRui Paulo 8535b9c547cSRui Paulo *value = NULL; 8545b9c547cSRui Paulo 8555b9c547cSRui Paulo locuri = oma_dm_get_target_locuri(ctx, get); 8565b9c547cSRui Paulo if (locuri == NULL) 8575b9c547cSRui Paulo return DM_RESP_BAD_REQUEST; 8585b9c547cSRui Paulo 8595b9c547cSRui Paulo wpa_printf(MSG_INFO, "Get command target LocURI: %s", locuri); 8605b9c547cSRui Paulo if (os_strncasecmp(locuri, "./Wi-Fi/", 8) != 0) { 8615b9c547cSRui Paulo wpa_printf(MSG_INFO, "Do not allow Get outside ./Wi-Fi"); 8625b9c547cSRui Paulo os_free(locuri); 8635b9c547cSRui Paulo return DM_RESP_PERMISSION_DENIED; 8645b9c547cSRui Paulo } 8655b9c547cSRui Paulo pos = locuri + 8; 8665b9c547cSRui Paulo 8675b9c547cSRui Paulo if (ctx->fqdn == NULL) 8685b9c547cSRui Paulo return DM_RESP_COMMAND_FAILED; 8695b9c547cSRui Paulo fqdn_len = os_strlen(ctx->fqdn); 8705b9c547cSRui Paulo if (os_strncasecmp(pos, ctx->fqdn, fqdn_len) != 0 || 8715b9c547cSRui Paulo pos[fqdn_len] != '/') { 8725b9c547cSRui Paulo wpa_printf(MSG_INFO, "Do not allow Get outside ./Wi-Fi/%s", 8735b9c547cSRui Paulo ctx->fqdn); 8745b9c547cSRui Paulo os_free(locuri); 8755b9c547cSRui Paulo return DM_RESP_PERMISSION_DENIED; 8765b9c547cSRui Paulo } 8775b9c547cSRui Paulo pos += fqdn_len + 1; 8785b9c547cSRui Paulo 8795b9c547cSRui Paulo if (os_strncasecmp(pos, "PerProviderSubscription/", 24) != 0) { 8805b9c547cSRui Paulo wpa_printf(MSG_INFO, 8815b9c547cSRui Paulo "Do not allow Get outside ./Wi-Fi/%s/PerProviderSubscription", 8825b9c547cSRui Paulo ctx->fqdn); 8835b9c547cSRui Paulo os_free(locuri); 8845b9c547cSRui Paulo return DM_RESP_PERMISSION_DENIED; 8855b9c547cSRui Paulo } 8865b9c547cSRui Paulo pos += 24; 8875b9c547cSRui Paulo 8885b9c547cSRui Paulo wpa_printf(MSG_INFO, "Get command for PPS node %s", pos); 8895b9c547cSRui Paulo 8905b9c547cSRui Paulo pps_node = get_node(ctx->xml, pps, pos); 8915b9c547cSRui Paulo if (pps_node == NULL) { 8925b9c547cSRui Paulo wpa_printf(MSG_INFO, "Specified PPS node not found"); 8935b9c547cSRui Paulo os_free(locuri); 8945b9c547cSRui Paulo return DM_RESP_NOT_FOUND; 8955b9c547cSRui Paulo } 8965b9c547cSRui Paulo 8975b9c547cSRui Paulo name = xml_node_get_localname(ctx->xml, pps_node); 8985b9c547cSRui Paulo wpa_printf(MSG_INFO, "Get command returned node with name '%s'", name); 8995b9c547cSRui Paulo if (os_strcasecmp(name, "Password") == 0) { 9005b9c547cSRui Paulo wpa_printf(MSG_INFO, "Do not allow Get for Password node"); 9015b9c547cSRui Paulo os_free(locuri); 9025b9c547cSRui Paulo return DM_RESP_PERMISSION_DENIED; 9035b9c547cSRui Paulo } 9045b9c547cSRui Paulo 9055b9c547cSRui Paulo /* 9065b9c547cSRui Paulo * TODO: No support for DMTNDS, so if interior node, reply with a 9075b9c547cSRui Paulo * list of children node names in Results element. The child list type is 9085b9c547cSRui Paulo * defined in [DMTND]. 9095b9c547cSRui Paulo */ 9105b9c547cSRui Paulo 9115b9c547cSRui Paulo *value = xml_node_get_text(ctx->xml, pps_node); 9125b9c547cSRui Paulo if (*value == NULL) 9135b9c547cSRui Paulo return DM_RESP_COMMAND_FAILED; 9145b9c547cSRui Paulo 9155b9c547cSRui Paulo return DM_RESP_OK; 9165b9c547cSRui Paulo } 9175b9c547cSRui Paulo 9185b9c547cSRui Paulo 9195b9c547cSRui Paulo static int oma_dm_get_cmdid(struct hs20_osu_client *ctx, xml_node_t *node) 9205b9c547cSRui Paulo { 9215b9c547cSRui Paulo xml_node_t *cnode; 9225b9c547cSRui Paulo char *str; 9235b9c547cSRui Paulo int ret; 9245b9c547cSRui Paulo 9255b9c547cSRui Paulo cnode = get_node(ctx->xml, node, "CmdID"); 9265b9c547cSRui Paulo if (cnode == NULL) 9275b9c547cSRui Paulo return 0; 9285b9c547cSRui Paulo 9295b9c547cSRui Paulo str = xml_node_get_text(ctx->xml, cnode); 9305b9c547cSRui Paulo if (str == NULL) 9315b9c547cSRui Paulo return 0; 9325b9c547cSRui Paulo ret = atoi(str); 9335b9c547cSRui Paulo xml_node_get_text_free(ctx->xml, str); 9345b9c547cSRui Paulo return ret; 9355b9c547cSRui Paulo } 9365b9c547cSRui Paulo 9375b9c547cSRui Paulo 9385b9c547cSRui Paulo static xml_node_t * oma_dm_send_recv(struct hs20_osu_client *ctx, 9395b9c547cSRui Paulo const char *url, xml_node_t *syncml, 9405b9c547cSRui Paulo const char *ext_hdr, 9415b9c547cSRui Paulo const char *username, const char *password, 9425b9c547cSRui Paulo const char *client_cert, 9435b9c547cSRui Paulo const char *client_key) 9445b9c547cSRui Paulo { 9455b9c547cSRui Paulo xml_node_t *resp; 9465b9c547cSRui Paulo char *str, *res; 9475b9c547cSRui Paulo char *resp_uri = NULL; 9485b9c547cSRui Paulo 9495b9c547cSRui Paulo str = xml_node_to_str(ctx->xml, syncml); 9505b9c547cSRui Paulo xml_node_free(ctx->xml, syncml); 9515b9c547cSRui Paulo if (str == NULL) 9525b9c547cSRui Paulo return NULL; 9535b9c547cSRui Paulo 9545b9c547cSRui Paulo wpa_printf(MSG_INFO, "Send OMA DM Package"); 9555b9c547cSRui Paulo write_summary(ctx, "Send OMA DM Package"); 9565b9c547cSRui Paulo os_free(ctx->server_url); 9575b9c547cSRui Paulo ctx->server_url = os_strdup(url); 9585b9c547cSRui Paulo res = http_post(ctx->http, url, str, "application/vnd.syncml.dm+xml", 9595b9c547cSRui Paulo ext_hdr, ctx->ca_fname, username, password, 9605b9c547cSRui Paulo client_cert, client_key, NULL); 9615b9c547cSRui Paulo os_free(str); 9625b9c547cSRui Paulo os_free(resp_uri); 9635b9c547cSRui Paulo resp_uri = NULL; 9645b9c547cSRui Paulo 9655b9c547cSRui Paulo if (res == NULL) { 9665b9c547cSRui Paulo const char *err = http_get_err(ctx->http); 9675b9c547cSRui Paulo if (err) { 9685b9c547cSRui Paulo wpa_printf(MSG_INFO, "HTTP error: %s", err); 9695b9c547cSRui Paulo write_result(ctx, "HTTP error: %s", err); 9705b9c547cSRui Paulo } else { 9715b9c547cSRui Paulo write_summary(ctx, "Failed to send OMA DM Package"); 9725b9c547cSRui Paulo } 9735b9c547cSRui Paulo return NULL; 9745b9c547cSRui Paulo } 9755b9c547cSRui Paulo wpa_printf(MSG_DEBUG, "Server response: %s", res); 9765b9c547cSRui Paulo 9775b9c547cSRui Paulo wpa_printf(MSG_INFO, "Process OMA DM Package"); 9785b9c547cSRui Paulo write_summary(ctx, "Process received OMA DM Package"); 9795b9c547cSRui Paulo resp = xml_node_from_buf(ctx->xml, res); 9805b9c547cSRui Paulo os_free(res); 9815b9c547cSRui Paulo if (resp == NULL) { 9825b9c547cSRui Paulo wpa_printf(MSG_INFO, "Failed to parse OMA DM response"); 9835b9c547cSRui Paulo return NULL; 9845b9c547cSRui Paulo } 9855b9c547cSRui Paulo 9865b9c547cSRui Paulo debug_dump_node(ctx, "OMA DM Package", resp); 9875b9c547cSRui Paulo 9885b9c547cSRui Paulo return resp; 9895b9c547cSRui Paulo } 9905b9c547cSRui Paulo 9915b9c547cSRui Paulo 9925b9c547cSRui Paulo static xml_node_t * oma_dm_process(struct hs20_osu_client *ctx, const char *url, 9935b9c547cSRui Paulo xml_node_t *resp, int msgid, 9945b9c547cSRui Paulo char **ret_resp_uri, 9955b9c547cSRui Paulo xml_node_t *pps, const char *pps_fname) 9965b9c547cSRui Paulo { 9975b9c547cSRui Paulo xml_node_t *syncml, *syncbody, *hdr, *body, *child; 9985b9c547cSRui Paulo const char *name; 9995b9c547cSRui Paulo char *resp_uri = NULL; 10005b9c547cSRui Paulo int server_msgid = 0; 10015b9c547cSRui Paulo int cmdid = 0; 10025b9c547cSRui Paulo int server_cmdid; 10035b9c547cSRui Paulo int resp_needed = 0; 10045b9c547cSRui Paulo char *tmp; 10055b9c547cSRui Paulo int final = 0; 10065b9c547cSRui Paulo char *locuri; 10075b9c547cSRui Paulo 10085b9c547cSRui Paulo *ret_resp_uri = NULL; 10095b9c547cSRui Paulo 10105b9c547cSRui Paulo name = xml_node_get_localname(ctx->xml, resp); 10115b9c547cSRui Paulo if (name == NULL || os_strcasecmp(name, "SyncML") != 0) { 10125b9c547cSRui Paulo wpa_printf(MSG_INFO, "SyncML node not found"); 10135b9c547cSRui Paulo return NULL; 10145b9c547cSRui Paulo } 10155b9c547cSRui Paulo 10165b9c547cSRui Paulo hdr = get_node(ctx->xml, resp, "SyncHdr"); 10175b9c547cSRui Paulo body = get_node(ctx->xml, resp, "SyncBody"); 10185b9c547cSRui Paulo if (hdr == NULL || body == NULL) { 10195b9c547cSRui Paulo wpa_printf(MSG_INFO, "Could not find SyncHdr or SyncBody"); 10205b9c547cSRui Paulo return NULL; 10215b9c547cSRui Paulo } 10225b9c547cSRui Paulo 10235b9c547cSRui Paulo xml_node_for_each_child(ctx->xml, child, hdr) { 10245b9c547cSRui Paulo xml_node_for_each_check(ctx->xml, child); 10255b9c547cSRui Paulo name = xml_node_get_localname(ctx->xml, child); 10265b9c547cSRui Paulo wpa_printf(MSG_INFO, "SyncHdr %s", name); 10275b9c547cSRui Paulo if (os_strcasecmp(name, "RespURI") == 0) { 10285b9c547cSRui Paulo tmp = xml_node_get_text(ctx->xml, child); 10295b9c547cSRui Paulo if (tmp) 10305b9c547cSRui Paulo resp_uri = os_strdup(tmp); 10315b9c547cSRui Paulo xml_node_get_text_free(ctx->xml, tmp); 10325b9c547cSRui Paulo } else if (os_strcasecmp(name, "MsgID") == 0) { 10335b9c547cSRui Paulo tmp = xml_node_get_text(ctx->xml, child); 10345b9c547cSRui Paulo if (tmp) 10355b9c547cSRui Paulo server_msgid = atoi(tmp); 10365b9c547cSRui Paulo xml_node_get_text_free(ctx->xml, tmp); 10375b9c547cSRui Paulo } 10385b9c547cSRui Paulo } 10395b9c547cSRui Paulo 10405b9c547cSRui Paulo wpa_printf(MSG_INFO, "Server MsgID: %d", server_msgid); 10415b9c547cSRui Paulo if (resp_uri) 10425b9c547cSRui Paulo wpa_printf(MSG_INFO, "RespURI: %s", resp_uri); 10435b9c547cSRui Paulo 10445b9c547cSRui Paulo syncml = oma_dm_build_hdr(ctx, resp_uri ? resp_uri : url, msgid); 10455b9c547cSRui Paulo if (syncml == NULL) { 10465b9c547cSRui Paulo os_free(resp_uri); 10475b9c547cSRui Paulo return NULL; 10485b9c547cSRui Paulo } 10495b9c547cSRui Paulo 10505b9c547cSRui Paulo syncbody = xml_node_create(ctx->xml, syncml, NULL, "SyncBody"); 10515b9c547cSRui Paulo cmdid++; 10525b9c547cSRui Paulo add_status(ctx, syncbody, server_msgid, 0, cmdid, "SyncHdr", 10535b9c547cSRui Paulo DM_RESP_AUTH_ACCEPTED, NULL); 10545b9c547cSRui Paulo 10555b9c547cSRui Paulo xml_node_for_each_child(ctx->xml, child, body) { 10565b9c547cSRui Paulo xml_node_for_each_check(ctx->xml, child); 10575b9c547cSRui Paulo server_cmdid = oma_dm_get_cmdid(ctx, child); 10585b9c547cSRui Paulo name = xml_node_get_localname(ctx->xml, child); 10595b9c547cSRui Paulo wpa_printf(MSG_INFO, "SyncBody CmdID=%d - %s", 10605b9c547cSRui Paulo server_cmdid, name); 10615b9c547cSRui Paulo if (os_strcasecmp(name, "Exec") == 0) { 10625b9c547cSRui Paulo int res = oma_dm_exec(ctx, child); 10635b9c547cSRui Paulo cmdid++; 10645b9c547cSRui Paulo locuri = oma_dm_get_target_locuri(ctx, child); 10655b9c547cSRui Paulo if (locuri == NULL) 10665b9c547cSRui Paulo res = DM_RESP_BAD_REQUEST; 10675b9c547cSRui Paulo add_status(ctx, syncbody, server_msgid, server_cmdid, 10685b9c547cSRui Paulo cmdid, name, res, locuri); 10695b9c547cSRui Paulo os_free(locuri); 10705b9c547cSRui Paulo resp_needed = 1; 10715b9c547cSRui Paulo } else if (os_strcasecmp(name, "Add") == 0) { 10725b9c547cSRui Paulo int res = oma_dm_add(ctx, child, pps, pps_fname); 10735b9c547cSRui Paulo cmdid++; 10745b9c547cSRui Paulo locuri = oma_dm_get_target_locuri(ctx, child); 10755b9c547cSRui Paulo if (locuri == NULL) 10765b9c547cSRui Paulo res = DM_RESP_BAD_REQUEST; 10775b9c547cSRui Paulo add_status(ctx, syncbody, server_msgid, server_cmdid, 10785b9c547cSRui Paulo cmdid, name, res, locuri); 10795b9c547cSRui Paulo os_free(locuri); 10805b9c547cSRui Paulo resp_needed = 1; 10815b9c547cSRui Paulo } else if (os_strcasecmp(name, "Replace") == 0) { 10825b9c547cSRui Paulo int res; 10835b9c547cSRui Paulo res = oma_dm_replace(ctx, child, pps, pps_fname); 10845b9c547cSRui Paulo cmdid++; 10855b9c547cSRui Paulo locuri = oma_dm_get_target_locuri(ctx, child); 10865b9c547cSRui Paulo if (locuri == NULL) 10875b9c547cSRui Paulo res = DM_RESP_BAD_REQUEST; 10885b9c547cSRui Paulo add_status(ctx, syncbody, server_msgid, server_cmdid, 10895b9c547cSRui Paulo cmdid, name, res, locuri); 10905b9c547cSRui Paulo os_free(locuri); 10915b9c547cSRui Paulo resp_needed = 1; 10925b9c547cSRui Paulo } else if (os_strcasecmp(name, "Status") == 0) { 10935b9c547cSRui Paulo /* TODO: Verify success */ 10945b9c547cSRui Paulo } else if (os_strcasecmp(name, "Get") == 0) { 10955b9c547cSRui Paulo int res; 10965b9c547cSRui Paulo char *value; 10975b9c547cSRui Paulo res = oma_dm_get(ctx, child, pps, pps_fname, &value); 10985b9c547cSRui Paulo cmdid++; 10995b9c547cSRui Paulo locuri = oma_dm_get_target_locuri(ctx, child); 11005b9c547cSRui Paulo if (locuri == NULL) 11015b9c547cSRui Paulo res = DM_RESP_BAD_REQUEST; 11025b9c547cSRui Paulo add_status(ctx, syncbody, server_msgid, server_cmdid, 11035b9c547cSRui Paulo cmdid, name, res, locuri); 11045b9c547cSRui Paulo if (res == DM_RESP_OK && value) { 11055b9c547cSRui Paulo cmdid++; 11065b9c547cSRui Paulo add_results(ctx, syncbody, server_msgid, 11075b9c547cSRui Paulo server_cmdid, cmdid, locuri, value); 11085b9c547cSRui Paulo } 11095b9c547cSRui Paulo os_free(locuri); 11105b9c547cSRui Paulo xml_node_get_text_free(ctx->xml, value); 11115b9c547cSRui Paulo resp_needed = 1; 11125b9c547cSRui Paulo #if 0 /* TODO: MUST support */ 11135b9c547cSRui Paulo } else if (os_strcasecmp(name, "Delete") == 0) { 11145b9c547cSRui Paulo #endif 11155b9c547cSRui Paulo #if 0 /* TODO: MUST support */ 11165b9c547cSRui Paulo } else if (os_strcasecmp(name, "Sequence") == 0) { 11175b9c547cSRui Paulo #endif 11185b9c547cSRui Paulo } else if (os_strcasecmp(name, "Final") == 0) { 11195b9c547cSRui Paulo final = 1; 11205b9c547cSRui Paulo break; 11215b9c547cSRui Paulo } else { 11225b9c547cSRui Paulo locuri = oma_dm_get_target_locuri(ctx, child); 11235b9c547cSRui Paulo add_status(ctx, syncbody, server_msgid, server_cmdid, 11245b9c547cSRui Paulo cmdid, name, DM_RESP_COMMAND_NOT_IMPLEMENTED, 11255b9c547cSRui Paulo locuri); 11265b9c547cSRui Paulo os_free(locuri); 11275b9c547cSRui Paulo resp_needed = 1; 11285b9c547cSRui Paulo } 11295b9c547cSRui Paulo } 11305b9c547cSRui Paulo 11315b9c547cSRui Paulo if (!final) { 11325b9c547cSRui Paulo wpa_printf(MSG_INFO, "Final node not found"); 11335b9c547cSRui Paulo xml_node_free(ctx->xml, syncml); 11345b9c547cSRui Paulo os_free(resp_uri); 11355b9c547cSRui Paulo return NULL; 11365b9c547cSRui Paulo } 11375b9c547cSRui Paulo 11385b9c547cSRui Paulo if (!resp_needed) { 11395b9c547cSRui Paulo wpa_printf(MSG_INFO, "Exchange completed - no response needed"); 11405b9c547cSRui Paulo xml_node_free(ctx->xml, syncml); 11415b9c547cSRui Paulo os_free(resp_uri); 11425b9c547cSRui Paulo return NULL; 11435b9c547cSRui Paulo } 11445b9c547cSRui Paulo 11455b9c547cSRui Paulo xml_node_create(ctx->xml, syncbody, NULL, "Final"); 11465b9c547cSRui Paulo 11475b9c547cSRui Paulo debug_dump_node(ctx, "OMA-DM Package 3", syncml); 11485b9c547cSRui Paulo 11495b9c547cSRui Paulo *ret_resp_uri = resp_uri; 11505b9c547cSRui Paulo return syncml; 11515b9c547cSRui Paulo } 11525b9c547cSRui Paulo 11535b9c547cSRui Paulo 11545b9c547cSRui Paulo int cmd_oma_dm_prov(struct hs20_osu_client *ctx, const char *url) 11555b9c547cSRui Paulo { 11565b9c547cSRui Paulo xml_node_t *syncml, *resp; 11575b9c547cSRui Paulo char *resp_uri = NULL; 11585b9c547cSRui Paulo int msgid = 0; 11595b9c547cSRui Paulo 11605b9c547cSRui Paulo if (url == NULL) { 11615b9c547cSRui Paulo wpa_printf(MSG_INFO, "Invalid prov command (missing URL)"); 11625b9c547cSRui Paulo return -1; 11635b9c547cSRui Paulo } 11645b9c547cSRui Paulo 11655b9c547cSRui Paulo wpa_printf(MSG_INFO, "OMA-DM credential provisioning requested"); 11665b9c547cSRui Paulo write_summary(ctx, "OMA-DM credential provisioning"); 11675b9c547cSRui Paulo 11685b9c547cSRui Paulo msgid++; 11695b9c547cSRui Paulo syncml = build_oma_dm_1_sub_reg(ctx, url, msgid); 11705b9c547cSRui Paulo if (syncml == NULL) 11715b9c547cSRui Paulo return -1; 11725b9c547cSRui Paulo 11735b9c547cSRui Paulo while (syncml) { 11745b9c547cSRui Paulo resp = oma_dm_send_recv(ctx, resp_uri ? resp_uri : url, 11755b9c547cSRui Paulo syncml, NULL, NULL, NULL, NULL, NULL); 11765b9c547cSRui Paulo if (resp == NULL) 11775b9c547cSRui Paulo return -1; 11785b9c547cSRui Paulo 11795b9c547cSRui Paulo msgid++; 11805b9c547cSRui Paulo syncml = oma_dm_process(ctx, url, resp, msgid, &resp_uri, 11815b9c547cSRui Paulo NULL, NULL); 11825b9c547cSRui Paulo xml_node_free(ctx->xml, resp); 11835b9c547cSRui Paulo } 11845b9c547cSRui Paulo 11855b9c547cSRui Paulo os_free(resp_uri); 11865b9c547cSRui Paulo 11875b9c547cSRui Paulo return ctx->pps_cred_set ? 0 : -1; 11885b9c547cSRui Paulo } 11895b9c547cSRui Paulo 11905b9c547cSRui Paulo 11915b9c547cSRui Paulo int cmd_oma_dm_sim_prov(struct hs20_osu_client *ctx, const char *url) 11925b9c547cSRui Paulo { 11935b9c547cSRui Paulo xml_node_t *syncml, *resp; 11945b9c547cSRui Paulo char *resp_uri = NULL; 11955b9c547cSRui Paulo int msgid = 0; 11965b9c547cSRui Paulo 11975b9c547cSRui Paulo if (url == NULL) { 11985b9c547cSRui Paulo wpa_printf(MSG_INFO, "Invalid prov command (missing URL)"); 11995b9c547cSRui Paulo return -1; 12005b9c547cSRui Paulo } 12015b9c547cSRui Paulo 12025b9c547cSRui Paulo wpa_printf(MSG_INFO, "OMA-DM SIM provisioning requested"); 12035b9c547cSRui Paulo ctx->no_reconnect = 2; 12045b9c547cSRui Paulo 12055b9c547cSRui Paulo wpa_printf(MSG_INFO, "Wait for IP address before starting SIM provisioning"); 12065b9c547cSRui Paulo write_summary(ctx, "Wait for IP address before starting SIM provisioning"); 12075b9c547cSRui Paulo 12085b9c547cSRui Paulo if (wait_ip_addr(ctx->ifname, 15) < 0) { 12095b9c547cSRui Paulo wpa_printf(MSG_INFO, "Could not get IP address for WLAN - try connection anyway"); 12105b9c547cSRui Paulo } 12115b9c547cSRui Paulo write_summary(ctx, "OMA-DM SIM provisioning"); 12125b9c547cSRui Paulo 12135b9c547cSRui Paulo msgid++; 12145b9c547cSRui Paulo syncml = build_oma_dm_1_sub_prov(ctx, url, msgid); 12155b9c547cSRui Paulo if (syncml == NULL) 12165b9c547cSRui Paulo return -1; 12175b9c547cSRui Paulo 12185b9c547cSRui Paulo while (syncml) { 12195b9c547cSRui Paulo resp = oma_dm_send_recv(ctx, resp_uri ? resp_uri : url, 12205b9c547cSRui Paulo syncml, NULL, NULL, NULL, NULL, NULL); 12215b9c547cSRui Paulo if (resp == NULL) 12225b9c547cSRui Paulo return -1; 12235b9c547cSRui Paulo 12245b9c547cSRui Paulo msgid++; 12255b9c547cSRui Paulo syncml = oma_dm_process(ctx, url, resp, msgid, &resp_uri, 12265b9c547cSRui Paulo NULL, NULL); 12275b9c547cSRui Paulo xml_node_free(ctx->xml, resp); 12285b9c547cSRui Paulo } 12295b9c547cSRui Paulo 12305b9c547cSRui Paulo os_free(resp_uri); 12315b9c547cSRui Paulo 12325b9c547cSRui Paulo if (ctx->pps_cred_set) { 12335b9c547cSRui Paulo wpa_printf(MSG_INFO, "Updating wpa_supplicant credentials"); 12345b9c547cSRui Paulo cmd_set_pps(ctx, ctx->pps_fname); 12355b9c547cSRui Paulo 12365b9c547cSRui Paulo wpa_printf(MSG_INFO, "Requesting reconnection with updated configuration"); 12375b9c547cSRui Paulo write_summary(ctx, "Requesting reconnection with updated configuration"); 12385b9c547cSRui Paulo if (wpa_command(ctx->ifname, "INTERWORKING_SELECT auto") < 0) { 12395b9c547cSRui Paulo wpa_printf(MSG_INFO, "Failed to request wpa_supplicant to reconnect"); 12405b9c547cSRui Paulo write_summary(ctx, "Failed to request wpa_supplicant to reconnect"); 12415b9c547cSRui Paulo return -1; 12425b9c547cSRui Paulo } 12435b9c547cSRui Paulo } 12445b9c547cSRui Paulo 12455b9c547cSRui Paulo return ctx->pps_cred_set ? 0 : -1; 12465b9c547cSRui Paulo } 12475b9c547cSRui Paulo 12485b9c547cSRui Paulo 12495b9c547cSRui Paulo void oma_dm_pol_upd(struct hs20_osu_client *ctx, const char *address, 12505b9c547cSRui Paulo const char *pps_fname, 12515b9c547cSRui Paulo const char *client_cert, const char *client_key, 12525b9c547cSRui Paulo const char *cred_username, const char *cred_password, 12535b9c547cSRui Paulo xml_node_t *pps) 12545b9c547cSRui Paulo { 12555b9c547cSRui Paulo xml_node_t *syncml, *resp; 12565b9c547cSRui Paulo char *resp_uri = NULL; 12575b9c547cSRui Paulo int msgid = 0; 12585b9c547cSRui Paulo 12595b9c547cSRui Paulo wpa_printf(MSG_INFO, "OMA-DM policy update"); 12605b9c547cSRui Paulo write_summary(ctx, "OMA-DM policy update"); 12615b9c547cSRui Paulo 12625b9c547cSRui Paulo msgid++; 12635b9c547cSRui Paulo syncml = build_oma_dm_1_pol_upd(ctx, address, msgid); 12645b9c547cSRui Paulo if (syncml == NULL) 12655b9c547cSRui Paulo return; 12665b9c547cSRui Paulo 12675b9c547cSRui Paulo while (syncml) { 12685b9c547cSRui Paulo resp = oma_dm_send_recv(ctx, resp_uri ? resp_uri : address, 12695b9c547cSRui Paulo syncml, NULL, cred_username, 12705b9c547cSRui Paulo cred_password, client_cert, client_key); 12715b9c547cSRui Paulo if (resp == NULL) 12725b9c547cSRui Paulo return; 12735b9c547cSRui Paulo 12745b9c547cSRui Paulo msgid++; 12755b9c547cSRui Paulo syncml = oma_dm_process(ctx, address, resp, msgid, &resp_uri, 12765b9c547cSRui Paulo pps, pps_fname); 12775b9c547cSRui Paulo xml_node_free(ctx->xml, resp); 12785b9c547cSRui Paulo } 12795b9c547cSRui Paulo 12805b9c547cSRui Paulo os_free(resp_uri); 12815b9c547cSRui Paulo 12825b9c547cSRui Paulo if (ctx->pps_updated) { 12835b9c547cSRui Paulo wpa_printf(MSG_INFO, "Update wpa_supplicant credential based on updated PPS MO"); 12845b9c547cSRui Paulo write_summary(ctx, "Update wpa_supplicant credential based on updated PPS MO and request connection"); 12855b9c547cSRui Paulo cmd_set_pps(ctx, pps_fname); 12865b9c547cSRui Paulo if (wpa_command(ctx->ifname, "INTERWORKING_SELECT auto") < 0) { 12875b9c547cSRui Paulo wpa_printf(MSG_INFO, 12885b9c547cSRui Paulo "Failed to request wpa_supplicant to reconnect"); 12895b9c547cSRui Paulo write_summary(ctx, 12905b9c547cSRui Paulo "Failed to request wpa_supplicant to reconnect"); 12915b9c547cSRui Paulo } 12925b9c547cSRui Paulo } 12935b9c547cSRui Paulo } 12945b9c547cSRui Paulo 12955b9c547cSRui Paulo 12965b9c547cSRui Paulo void oma_dm_sub_rem(struct hs20_osu_client *ctx, const char *address, 12975b9c547cSRui Paulo const char *pps_fname, 12985b9c547cSRui Paulo const char *client_cert, const char *client_key, 12995b9c547cSRui Paulo const char *cred_username, const char *cred_password, 13005b9c547cSRui Paulo xml_node_t *pps) 13015b9c547cSRui Paulo { 13025b9c547cSRui Paulo xml_node_t *syncml, *resp; 13035b9c547cSRui Paulo char *resp_uri = NULL; 13045b9c547cSRui Paulo int msgid = 0; 13055b9c547cSRui Paulo 13065b9c547cSRui Paulo wpa_printf(MSG_INFO, "OMA-DM subscription remediation"); 13075b9c547cSRui Paulo write_summary(ctx, "OMA-DM subscription remediation"); 13085b9c547cSRui Paulo 13095b9c547cSRui Paulo msgid++; 13105b9c547cSRui Paulo syncml = build_oma_dm_1_sub_rem(ctx, address, msgid); 13115b9c547cSRui Paulo if (syncml == NULL) 13125b9c547cSRui Paulo return; 13135b9c547cSRui Paulo 13145b9c547cSRui Paulo while (syncml) { 13155b9c547cSRui Paulo resp = oma_dm_send_recv(ctx, resp_uri ? resp_uri : address, 13165b9c547cSRui Paulo syncml, NULL, cred_username, 13175b9c547cSRui Paulo cred_password, client_cert, client_key); 13185b9c547cSRui Paulo if (resp == NULL) 13195b9c547cSRui Paulo return; 13205b9c547cSRui Paulo 13215b9c547cSRui Paulo msgid++; 13225b9c547cSRui Paulo syncml = oma_dm_process(ctx, address, resp, msgid, &resp_uri, 13235b9c547cSRui Paulo pps, pps_fname); 13245b9c547cSRui Paulo xml_node_free(ctx->xml, resp); 13255b9c547cSRui Paulo } 13265b9c547cSRui Paulo 13275b9c547cSRui Paulo os_free(resp_uri); 13285b9c547cSRui Paulo 13295b9c547cSRui Paulo wpa_printf(MSG_INFO, "Update wpa_supplicant credential based on updated PPS MO and request reconnection"); 13305b9c547cSRui Paulo write_summary(ctx, "Update wpa_supplicant credential based on updated PPS MO and request reconnection"); 13315b9c547cSRui Paulo cmd_set_pps(ctx, pps_fname); 13325b9c547cSRui Paulo if (wpa_command(ctx->ifname, "INTERWORKING_SELECT auto") < 0) { 13335b9c547cSRui Paulo wpa_printf(MSG_INFO, "Failed to request wpa_supplicant to reconnect"); 13345b9c547cSRui Paulo write_summary(ctx, "Failed to request wpa_supplicant to reconnect"); 13355b9c547cSRui Paulo } 13365b9c547cSRui Paulo } 13375b9c547cSRui Paulo 13385b9c547cSRui Paulo 13395b9c547cSRui Paulo void cmd_oma_dm_add(struct hs20_osu_client *ctx, const char *pps_fname, 13405b9c547cSRui Paulo const char *add_fname) 13415b9c547cSRui Paulo { 13425b9c547cSRui Paulo xml_node_t *pps, *add; 13435b9c547cSRui Paulo int res; 13445b9c547cSRui Paulo 13455b9c547cSRui Paulo ctx->fqdn = os_strdup("wi-fi.org"); 13465b9c547cSRui Paulo 13475b9c547cSRui Paulo pps = node_from_file(ctx->xml, pps_fname); 13485b9c547cSRui Paulo if (pps == NULL) { 13495b9c547cSRui Paulo wpa_printf(MSG_INFO, "PPS file %s could not be parsed", 13505b9c547cSRui Paulo pps_fname); 13515b9c547cSRui Paulo return; 13525b9c547cSRui Paulo } 13535b9c547cSRui Paulo 13545b9c547cSRui Paulo add = node_from_file(ctx->xml, add_fname); 13555b9c547cSRui Paulo if (add == NULL) { 13565b9c547cSRui Paulo wpa_printf(MSG_INFO, "Add file %s could not be parsed", 13575b9c547cSRui Paulo add_fname); 13585b9c547cSRui Paulo xml_node_free(ctx->xml, pps); 13595b9c547cSRui Paulo return; 13605b9c547cSRui Paulo } 13615b9c547cSRui Paulo 13625b9c547cSRui Paulo res = oma_dm_add(ctx, add, pps, pps_fname); 13635b9c547cSRui Paulo wpa_printf(MSG_INFO, "oma_dm_add --> %d", res); 13645b9c547cSRui Paulo 13655b9c547cSRui Paulo xml_node_free(ctx->xml, pps); 13665b9c547cSRui Paulo xml_node_free(ctx->xml, add); 13675b9c547cSRui Paulo } 13685b9c547cSRui Paulo 13695b9c547cSRui Paulo 13705b9c547cSRui Paulo void cmd_oma_dm_replace(struct hs20_osu_client *ctx, const char *pps_fname, 13715b9c547cSRui Paulo const char *replace_fname) 13725b9c547cSRui Paulo { 13735b9c547cSRui Paulo xml_node_t *pps, *replace; 13745b9c547cSRui Paulo int res; 13755b9c547cSRui Paulo 13765b9c547cSRui Paulo ctx->fqdn = os_strdup("wi-fi.org"); 13775b9c547cSRui Paulo 13785b9c547cSRui Paulo pps = node_from_file(ctx->xml, pps_fname); 13795b9c547cSRui Paulo if (pps == NULL) { 13805b9c547cSRui Paulo wpa_printf(MSG_INFO, "PPS file %s could not be parsed", 13815b9c547cSRui Paulo pps_fname); 13825b9c547cSRui Paulo return; 13835b9c547cSRui Paulo } 13845b9c547cSRui Paulo 13855b9c547cSRui Paulo replace = node_from_file(ctx->xml, replace_fname); 13865b9c547cSRui Paulo if (replace == NULL) { 13875b9c547cSRui Paulo wpa_printf(MSG_INFO, "Replace file %s could not be parsed", 13885b9c547cSRui Paulo replace_fname); 13895b9c547cSRui Paulo xml_node_free(ctx->xml, pps); 13905b9c547cSRui Paulo return; 13915b9c547cSRui Paulo } 13925b9c547cSRui Paulo 13935b9c547cSRui Paulo res = oma_dm_replace(ctx, replace, pps, pps_fname); 13945b9c547cSRui Paulo wpa_printf(MSG_INFO, "oma_dm_replace --> %d", res); 13955b9c547cSRui Paulo 13965b9c547cSRui Paulo xml_node_free(ctx->xml, pps); 13975b9c547cSRui Paulo xml_node_free(ctx->xml, replace); 13985b9c547cSRui Paulo } 1399