1*5b9c547cSRui Paulo /* 2*5b9c547cSRui Paulo * Hotspot 2.0 - OMA DM client 3*5b9c547cSRui Paulo * Copyright (c) 2013-2014, Qualcomm Atheros, Inc. 4*5b9c547cSRui Paulo * 5*5b9c547cSRui Paulo * This software may be distributed under the terms of the BSD license. 6*5b9c547cSRui Paulo * See README for more details. 7*5b9c547cSRui Paulo */ 8*5b9c547cSRui Paulo 9*5b9c547cSRui Paulo #include "includes.h" 10*5b9c547cSRui Paulo 11*5b9c547cSRui Paulo #include "common.h" 12*5b9c547cSRui Paulo #include "wpa_helpers.h" 13*5b9c547cSRui Paulo #include "xml-utils.h" 14*5b9c547cSRui Paulo #include "http-utils.h" 15*5b9c547cSRui Paulo #include "utils/browser.h" 16*5b9c547cSRui Paulo #include "osu_client.h" 17*5b9c547cSRui Paulo 18*5b9c547cSRui Paulo 19*5b9c547cSRui Paulo #define DM_SERVER_INITIATED_MGMT 1200 20*5b9c547cSRui Paulo #define DM_CLIENT_INITIATED_MGMT 1201 21*5b9c547cSRui Paulo #define DM_GENERIC_ALERT 1226 22*5b9c547cSRui Paulo 23*5b9c547cSRui Paulo /* OMA-TS-SyncML-RepPro-V1_2_2 - 10. Response Status Codes */ 24*5b9c547cSRui Paulo #define DM_RESP_OK 200 25*5b9c547cSRui Paulo #define DM_RESP_AUTH_ACCEPTED 212 26*5b9c547cSRui Paulo #define DM_RESP_CHUNKED_ITEM_ACCEPTED 213 27*5b9c547cSRui Paulo #define DM_RESP_NOT_EXECUTED 215 28*5b9c547cSRui Paulo #define DM_RESP_ATOMIC_ROLL_BACK_OK 216 29*5b9c547cSRui Paulo #define DM_RESP_NOT_MODIFIED 304 30*5b9c547cSRui Paulo #define DM_RESP_BAD_REQUEST 400 31*5b9c547cSRui Paulo #define DM_RESP_UNAUTHORIZED 401 32*5b9c547cSRui Paulo #define DM_RESP_FORBIDDEN 403 33*5b9c547cSRui Paulo #define DM_RESP_NOT_FOUND 404 34*5b9c547cSRui Paulo #define DM_RESP_COMMAND_NOT_ALLOWED 405 35*5b9c547cSRui Paulo #define DM_RESP_OPTIONAL_FEATURE_NOT_SUPPORTED 406 36*5b9c547cSRui Paulo #define DM_RESP_MISSING_CREDENTIALS 407 37*5b9c547cSRui Paulo #define DM_RESP_CONFLICT 409 38*5b9c547cSRui Paulo #define DM_RESP_GONE 410 39*5b9c547cSRui Paulo #define DM_RESP_INCOMPLETE_COMMAND 412 40*5b9c547cSRui Paulo #define DM_RESP_REQ_ENTITY_TOO_LARGE 413 41*5b9c547cSRui Paulo #define DM_RESP_URI_TOO_LONG 414 42*5b9c547cSRui Paulo #define DM_RESP_UNSUPPORTED_MEDIA_TYPE_OR_FORMAT 415 43*5b9c547cSRui Paulo #define DM_RESP_REQ_TOO_BIG 416 44*5b9c547cSRui Paulo #define DM_RESP_ALREADY_EXISTS 418 45*5b9c547cSRui Paulo #define DM_RESP_DEVICE_FULL 420 46*5b9c547cSRui Paulo #define DM_RESP_SIZE_MISMATCH 424 47*5b9c547cSRui Paulo #define DM_RESP_PERMISSION_DENIED 425 48*5b9c547cSRui Paulo #define DM_RESP_COMMAND_FAILED 500 49*5b9c547cSRui Paulo #define DM_RESP_COMMAND_NOT_IMPLEMENTED 501 50*5b9c547cSRui Paulo #define DM_RESP_ATOMIC_ROLL_BACK_FAILED 516 51*5b9c547cSRui Paulo 52*5b9c547cSRui Paulo #define DM_HS20_SUBSCRIPTION_CREATION \ 53*5b9c547cSRui Paulo "org.wi-fi.hotspot2dot0.SubscriptionCreation" 54*5b9c547cSRui Paulo #define DM_HS20_SUBSCRIPTION_PROVISIONING \ 55*5b9c547cSRui Paulo "org.wi-fi.hotspot2dot0.SubscriptionProvisioning" 56*5b9c547cSRui Paulo #define DM_HS20_SUBSCRIPTION_REMEDIATION \ 57*5b9c547cSRui Paulo "org.wi-fi.hotspot2dot0.SubscriptionRemediation" 58*5b9c547cSRui Paulo #define DM_HS20_POLICY_UPDATE \ 59*5b9c547cSRui Paulo "org.wi-fi.hotspot2dot0.PolicyUpdate" 60*5b9c547cSRui Paulo 61*5b9c547cSRui Paulo #define DM_URI_PPS "./Wi-Fi/org.wi-fi/PerProviderSubscription" 62*5b9c547cSRui Paulo #define DM_URI_LAUNCH_BROWSER \ 63*5b9c547cSRui Paulo "./DevDetail/Ext/org.wi-fi/Wi-Fi/Ops/launchBrowserToURI" 64*5b9c547cSRui Paulo 65*5b9c547cSRui Paulo 66*5b9c547cSRui Paulo static void add_item(struct hs20_osu_client *ctx, xml_node_t *parent, 67*5b9c547cSRui Paulo const char *locuri, const char *data); 68*5b9c547cSRui Paulo 69*5b9c547cSRui Paulo 70*5b9c547cSRui Paulo static const char * int2str(int val) 71*5b9c547cSRui Paulo { 72*5b9c547cSRui Paulo static char buf[20]; 73*5b9c547cSRui Paulo snprintf(buf, sizeof(buf), "%d", val); 74*5b9c547cSRui Paulo return buf; 75*5b9c547cSRui Paulo } 76*5b9c547cSRui Paulo 77*5b9c547cSRui Paulo 78*5b9c547cSRui Paulo static char * oma_dm_get_target_locuri(struct hs20_osu_client *ctx, 79*5b9c547cSRui Paulo xml_node_t *node) 80*5b9c547cSRui Paulo { 81*5b9c547cSRui Paulo xml_node_t *locuri; 82*5b9c547cSRui Paulo char *uri, *ret = NULL; 83*5b9c547cSRui Paulo 84*5b9c547cSRui Paulo locuri = get_node(ctx->xml, node, "Item/Target/LocURI"); 85*5b9c547cSRui Paulo if (locuri == NULL) 86*5b9c547cSRui Paulo return NULL; 87*5b9c547cSRui Paulo 88*5b9c547cSRui Paulo uri = xml_node_get_text(ctx->xml, locuri); 89*5b9c547cSRui Paulo if (uri) 90*5b9c547cSRui Paulo ret = os_strdup(uri); 91*5b9c547cSRui Paulo xml_node_get_text_free(ctx->xml, uri); 92*5b9c547cSRui Paulo return ret; 93*5b9c547cSRui Paulo } 94*5b9c547cSRui Paulo 95*5b9c547cSRui Paulo 96*5b9c547cSRui Paulo static void oma_dm_add_locuri(struct hs20_osu_client *ctx, xml_node_t *parent, 97*5b9c547cSRui Paulo const char *element, const char *uri) 98*5b9c547cSRui Paulo { 99*5b9c547cSRui Paulo xml_node_t *node; 100*5b9c547cSRui Paulo 101*5b9c547cSRui Paulo node = xml_node_create(ctx->xml, parent, NULL, element); 102*5b9c547cSRui Paulo if (node == NULL) 103*5b9c547cSRui Paulo return; 104*5b9c547cSRui Paulo xml_node_create_text(ctx->xml, node, NULL, "LocURI", uri); 105*5b9c547cSRui Paulo } 106*5b9c547cSRui Paulo 107*5b9c547cSRui Paulo 108*5b9c547cSRui Paulo static xml_node_t * oma_dm_build_hdr(struct hs20_osu_client *ctx, 109*5b9c547cSRui Paulo const char *url, int msgid) 110*5b9c547cSRui Paulo { 111*5b9c547cSRui Paulo xml_node_t *syncml, *synchdr; 112*5b9c547cSRui Paulo xml_namespace_t *ns; 113*5b9c547cSRui Paulo 114*5b9c547cSRui Paulo syncml = xml_node_create_root(ctx->xml, "SYNCML:SYNCML1.2", NULL, &ns, 115*5b9c547cSRui Paulo "SyncML"); 116*5b9c547cSRui Paulo 117*5b9c547cSRui Paulo synchdr = xml_node_create(ctx->xml, syncml, NULL, "SyncHdr"); 118*5b9c547cSRui Paulo xml_node_create_text(ctx->xml, synchdr, NULL, "VerDTD", "1.2"); 119*5b9c547cSRui Paulo xml_node_create_text(ctx->xml, synchdr, NULL, "VerProto", "DM/1.2"); 120*5b9c547cSRui Paulo xml_node_create_text(ctx->xml, synchdr, NULL, "SessionID", "1"); 121*5b9c547cSRui Paulo xml_node_create_text(ctx->xml, synchdr, NULL, "MsgID", int2str(msgid)); 122*5b9c547cSRui Paulo 123*5b9c547cSRui Paulo oma_dm_add_locuri(ctx, synchdr, "Target", url); 124*5b9c547cSRui Paulo oma_dm_add_locuri(ctx, synchdr, "Source", ctx->devid); 125*5b9c547cSRui Paulo 126*5b9c547cSRui Paulo return syncml; 127*5b9c547cSRui Paulo } 128*5b9c547cSRui Paulo 129*5b9c547cSRui Paulo 130*5b9c547cSRui Paulo static void oma_dm_add_cmdid(struct hs20_osu_client *ctx, xml_node_t *parent, 131*5b9c547cSRui Paulo int cmdid) 132*5b9c547cSRui Paulo { 133*5b9c547cSRui Paulo xml_node_create_text(ctx->xml, parent, NULL, "CmdID", int2str(cmdid)); 134*5b9c547cSRui Paulo } 135*5b9c547cSRui Paulo 136*5b9c547cSRui Paulo 137*5b9c547cSRui Paulo static xml_node_t * add_alert(struct hs20_osu_client *ctx, xml_node_t *parent, 138*5b9c547cSRui Paulo int cmdid, int data) 139*5b9c547cSRui Paulo { 140*5b9c547cSRui Paulo xml_node_t *node; 141*5b9c547cSRui Paulo 142*5b9c547cSRui Paulo node = xml_node_create(ctx->xml, parent, NULL, "Alert"); 143*5b9c547cSRui Paulo if (node == NULL) 144*5b9c547cSRui Paulo return NULL; 145*5b9c547cSRui Paulo oma_dm_add_cmdid(ctx, node, cmdid); 146*5b9c547cSRui Paulo xml_node_create_text(ctx->xml, node, NULL, "Data", int2str(data)); 147*5b9c547cSRui Paulo 148*5b9c547cSRui Paulo return node; 149*5b9c547cSRui Paulo } 150*5b9c547cSRui Paulo 151*5b9c547cSRui Paulo 152*5b9c547cSRui Paulo static xml_node_t * add_status(struct hs20_osu_client *ctx, xml_node_t *parent, 153*5b9c547cSRui Paulo int msgref, int cmdref, int cmdid, 154*5b9c547cSRui Paulo const char *cmd, int data, const char *targetref) 155*5b9c547cSRui Paulo { 156*5b9c547cSRui Paulo xml_node_t *node; 157*5b9c547cSRui Paulo 158*5b9c547cSRui Paulo node = xml_node_create(ctx->xml, parent, NULL, "Status"); 159*5b9c547cSRui Paulo if (node == NULL) 160*5b9c547cSRui Paulo return NULL; 161*5b9c547cSRui Paulo oma_dm_add_cmdid(ctx, node, cmdid); 162*5b9c547cSRui Paulo xml_node_create_text(ctx->xml, node, NULL, "MsgRef", int2str(msgref)); 163*5b9c547cSRui Paulo if (cmdref) 164*5b9c547cSRui Paulo xml_node_create_text(ctx->xml, node, NULL, "CmdRef", 165*5b9c547cSRui Paulo int2str(cmdref)); 166*5b9c547cSRui Paulo xml_node_create_text(ctx->xml, node, NULL, "Cmd", cmd); 167*5b9c547cSRui Paulo xml_node_create_text(ctx->xml, node, NULL, "Data", int2str(data)); 168*5b9c547cSRui Paulo if (targetref) { 169*5b9c547cSRui Paulo xml_node_create_text(ctx->xml, node, NULL, "TargetRef", 170*5b9c547cSRui Paulo targetref); 171*5b9c547cSRui Paulo } 172*5b9c547cSRui Paulo 173*5b9c547cSRui Paulo return node; 174*5b9c547cSRui Paulo } 175*5b9c547cSRui Paulo 176*5b9c547cSRui Paulo 177*5b9c547cSRui Paulo static xml_node_t * add_results(struct hs20_osu_client *ctx, xml_node_t *parent, 178*5b9c547cSRui Paulo int msgref, int cmdref, int cmdid, 179*5b9c547cSRui Paulo const char *locuri, const char *data) 180*5b9c547cSRui Paulo { 181*5b9c547cSRui Paulo xml_node_t *node; 182*5b9c547cSRui Paulo 183*5b9c547cSRui Paulo node = xml_node_create(ctx->xml, parent, NULL, "Results"); 184*5b9c547cSRui Paulo if (node == NULL) 185*5b9c547cSRui Paulo return NULL; 186*5b9c547cSRui Paulo 187*5b9c547cSRui Paulo oma_dm_add_cmdid(ctx, node, cmdid); 188*5b9c547cSRui Paulo xml_node_create_text(ctx->xml, node, NULL, "MsgRef", int2str(msgref)); 189*5b9c547cSRui Paulo xml_node_create_text(ctx->xml, node, NULL, "CmdRef", int2str(cmdref)); 190*5b9c547cSRui Paulo add_item(ctx, node, locuri, data); 191*5b9c547cSRui Paulo 192*5b9c547cSRui Paulo return node; 193*5b9c547cSRui Paulo } 194*5b9c547cSRui Paulo 195*5b9c547cSRui Paulo 196*5b9c547cSRui Paulo static char * mo_str(struct hs20_osu_client *ctx, const char *urn, 197*5b9c547cSRui Paulo const char *fname) 198*5b9c547cSRui Paulo { 199*5b9c547cSRui Paulo xml_node_t *fnode, *tnds; 200*5b9c547cSRui Paulo char *str; 201*5b9c547cSRui Paulo 202*5b9c547cSRui Paulo fnode = node_from_file(ctx->xml, fname); 203*5b9c547cSRui Paulo if (!fnode) 204*5b9c547cSRui Paulo return NULL; 205*5b9c547cSRui Paulo tnds = mo_to_tnds(ctx->xml, fnode, 0, urn, "syncml:dmddf1.2"); 206*5b9c547cSRui Paulo xml_node_free(ctx->xml, fnode); 207*5b9c547cSRui Paulo if (!tnds) 208*5b9c547cSRui Paulo return NULL; 209*5b9c547cSRui Paulo 210*5b9c547cSRui Paulo str = xml_node_to_str(ctx->xml, tnds); 211*5b9c547cSRui Paulo xml_node_free(ctx->xml, tnds); 212*5b9c547cSRui Paulo if (str == NULL) 213*5b9c547cSRui Paulo return NULL; 214*5b9c547cSRui Paulo wpa_printf(MSG_INFO, "MgmtTree: %s", str); 215*5b9c547cSRui Paulo 216*5b9c547cSRui Paulo return str; 217*5b9c547cSRui Paulo } 218*5b9c547cSRui Paulo 219*5b9c547cSRui Paulo 220*5b9c547cSRui Paulo static void add_item(struct hs20_osu_client *ctx, xml_node_t *parent, 221*5b9c547cSRui Paulo const char *locuri, const char *data) 222*5b9c547cSRui Paulo { 223*5b9c547cSRui Paulo xml_node_t *item, *node; 224*5b9c547cSRui Paulo 225*5b9c547cSRui Paulo item = xml_node_create(ctx->xml, parent, NULL, "Item"); 226*5b9c547cSRui Paulo oma_dm_add_locuri(ctx, item, "Source", locuri); 227*5b9c547cSRui Paulo node = xml_node_create(ctx->xml, item, NULL, "Meta"); 228*5b9c547cSRui Paulo xml_node_create_text_ns(ctx->xml, node, "syncml:metinf", "Format", 229*5b9c547cSRui Paulo "Chr"); 230*5b9c547cSRui Paulo xml_node_create_text_ns(ctx->xml, node, "syncml:metinf", "Type", 231*5b9c547cSRui Paulo "text/plain"); 232*5b9c547cSRui Paulo xml_node_create_text(ctx->xml, item, NULL, "Data", data); 233*5b9c547cSRui Paulo } 234*5b9c547cSRui Paulo 235*5b9c547cSRui Paulo 236*5b9c547cSRui Paulo static void add_replace_devinfo(struct hs20_osu_client *ctx, xml_node_t *parent, 237*5b9c547cSRui Paulo int cmdid) 238*5b9c547cSRui Paulo { 239*5b9c547cSRui Paulo xml_node_t *info, *child, *replace; 240*5b9c547cSRui Paulo const char *name; 241*5b9c547cSRui Paulo char locuri[200], *txt; 242*5b9c547cSRui Paulo 243*5b9c547cSRui Paulo info = node_from_file(ctx->xml, "devinfo.xml"); 244*5b9c547cSRui Paulo if (info == NULL) { 245*5b9c547cSRui Paulo wpa_printf(MSG_INFO, "Could not read devinfo.xml"); 246*5b9c547cSRui Paulo return; 247*5b9c547cSRui Paulo } 248*5b9c547cSRui Paulo 249*5b9c547cSRui Paulo replace = xml_node_create(ctx->xml, parent, NULL, "Replace"); 250*5b9c547cSRui Paulo if (replace == NULL) { 251*5b9c547cSRui Paulo xml_node_free(ctx->xml, info); 252*5b9c547cSRui Paulo return; 253*5b9c547cSRui Paulo } 254*5b9c547cSRui Paulo oma_dm_add_cmdid(ctx, replace, cmdid); 255*5b9c547cSRui Paulo 256*5b9c547cSRui Paulo xml_node_for_each_child(ctx->xml, child, info) { 257*5b9c547cSRui Paulo xml_node_for_each_check(ctx->xml, child); 258*5b9c547cSRui Paulo name = xml_node_get_localname(ctx->xml, child); 259*5b9c547cSRui Paulo os_snprintf(locuri, sizeof(locuri), "./DevInfo/%s", name); 260*5b9c547cSRui Paulo txt = xml_node_get_text(ctx->xml, child); 261*5b9c547cSRui Paulo if (txt) { 262*5b9c547cSRui Paulo add_item(ctx, replace, locuri, txt); 263*5b9c547cSRui Paulo xml_node_get_text_free(ctx->xml, txt); 264*5b9c547cSRui Paulo } 265*5b9c547cSRui Paulo } 266*5b9c547cSRui Paulo 267*5b9c547cSRui Paulo xml_node_free(ctx->xml, info); 268*5b9c547cSRui Paulo } 269*5b9c547cSRui Paulo 270*5b9c547cSRui Paulo 271*5b9c547cSRui Paulo static void oma_dm_add_hs20_generic_alert(struct hs20_osu_client *ctx, 272*5b9c547cSRui Paulo xml_node_t *syncbody, 273*5b9c547cSRui Paulo int cmdid, const char *oper, 274*5b9c547cSRui Paulo const char *data) 275*5b9c547cSRui Paulo { 276*5b9c547cSRui Paulo xml_node_t *node, *item; 277*5b9c547cSRui Paulo char buf[200]; 278*5b9c547cSRui Paulo 279*5b9c547cSRui Paulo node = add_alert(ctx, syncbody, cmdid, DM_GENERIC_ALERT); 280*5b9c547cSRui Paulo 281*5b9c547cSRui Paulo item = xml_node_create(ctx->xml, node, NULL, "Item"); 282*5b9c547cSRui Paulo oma_dm_add_locuri(ctx, item, "Source", DM_URI_PPS); 283*5b9c547cSRui Paulo node = xml_node_create(ctx->xml, item, NULL, "Meta"); 284*5b9c547cSRui Paulo snprintf(buf, sizeof(buf), "Reversed-Domain-Name: %s", oper); 285*5b9c547cSRui Paulo xml_node_create_text_ns(ctx->xml, node, "syncml:metinf", "Type", buf); 286*5b9c547cSRui Paulo xml_node_create_text_ns(ctx->xml, node, "syncml:metinf", "Format", 287*5b9c547cSRui Paulo "xml"); 288*5b9c547cSRui Paulo xml_node_create_text(ctx->xml, item, NULL, "Data", data); 289*5b9c547cSRui Paulo } 290*5b9c547cSRui Paulo 291*5b9c547cSRui Paulo 292*5b9c547cSRui Paulo static xml_node_t * build_oma_dm_1(struct hs20_osu_client *ctx, 293*5b9c547cSRui Paulo const char *url, int msgid, const char *oper) 294*5b9c547cSRui Paulo { 295*5b9c547cSRui Paulo xml_node_t *syncml, *syncbody; 296*5b9c547cSRui Paulo char *str; 297*5b9c547cSRui Paulo int cmdid = 0; 298*5b9c547cSRui Paulo 299*5b9c547cSRui Paulo syncml = oma_dm_build_hdr(ctx, url, msgid); 300*5b9c547cSRui Paulo if (syncml == NULL) 301*5b9c547cSRui Paulo return NULL; 302*5b9c547cSRui Paulo 303*5b9c547cSRui Paulo syncbody = xml_node_create(ctx->xml, syncml, NULL, "SyncBody"); 304*5b9c547cSRui Paulo if (syncbody == NULL) { 305*5b9c547cSRui Paulo xml_node_free(ctx->xml, syncml); 306*5b9c547cSRui Paulo return NULL; 307*5b9c547cSRui Paulo } 308*5b9c547cSRui Paulo 309*5b9c547cSRui Paulo cmdid++; 310*5b9c547cSRui Paulo add_alert(ctx, syncbody, cmdid, DM_CLIENT_INITIATED_MGMT); 311*5b9c547cSRui Paulo 312*5b9c547cSRui Paulo str = mo_str(ctx, NULL, "devdetail.xml"); 313*5b9c547cSRui Paulo if (str == NULL) { 314*5b9c547cSRui Paulo xml_node_free(ctx->xml, syncml); 315*5b9c547cSRui Paulo return NULL; 316*5b9c547cSRui Paulo } 317*5b9c547cSRui Paulo cmdid++; 318*5b9c547cSRui Paulo oma_dm_add_hs20_generic_alert(ctx, syncbody, cmdid, oper, str); 319*5b9c547cSRui Paulo os_free(str); 320*5b9c547cSRui Paulo 321*5b9c547cSRui Paulo cmdid++; 322*5b9c547cSRui Paulo add_replace_devinfo(ctx, syncbody, cmdid); 323*5b9c547cSRui Paulo 324*5b9c547cSRui Paulo xml_node_create(ctx->xml, syncbody, NULL, "Final"); 325*5b9c547cSRui Paulo 326*5b9c547cSRui Paulo return syncml; 327*5b9c547cSRui Paulo } 328*5b9c547cSRui Paulo 329*5b9c547cSRui Paulo 330*5b9c547cSRui Paulo static xml_node_t * build_oma_dm_1_sub_reg(struct hs20_osu_client *ctx, 331*5b9c547cSRui Paulo const char *url, int msgid) 332*5b9c547cSRui Paulo { 333*5b9c547cSRui Paulo xml_node_t *syncml; 334*5b9c547cSRui Paulo 335*5b9c547cSRui Paulo syncml = build_oma_dm_1(ctx, url, msgid, DM_HS20_SUBSCRIPTION_CREATION); 336*5b9c547cSRui Paulo if (syncml) 337*5b9c547cSRui Paulo debug_dump_node(ctx, "OMA-DM Package 1 (sub reg)", syncml); 338*5b9c547cSRui Paulo 339*5b9c547cSRui Paulo return syncml; 340*5b9c547cSRui Paulo } 341*5b9c547cSRui Paulo 342*5b9c547cSRui Paulo 343*5b9c547cSRui Paulo static xml_node_t * build_oma_dm_1_sub_prov(struct hs20_osu_client *ctx, 344*5b9c547cSRui Paulo const char *url, int msgid) 345*5b9c547cSRui Paulo { 346*5b9c547cSRui Paulo xml_node_t *syncml; 347*5b9c547cSRui Paulo 348*5b9c547cSRui Paulo syncml = build_oma_dm_1(ctx, url, msgid, 349*5b9c547cSRui Paulo DM_HS20_SUBSCRIPTION_PROVISIONING); 350*5b9c547cSRui Paulo if (syncml) 351*5b9c547cSRui Paulo debug_dump_node(ctx, "OMA-DM Package 1 (sub prov)", syncml); 352*5b9c547cSRui Paulo 353*5b9c547cSRui Paulo return syncml; 354*5b9c547cSRui Paulo } 355*5b9c547cSRui Paulo 356*5b9c547cSRui Paulo 357*5b9c547cSRui Paulo static xml_node_t * build_oma_dm_1_pol_upd(struct hs20_osu_client *ctx, 358*5b9c547cSRui Paulo const char *url, int msgid) 359*5b9c547cSRui Paulo { 360*5b9c547cSRui Paulo xml_node_t *syncml; 361*5b9c547cSRui Paulo 362*5b9c547cSRui Paulo syncml = build_oma_dm_1(ctx, url, msgid, DM_HS20_POLICY_UPDATE); 363*5b9c547cSRui Paulo if (syncml) 364*5b9c547cSRui Paulo debug_dump_node(ctx, "OMA-DM Package 1 (pol upd)", syncml); 365*5b9c547cSRui Paulo 366*5b9c547cSRui Paulo return syncml; 367*5b9c547cSRui Paulo } 368*5b9c547cSRui Paulo 369*5b9c547cSRui Paulo 370*5b9c547cSRui Paulo static xml_node_t * build_oma_dm_1_sub_rem(struct hs20_osu_client *ctx, 371*5b9c547cSRui Paulo const char *url, int msgid) 372*5b9c547cSRui Paulo { 373*5b9c547cSRui Paulo xml_node_t *syncml; 374*5b9c547cSRui Paulo 375*5b9c547cSRui Paulo syncml = build_oma_dm_1(ctx, url, msgid, 376*5b9c547cSRui Paulo DM_HS20_SUBSCRIPTION_REMEDIATION); 377*5b9c547cSRui Paulo if (syncml) 378*5b9c547cSRui Paulo debug_dump_node(ctx, "OMA-DM Package 1 (sub rem)", syncml); 379*5b9c547cSRui Paulo 380*5b9c547cSRui Paulo return syncml; 381*5b9c547cSRui Paulo } 382*5b9c547cSRui Paulo 383*5b9c547cSRui Paulo 384*5b9c547cSRui Paulo static int oma_dm_exec_browser(struct hs20_osu_client *ctx, xml_node_t *exec) 385*5b9c547cSRui Paulo { 386*5b9c547cSRui Paulo xml_node_t *node; 387*5b9c547cSRui Paulo char *data; 388*5b9c547cSRui Paulo int res; 389*5b9c547cSRui Paulo 390*5b9c547cSRui Paulo node = get_node(ctx->xml, exec, "Item/Data"); 391*5b9c547cSRui Paulo if (node == NULL) { 392*5b9c547cSRui Paulo wpa_printf(MSG_INFO, "No Data node found"); 393*5b9c547cSRui Paulo return DM_RESP_BAD_REQUEST; 394*5b9c547cSRui Paulo } 395*5b9c547cSRui Paulo 396*5b9c547cSRui Paulo data = xml_node_get_text(ctx->xml, node); 397*5b9c547cSRui Paulo if (data == NULL) { 398*5b9c547cSRui Paulo wpa_printf(MSG_INFO, "Invalid data"); 399*5b9c547cSRui Paulo return DM_RESP_BAD_REQUEST; 400*5b9c547cSRui Paulo } 401*5b9c547cSRui Paulo wpa_printf(MSG_INFO, "Data: %s", data); 402*5b9c547cSRui Paulo wpa_printf(MSG_INFO, "Launch browser to URI '%s'", data); 403*5b9c547cSRui Paulo write_summary(ctx, "Launch browser to URI '%s'", data); 404*5b9c547cSRui Paulo res = hs20_web_browser(data); 405*5b9c547cSRui Paulo xml_node_get_text_free(ctx->xml, data); 406*5b9c547cSRui Paulo if (res > 0) { 407*5b9c547cSRui Paulo wpa_printf(MSG_INFO, "User response in browser completed successfully"); 408*5b9c547cSRui Paulo write_summary(ctx, "User response in browser completed successfully"); 409*5b9c547cSRui Paulo return DM_RESP_OK; 410*5b9c547cSRui Paulo } else { 411*5b9c547cSRui Paulo wpa_printf(MSG_INFO, "Failed to receive user response"); 412*5b9c547cSRui Paulo write_summary(ctx, "Failed to receive user response"); 413*5b9c547cSRui Paulo return DM_RESP_COMMAND_FAILED; 414*5b9c547cSRui Paulo } 415*5b9c547cSRui Paulo } 416*5b9c547cSRui Paulo 417*5b9c547cSRui Paulo 418*5b9c547cSRui Paulo static int oma_dm_exec_get_cert(struct hs20_osu_client *ctx, xml_node_t *exec) 419*5b9c547cSRui Paulo { 420*5b9c547cSRui Paulo xml_node_t *node, *getcert; 421*5b9c547cSRui Paulo char *data; 422*5b9c547cSRui Paulo const char *name; 423*5b9c547cSRui Paulo int res; 424*5b9c547cSRui Paulo 425*5b9c547cSRui Paulo wpa_printf(MSG_INFO, "Client certificate enrollment"); 426*5b9c547cSRui Paulo write_summary(ctx, "Client certificate enrollment"); 427*5b9c547cSRui Paulo 428*5b9c547cSRui Paulo node = get_node(ctx->xml, exec, "Item/Data"); 429*5b9c547cSRui Paulo if (node == NULL) { 430*5b9c547cSRui Paulo wpa_printf(MSG_INFO, "No Data node found"); 431*5b9c547cSRui Paulo return DM_RESP_BAD_REQUEST; 432*5b9c547cSRui Paulo } 433*5b9c547cSRui Paulo 434*5b9c547cSRui Paulo data = xml_node_get_text(ctx->xml, node); 435*5b9c547cSRui Paulo if (data == NULL) { 436*5b9c547cSRui Paulo wpa_printf(MSG_INFO, "Invalid data"); 437*5b9c547cSRui Paulo return DM_RESP_BAD_REQUEST; 438*5b9c547cSRui Paulo } 439*5b9c547cSRui Paulo wpa_printf(MSG_INFO, "Data: %s", data); 440*5b9c547cSRui Paulo getcert = xml_node_from_buf(ctx->xml, data); 441*5b9c547cSRui Paulo xml_node_get_text_free(ctx->xml, data); 442*5b9c547cSRui Paulo 443*5b9c547cSRui Paulo if (getcert == NULL) { 444*5b9c547cSRui Paulo wpa_printf(MSG_INFO, "Could not parse Item/Data node contents"); 445*5b9c547cSRui Paulo return DM_RESP_BAD_REQUEST; 446*5b9c547cSRui Paulo } 447*5b9c547cSRui Paulo 448*5b9c547cSRui Paulo debug_dump_node(ctx, "OMA-DM getCertificate", getcert); 449*5b9c547cSRui Paulo 450*5b9c547cSRui Paulo name = xml_node_get_localname(ctx->xml, getcert); 451*5b9c547cSRui Paulo if (name == NULL || os_strcasecmp(name, "getCertificate") != 0) { 452*5b9c547cSRui Paulo wpa_printf(MSG_INFO, "Unexpected getCertificate node name '%s'", 453*5b9c547cSRui Paulo name); 454*5b9c547cSRui Paulo return DM_RESP_BAD_REQUEST; 455*5b9c547cSRui Paulo } 456*5b9c547cSRui Paulo 457*5b9c547cSRui Paulo res = osu_get_certificate(ctx, getcert); 458*5b9c547cSRui Paulo 459*5b9c547cSRui Paulo xml_node_free(ctx->xml, getcert); 460*5b9c547cSRui Paulo 461*5b9c547cSRui Paulo return res == 0 ? DM_RESP_OK : DM_RESP_COMMAND_FAILED; 462*5b9c547cSRui Paulo } 463*5b9c547cSRui Paulo 464*5b9c547cSRui Paulo 465*5b9c547cSRui Paulo static int oma_dm_exec(struct hs20_osu_client *ctx, xml_node_t *exec) 466*5b9c547cSRui Paulo { 467*5b9c547cSRui Paulo char *locuri; 468*5b9c547cSRui Paulo int ret; 469*5b9c547cSRui Paulo 470*5b9c547cSRui Paulo locuri = oma_dm_get_target_locuri(ctx, exec); 471*5b9c547cSRui Paulo if (locuri == NULL) { 472*5b9c547cSRui Paulo wpa_printf(MSG_INFO, "No Target LocURI node found"); 473*5b9c547cSRui Paulo return DM_RESP_BAD_REQUEST; 474*5b9c547cSRui Paulo } 475*5b9c547cSRui Paulo 476*5b9c547cSRui Paulo wpa_printf(MSG_INFO, "Target LocURI: %s", locuri); 477*5b9c547cSRui Paulo 478*5b9c547cSRui Paulo if (os_strcasecmp(locuri, "./DevDetail/Ext/org.wi-fi/Wi-Fi/Ops/" 479*5b9c547cSRui Paulo "launchBrowserToURI") == 0) { 480*5b9c547cSRui Paulo ret = oma_dm_exec_browser(ctx, exec); 481*5b9c547cSRui Paulo } else if (os_strcasecmp(locuri, "./DevDetail/Ext/org.wi-fi/Wi-Fi/Ops/" 482*5b9c547cSRui Paulo "getCertificate") == 0) { 483*5b9c547cSRui Paulo ret = oma_dm_exec_get_cert(ctx, exec); 484*5b9c547cSRui Paulo } else { 485*5b9c547cSRui Paulo wpa_printf(MSG_INFO, "Unsupported exec Target LocURI"); 486*5b9c547cSRui Paulo ret = DM_RESP_NOT_FOUND; 487*5b9c547cSRui Paulo } 488*5b9c547cSRui Paulo os_free(locuri); 489*5b9c547cSRui Paulo 490*5b9c547cSRui Paulo return ret; 491*5b9c547cSRui Paulo } 492*5b9c547cSRui Paulo 493*5b9c547cSRui Paulo 494*5b9c547cSRui Paulo static int oma_dm_run_add(struct hs20_osu_client *ctx, const char *locuri, 495*5b9c547cSRui Paulo xml_node_t *add, xml_node_t *pps, 496*5b9c547cSRui Paulo const char *pps_fname) 497*5b9c547cSRui Paulo { 498*5b9c547cSRui Paulo const char *pos; 499*5b9c547cSRui Paulo size_t fqdn_len; 500*5b9c547cSRui Paulo xml_node_t *node, *tnds, *unode, *pps_node; 501*5b9c547cSRui Paulo char *data, *uri, *upos, *end; 502*5b9c547cSRui Paulo int use_tnds = 0; 503*5b9c547cSRui Paulo size_t uri_len; 504*5b9c547cSRui Paulo 505*5b9c547cSRui Paulo wpa_printf(MSG_INFO, "Add command target LocURI: %s", locuri); 506*5b9c547cSRui Paulo 507*5b9c547cSRui Paulo if (os_strncasecmp(locuri, "./Wi-Fi/", 8) != 0) { 508*5b9c547cSRui Paulo wpa_printf(MSG_INFO, "Do not allow Add outside ./Wi-Fi"); 509*5b9c547cSRui Paulo return DM_RESP_PERMISSION_DENIED; 510*5b9c547cSRui Paulo } 511*5b9c547cSRui Paulo pos = locuri + 8; 512*5b9c547cSRui Paulo 513*5b9c547cSRui Paulo if (ctx->fqdn == NULL) 514*5b9c547cSRui Paulo return DM_RESP_COMMAND_FAILED; 515*5b9c547cSRui Paulo fqdn_len = os_strlen(ctx->fqdn); 516*5b9c547cSRui Paulo if (os_strncasecmp(pos, ctx->fqdn, fqdn_len) != 0 || 517*5b9c547cSRui Paulo pos[fqdn_len] != '/') { 518*5b9c547cSRui Paulo wpa_printf(MSG_INFO, "Do not allow Add outside ./Wi-Fi/%s", 519*5b9c547cSRui Paulo ctx->fqdn); 520*5b9c547cSRui Paulo return DM_RESP_PERMISSION_DENIED; 521*5b9c547cSRui Paulo } 522*5b9c547cSRui Paulo pos += fqdn_len + 1; 523*5b9c547cSRui Paulo 524*5b9c547cSRui Paulo if (os_strncasecmp(pos, "PerProviderSubscription/", 24) != 0) { 525*5b9c547cSRui Paulo wpa_printf(MSG_INFO, 526*5b9c547cSRui Paulo "Do not allow Add outside ./Wi-Fi/%s/PerProviderSubscription", 527*5b9c547cSRui Paulo ctx->fqdn); 528*5b9c547cSRui Paulo return DM_RESP_PERMISSION_DENIED; 529*5b9c547cSRui Paulo } 530*5b9c547cSRui Paulo pos += 24; 531*5b9c547cSRui Paulo 532*5b9c547cSRui Paulo wpa_printf(MSG_INFO, "Add command for PPS node %s", pos); 533*5b9c547cSRui Paulo 534*5b9c547cSRui Paulo pps_node = get_node(ctx->xml, pps, pos); 535*5b9c547cSRui Paulo if (pps_node) { 536*5b9c547cSRui Paulo wpa_printf(MSG_INFO, "Specified PPS node exists already"); 537*5b9c547cSRui Paulo return DM_RESP_ALREADY_EXISTS; 538*5b9c547cSRui Paulo } 539*5b9c547cSRui Paulo 540*5b9c547cSRui Paulo uri = os_strdup(pos); 541*5b9c547cSRui Paulo if (uri == NULL) 542*5b9c547cSRui Paulo return DM_RESP_COMMAND_FAILED; 543*5b9c547cSRui Paulo while (!pps_node) { 544*5b9c547cSRui Paulo upos = os_strrchr(uri, '/'); 545*5b9c547cSRui Paulo if (!upos) 546*5b9c547cSRui Paulo break; 547*5b9c547cSRui Paulo upos[0] = '\0'; 548*5b9c547cSRui Paulo pps_node = get_node(ctx->xml, pps, uri); 549*5b9c547cSRui Paulo wpa_printf(MSG_INFO, "Node %s %s", uri, 550*5b9c547cSRui Paulo pps_node ? "exists" : "does not exist"); 551*5b9c547cSRui Paulo } 552*5b9c547cSRui Paulo 553*5b9c547cSRui Paulo wpa_printf(MSG_INFO, "Parent URI: %s", uri); 554*5b9c547cSRui Paulo 555*5b9c547cSRui Paulo if (!pps_node) { 556*5b9c547cSRui Paulo /* Add at root of PPS MO */ 557*5b9c547cSRui Paulo pps_node = pps; 558*5b9c547cSRui Paulo } 559*5b9c547cSRui Paulo 560*5b9c547cSRui Paulo uri_len = os_strlen(uri); 561*5b9c547cSRui Paulo os_strlcpy(uri, pos + uri_len, os_strlen(pos)); 562*5b9c547cSRui Paulo upos = uri; 563*5b9c547cSRui Paulo while (*upos == '/') 564*5b9c547cSRui Paulo upos++; 565*5b9c547cSRui Paulo wpa_printf(MSG_INFO, "Nodes to add: %s", upos); 566*5b9c547cSRui Paulo 567*5b9c547cSRui Paulo for (;;) { 568*5b9c547cSRui Paulo end = os_strchr(upos, '/'); 569*5b9c547cSRui Paulo if (!end) 570*5b9c547cSRui Paulo break; 571*5b9c547cSRui Paulo *end = '\0'; 572*5b9c547cSRui Paulo wpa_printf(MSG_INFO, "Adding interim node %s", upos); 573*5b9c547cSRui Paulo pps_node = xml_node_create(ctx->xml, pps_node, NULL, upos); 574*5b9c547cSRui Paulo if (pps_node == NULL) { 575*5b9c547cSRui Paulo os_free(uri); 576*5b9c547cSRui Paulo return DM_RESP_COMMAND_FAILED; 577*5b9c547cSRui Paulo } 578*5b9c547cSRui Paulo upos = end + 1; 579*5b9c547cSRui Paulo } 580*5b9c547cSRui Paulo 581*5b9c547cSRui Paulo wpa_printf(MSG_INFO, "Adding node %s", upos); 582*5b9c547cSRui Paulo 583*5b9c547cSRui Paulo node = get_node(ctx->xml, add, "Item/Meta/Type"); 584*5b9c547cSRui Paulo if (node) { 585*5b9c547cSRui Paulo char *type; 586*5b9c547cSRui Paulo type = xml_node_get_text(ctx->xml, node); 587*5b9c547cSRui Paulo if (type == NULL) { 588*5b9c547cSRui Paulo wpa_printf(MSG_ERROR, "Could not find type text"); 589*5b9c547cSRui Paulo os_free(uri); 590*5b9c547cSRui Paulo return DM_RESP_BAD_REQUEST; 591*5b9c547cSRui Paulo } 592*5b9c547cSRui Paulo use_tnds = node && 593*5b9c547cSRui Paulo os_strstr(type, "application/vnd.syncml.dmtnds+xml"); 594*5b9c547cSRui Paulo } 595*5b9c547cSRui Paulo 596*5b9c547cSRui Paulo node = get_node(ctx->xml, add, "Item/Data"); 597*5b9c547cSRui Paulo if (node == NULL) { 598*5b9c547cSRui Paulo wpa_printf(MSG_INFO, "No Add/Item/Data found"); 599*5b9c547cSRui Paulo os_free(uri); 600*5b9c547cSRui Paulo return DM_RESP_BAD_REQUEST; 601*5b9c547cSRui Paulo } 602*5b9c547cSRui Paulo 603*5b9c547cSRui Paulo data = xml_node_get_text(ctx->xml, node); 604*5b9c547cSRui Paulo if (data == NULL) { 605*5b9c547cSRui Paulo wpa_printf(MSG_INFO, "Could not get Add/Item/Data text"); 606*5b9c547cSRui Paulo os_free(uri); 607*5b9c547cSRui Paulo return DM_RESP_BAD_REQUEST; 608*5b9c547cSRui Paulo } 609*5b9c547cSRui Paulo 610*5b9c547cSRui Paulo wpa_printf(MSG_DEBUG, "Add/Item/Data: %s", data); 611*5b9c547cSRui Paulo 612*5b9c547cSRui Paulo if (use_tnds) { 613*5b9c547cSRui Paulo tnds = xml_node_from_buf(ctx->xml, data); 614*5b9c547cSRui Paulo xml_node_get_text_free(ctx->xml, data); 615*5b9c547cSRui Paulo if (tnds == NULL) { 616*5b9c547cSRui Paulo wpa_printf(MSG_INFO, 617*5b9c547cSRui Paulo "Could not parse Add/Item/Data text"); 618*5b9c547cSRui Paulo os_free(uri); 619*5b9c547cSRui Paulo return DM_RESP_BAD_REQUEST; 620*5b9c547cSRui Paulo } 621*5b9c547cSRui Paulo 622*5b9c547cSRui Paulo unode = tnds_to_mo(ctx->xml, tnds); 623*5b9c547cSRui Paulo xml_node_free(ctx->xml, tnds); 624*5b9c547cSRui Paulo if (unode == NULL) { 625*5b9c547cSRui Paulo wpa_printf(MSG_INFO, "Could not parse TNDS text"); 626*5b9c547cSRui Paulo os_free(uri); 627*5b9c547cSRui Paulo return DM_RESP_BAD_REQUEST; 628*5b9c547cSRui Paulo } 629*5b9c547cSRui Paulo 630*5b9c547cSRui Paulo debug_dump_node(ctx, "Parsed TNDS", unode); 631*5b9c547cSRui Paulo 632*5b9c547cSRui Paulo xml_node_add_child(ctx->xml, pps_node, unode); 633*5b9c547cSRui Paulo } else { 634*5b9c547cSRui Paulo /* TODO: What to do here? */ 635*5b9c547cSRui Paulo os_free(uri); 636*5b9c547cSRui Paulo return DM_RESP_BAD_REQUEST; 637*5b9c547cSRui Paulo } 638*5b9c547cSRui Paulo 639*5b9c547cSRui Paulo os_free(uri); 640*5b9c547cSRui Paulo 641*5b9c547cSRui Paulo if (update_pps_file(ctx, pps_fname, pps) < 0) 642*5b9c547cSRui Paulo return DM_RESP_COMMAND_FAILED; 643*5b9c547cSRui Paulo 644*5b9c547cSRui Paulo ctx->pps_updated = 1; 645*5b9c547cSRui Paulo 646*5b9c547cSRui Paulo return DM_RESP_OK; 647*5b9c547cSRui Paulo } 648*5b9c547cSRui Paulo 649*5b9c547cSRui Paulo 650*5b9c547cSRui Paulo static int oma_dm_add(struct hs20_osu_client *ctx, xml_node_t *add, 651*5b9c547cSRui Paulo xml_node_t *pps, const char *pps_fname) 652*5b9c547cSRui Paulo { 653*5b9c547cSRui Paulo xml_node_t *node; 654*5b9c547cSRui Paulo char *locuri; 655*5b9c547cSRui Paulo char fname[300]; 656*5b9c547cSRui Paulo int ret; 657*5b9c547cSRui Paulo 658*5b9c547cSRui Paulo node = get_node(ctx->xml, add, "Item/Target/LocURI"); 659*5b9c547cSRui Paulo if (node == NULL) { 660*5b9c547cSRui Paulo wpa_printf(MSG_INFO, "No Target LocURI node found"); 661*5b9c547cSRui Paulo return DM_RESP_BAD_REQUEST; 662*5b9c547cSRui Paulo } 663*5b9c547cSRui Paulo locuri = xml_node_get_text(ctx->xml, node); 664*5b9c547cSRui Paulo if (locuri == NULL) { 665*5b9c547cSRui Paulo wpa_printf(MSG_ERROR, "No LocURI node text found"); 666*5b9c547cSRui Paulo return DM_RESP_BAD_REQUEST; 667*5b9c547cSRui Paulo } 668*5b9c547cSRui Paulo wpa_printf(MSG_INFO, "Target LocURI: %s", locuri); 669*5b9c547cSRui Paulo if (os_strncasecmp(locuri, "./Wi-Fi/", 8) != 0) { 670*5b9c547cSRui Paulo wpa_printf(MSG_INFO, "Unsupported Add Target LocURI"); 671*5b9c547cSRui Paulo xml_node_get_text_free(ctx->xml, locuri); 672*5b9c547cSRui Paulo return DM_RESP_PERMISSION_DENIED; 673*5b9c547cSRui Paulo } 674*5b9c547cSRui Paulo 675*5b9c547cSRui Paulo node = get_node(ctx->xml, add, "Item/Data"); 676*5b9c547cSRui Paulo if (node == NULL) { 677*5b9c547cSRui Paulo wpa_printf(MSG_INFO, "No Data node found"); 678*5b9c547cSRui Paulo xml_node_get_text_free(ctx->xml, locuri); 679*5b9c547cSRui Paulo return DM_RESP_BAD_REQUEST; 680*5b9c547cSRui Paulo } 681*5b9c547cSRui Paulo 682*5b9c547cSRui Paulo if (pps_fname && os_file_exists(pps_fname)) { 683*5b9c547cSRui Paulo ret = oma_dm_run_add(ctx, locuri, add, pps, pps_fname); 684*5b9c547cSRui Paulo if (ret != DM_RESP_OK) { 685*5b9c547cSRui Paulo xml_node_get_text_free(ctx->xml, locuri); 686*5b9c547cSRui Paulo return ret; 687*5b9c547cSRui Paulo } 688*5b9c547cSRui Paulo ret = 0; 689*5b9c547cSRui Paulo os_strlcpy(fname, pps_fname, sizeof(fname)); 690*5b9c547cSRui Paulo } else 691*5b9c547cSRui Paulo ret = hs20_add_pps_mo(ctx, locuri, node, fname, sizeof(fname)); 692*5b9c547cSRui Paulo xml_node_get_text_free(ctx->xml, locuri); 693*5b9c547cSRui Paulo if (ret < 0) 694*5b9c547cSRui Paulo return ret == -2 ? DM_RESP_ALREADY_EXISTS : 695*5b9c547cSRui Paulo DM_RESP_COMMAND_FAILED; 696*5b9c547cSRui Paulo 697*5b9c547cSRui Paulo if (ctx->no_reconnect == 2) { 698*5b9c547cSRui Paulo os_snprintf(ctx->pps_fname, sizeof(ctx->pps_fname), "%s", 699*5b9c547cSRui Paulo fname); 700*5b9c547cSRui Paulo ctx->pps_cred_set = 1; 701*5b9c547cSRui Paulo return DM_RESP_OK; 702*5b9c547cSRui Paulo } 703*5b9c547cSRui Paulo 704*5b9c547cSRui Paulo wpa_printf(MSG_INFO, "Updating wpa_supplicant credentials"); 705*5b9c547cSRui Paulo cmd_set_pps(ctx, fname); 706*5b9c547cSRui Paulo 707*5b9c547cSRui Paulo if (ctx->no_reconnect) 708*5b9c547cSRui Paulo return DM_RESP_OK; 709*5b9c547cSRui Paulo 710*5b9c547cSRui Paulo wpa_printf(MSG_INFO, "Requesting reconnection with updated configuration"); 711*5b9c547cSRui Paulo if (wpa_command(ctx->ifname, "INTERWORKING_SELECT auto") < 0) 712*5b9c547cSRui Paulo wpa_printf(MSG_INFO, "Failed to request wpa_supplicant to reconnect"); 713*5b9c547cSRui Paulo 714*5b9c547cSRui Paulo return DM_RESP_OK; 715*5b9c547cSRui Paulo } 716*5b9c547cSRui Paulo 717*5b9c547cSRui Paulo 718*5b9c547cSRui Paulo static int oma_dm_replace(struct hs20_osu_client *ctx, xml_node_t *replace, 719*5b9c547cSRui Paulo xml_node_t *pps, const char *pps_fname) 720*5b9c547cSRui Paulo { 721*5b9c547cSRui Paulo char *locuri, *pos; 722*5b9c547cSRui Paulo size_t fqdn_len; 723*5b9c547cSRui Paulo xml_node_t *node, *tnds, *unode, *pps_node, *parent; 724*5b9c547cSRui Paulo char *data; 725*5b9c547cSRui Paulo int use_tnds = 0; 726*5b9c547cSRui Paulo 727*5b9c547cSRui Paulo locuri = oma_dm_get_target_locuri(ctx, replace); 728*5b9c547cSRui Paulo if (locuri == NULL) 729*5b9c547cSRui Paulo return DM_RESP_BAD_REQUEST; 730*5b9c547cSRui Paulo 731*5b9c547cSRui Paulo wpa_printf(MSG_INFO, "Replace command target LocURI: %s", locuri); 732*5b9c547cSRui Paulo if (os_strncasecmp(locuri, "./Wi-Fi/", 8) != 0) { 733*5b9c547cSRui Paulo wpa_printf(MSG_INFO, "Do not allow Replace outside ./Wi-Fi"); 734*5b9c547cSRui Paulo os_free(locuri); 735*5b9c547cSRui Paulo return DM_RESP_PERMISSION_DENIED; 736*5b9c547cSRui Paulo } 737*5b9c547cSRui Paulo pos = locuri + 8; 738*5b9c547cSRui Paulo 739*5b9c547cSRui Paulo if (ctx->fqdn == NULL) { 740*5b9c547cSRui Paulo os_free(locuri); 741*5b9c547cSRui Paulo return DM_RESP_COMMAND_FAILED; 742*5b9c547cSRui Paulo } 743*5b9c547cSRui Paulo fqdn_len = os_strlen(ctx->fqdn); 744*5b9c547cSRui Paulo if (os_strncasecmp(pos, ctx->fqdn, fqdn_len) != 0 || 745*5b9c547cSRui Paulo pos[fqdn_len] != '/') { 746*5b9c547cSRui Paulo wpa_printf(MSG_INFO, "Do not allow Replace outside ./Wi-Fi/%s", 747*5b9c547cSRui Paulo ctx->fqdn); 748*5b9c547cSRui Paulo os_free(locuri); 749*5b9c547cSRui Paulo return DM_RESP_PERMISSION_DENIED; 750*5b9c547cSRui Paulo } 751*5b9c547cSRui Paulo pos += fqdn_len + 1; 752*5b9c547cSRui Paulo 753*5b9c547cSRui Paulo if (os_strncasecmp(pos, "PerProviderSubscription/", 24) != 0) { 754*5b9c547cSRui Paulo wpa_printf(MSG_INFO, 755*5b9c547cSRui Paulo "Do not allow Replace outside ./Wi-Fi/%s/PerProviderSubscription", 756*5b9c547cSRui Paulo ctx->fqdn); 757*5b9c547cSRui Paulo os_free(locuri); 758*5b9c547cSRui Paulo return DM_RESP_PERMISSION_DENIED; 759*5b9c547cSRui Paulo } 760*5b9c547cSRui Paulo pos += 24; 761*5b9c547cSRui Paulo 762*5b9c547cSRui Paulo wpa_printf(MSG_INFO, "Replace command for PPS node %s", pos); 763*5b9c547cSRui Paulo 764*5b9c547cSRui Paulo pps_node = get_node(ctx->xml, pps, pos); 765*5b9c547cSRui Paulo if (pps_node == NULL) { 766*5b9c547cSRui Paulo wpa_printf(MSG_INFO, "Specified PPS node not found"); 767*5b9c547cSRui Paulo os_free(locuri); 768*5b9c547cSRui Paulo return DM_RESP_NOT_FOUND; 769*5b9c547cSRui Paulo } 770*5b9c547cSRui Paulo 771*5b9c547cSRui Paulo node = get_node(ctx->xml, replace, "Item/Meta/Type"); 772*5b9c547cSRui Paulo if (node) { 773*5b9c547cSRui Paulo char *type; 774*5b9c547cSRui Paulo type = xml_node_get_text(ctx->xml, node); 775*5b9c547cSRui Paulo if (type == NULL) { 776*5b9c547cSRui Paulo wpa_printf(MSG_INFO, "Could not find type text"); 777*5b9c547cSRui Paulo os_free(locuri); 778*5b9c547cSRui Paulo return DM_RESP_BAD_REQUEST; 779*5b9c547cSRui Paulo } 780*5b9c547cSRui Paulo use_tnds = node && 781*5b9c547cSRui Paulo os_strstr(type, "application/vnd.syncml.dmtnds+xml"); 782*5b9c547cSRui Paulo } 783*5b9c547cSRui Paulo 784*5b9c547cSRui Paulo node = get_node(ctx->xml, replace, "Item/Data"); 785*5b9c547cSRui Paulo if (node == NULL) { 786*5b9c547cSRui Paulo wpa_printf(MSG_INFO, "No Replace/Item/Data found"); 787*5b9c547cSRui Paulo os_free(locuri); 788*5b9c547cSRui Paulo return DM_RESP_BAD_REQUEST; 789*5b9c547cSRui Paulo } 790*5b9c547cSRui Paulo 791*5b9c547cSRui Paulo data = xml_node_get_text(ctx->xml, node); 792*5b9c547cSRui Paulo if (data == NULL) { 793*5b9c547cSRui Paulo wpa_printf(MSG_INFO, "Could not get Replace/Item/Data text"); 794*5b9c547cSRui Paulo os_free(locuri); 795*5b9c547cSRui Paulo return DM_RESP_BAD_REQUEST; 796*5b9c547cSRui Paulo } 797*5b9c547cSRui Paulo 798*5b9c547cSRui Paulo wpa_printf(MSG_DEBUG, "Replace/Item/Data: %s", data); 799*5b9c547cSRui Paulo 800*5b9c547cSRui Paulo if (use_tnds) { 801*5b9c547cSRui Paulo tnds = xml_node_from_buf(ctx->xml, data); 802*5b9c547cSRui Paulo xml_node_get_text_free(ctx->xml, data); 803*5b9c547cSRui Paulo if (tnds == NULL) { 804*5b9c547cSRui Paulo wpa_printf(MSG_INFO, 805*5b9c547cSRui Paulo "Could not parse Replace/Item/Data text"); 806*5b9c547cSRui Paulo os_free(locuri); 807*5b9c547cSRui Paulo return DM_RESP_BAD_REQUEST; 808*5b9c547cSRui Paulo } 809*5b9c547cSRui Paulo 810*5b9c547cSRui Paulo unode = tnds_to_mo(ctx->xml, tnds); 811*5b9c547cSRui Paulo xml_node_free(ctx->xml, tnds); 812*5b9c547cSRui Paulo if (unode == NULL) { 813*5b9c547cSRui Paulo wpa_printf(MSG_INFO, "Could not parse TNDS text"); 814*5b9c547cSRui Paulo os_free(locuri); 815*5b9c547cSRui Paulo return DM_RESP_BAD_REQUEST; 816*5b9c547cSRui Paulo } 817*5b9c547cSRui Paulo 818*5b9c547cSRui Paulo debug_dump_node(ctx, "Parsed TNDS", unode); 819*5b9c547cSRui Paulo 820*5b9c547cSRui Paulo parent = xml_node_get_parent(ctx->xml, pps_node); 821*5b9c547cSRui Paulo xml_node_detach(ctx->xml, pps_node); 822*5b9c547cSRui Paulo xml_node_add_child(ctx->xml, parent, unode); 823*5b9c547cSRui Paulo } else { 824*5b9c547cSRui Paulo xml_node_set_text(ctx->xml, pps_node, data); 825*5b9c547cSRui Paulo xml_node_get_text_free(ctx->xml, data); 826*5b9c547cSRui Paulo } 827*5b9c547cSRui Paulo 828*5b9c547cSRui Paulo os_free(locuri); 829*5b9c547cSRui Paulo 830*5b9c547cSRui Paulo if (update_pps_file(ctx, pps_fname, pps) < 0) 831*5b9c547cSRui Paulo return DM_RESP_COMMAND_FAILED; 832*5b9c547cSRui Paulo 833*5b9c547cSRui Paulo ctx->pps_updated = 1; 834*5b9c547cSRui Paulo 835*5b9c547cSRui Paulo return DM_RESP_OK; 836*5b9c547cSRui Paulo } 837*5b9c547cSRui Paulo 838*5b9c547cSRui Paulo 839*5b9c547cSRui Paulo static int oma_dm_get(struct hs20_osu_client *ctx, xml_node_t *get, 840*5b9c547cSRui Paulo xml_node_t *pps, const char *pps_fname, char **value) 841*5b9c547cSRui Paulo { 842*5b9c547cSRui Paulo char *locuri, *pos; 843*5b9c547cSRui Paulo size_t fqdn_len; 844*5b9c547cSRui Paulo xml_node_t *pps_node; 845*5b9c547cSRui Paulo const char *name; 846*5b9c547cSRui Paulo 847*5b9c547cSRui Paulo *value = NULL; 848*5b9c547cSRui Paulo 849*5b9c547cSRui Paulo locuri = oma_dm_get_target_locuri(ctx, get); 850*5b9c547cSRui Paulo if (locuri == NULL) 851*5b9c547cSRui Paulo return DM_RESP_BAD_REQUEST; 852*5b9c547cSRui Paulo 853*5b9c547cSRui Paulo wpa_printf(MSG_INFO, "Get command target LocURI: %s", locuri); 854*5b9c547cSRui Paulo if (os_strncasecmp(locuri, "./Wi-Fi/", 8) != 0) { 855*5b9c547cSRui Paulo wpa_printf(MSG_INFO, "Do not allow Get outside ./Wi-Fi"); 856*5b9c547cSRui Paulo os_free(locuri); 857*5b9c547cSRui Paulo return DM_RESP_PERMISSION_DENIED; 858*5b9c547cSRui Paulo } 859*5b9c547cSRui Paulo pos = locuri + 8; 860*5b9c547cSRui Paulo 861*5b9c547cSRui Paulo if (ctx->fqdn == NULL) 862*5b9c547cSRui Paulo return DM_RESP_COMMAND_FAILED; 863*5b9c547cSRui Paulo fqdn_len = os_strlen(ctx->fqdn); 864*5b9c547cSRui Paulo if (os_strncasecmp(pos, ctx->fqdn, fqdn_len) != 0 || 865*5b9c547cSRui Paulo pos[fqdn_len] != '/') { 866*5b9c547cSRui Paulo wpa_printf(MSG_INFO, "Do not allow Get outside ./Wi-Fi/%s", 867*5b9c547cSRui Paulo ctx->fqdn); 868*5b9c547cSRui Paulo os_free(locuri); 869*5b9c547cSRui Paulo return DM_RESP_PERMISSION_DENIED; 870*5b9c547cSRui Paulo } 871*5b9c547cSRui Paulo pos += fqdn_len + 1; 872*5b9c547cSRui Paulo 873*5b9c547cSRui Paulo if (os_strncasecmp(pos, "PerProviderSubscription/", 24) != 0) { 874*5b9c547cSRui Paulo wpa_printf(MSG_INFO, 875*5b9c547cSRui Paulo "Do not allow Get outside ./Wi-Fi/%s/PerProviderSubscription", 876*5b9c547cSRui Paulo ctx->fqdn); 877*5b9c547cSRui Paulo os_free(locuri); 878*5b9c547cSRui Paulo return DM_RESP_PERMISSION_DENIED; 879*5b9c547cSRui Paulo } 880*5b9c547cSRui Paulo pos += 24; 881*5b9c547cSRui Paulo 882*5b9c547cSRui Paulo wpa_printf(MSG_INFO, "Get command for PPS node %s", pos); 883*5b9c547cSRui Paulo 884*5b9c547cSRui Paulo pps_node = get_node(ctx->xml, pps, pos); 885*5b9c547cSRui Paulo if (pps_node == NULL) { 886*5b9c547cSRui Paulo wpa_printf(MSG_INFO, "Specified PPS node not found"); 887*5b9c547cSRui Paulo os_free(locuri); 888*5b9c547cSRui Paulo return DM_RESP_NOT_FOUND; 889*5b9c547cSRui Paulo } 890*5b9c547cSRui Paulo 891*5b9c547cSRui Paulo name = xml_node_get_localname(ctx->xml, pps_node); 892*5b9c547cSRui Paulo wpa_printf(MSG_INFO, "Get command returned node with name '%s'", name); 893*5b9c547cSRui Paulo if (os_strcasecmp(name, "Password") == 0) { 894*5b9c547cSRui Paulo wpa_printf(MSG_INFO, "Do not allow Get for Password node"); 895*5b9c547cSRui Paulo os_free(locuri); 896*5b9c547cSRui Paulo return DM_RESP_PERMISSION_DENIED; 897*5b9c547cSRui Paulo } 898*5b9c547cSRui Paulo 899*5b9c547cSRui Paulo /* 900*5b9c547cSRui Paulo * TODO: No support for DMTNDS, so if interior node, reply with a 901*5b9c547cSRui Paulo * list of children node names in Results element. The child list type is 902*5b9c547cSRui Paulo * defined in [DMTND]. 903*5b9c547cSRui Paulo */ 904*5b9c547cSRui Paulo 905*5b9c547cSRui Paulo *value = xml_node_get_text(ctx->xml, pps_node); 906*5b9c547cSRui Paulo if (*value == NULL) 907*5b9c547cSRui Paulo return DM_RESP_COMMAND_FAILED; 908*5b9c547cSRui Paulo 909*5b9c547cSRui Paulo return DM_RESP_OK; 910*5b9c547cSRui Paulo } 911*5b9c547cSRui Paulo 912*5b9c547cSRui Paulo 913*5b9c547cSRui Paulo static int oma_dm_get_cmdid(struct hs20_osu_client *ctx, xml_node_t *node) 914*5b9c547cSRui Paulo { 915*5b9c547cSRui Paulo xml_node_t *cnode; 916*5b9c547cSRui Paulo char *str; 917*5b9c547cSRui Paulo int ret; 918*5b9c547cSRui Paulo 919*5b9c547cSRui Paulo cnode = get_node(ctx->xml, node, "CmdID"); 920*5b9c547cSRui Paulo if (cnode == NULL) 921*5b9c547cSRui Paulo return 0; 922*5b9c547cSRui Paulo 923*5b9c547cSRui Paulo str = xml_node_get_text(ctx->xml, cnode); 924*5b9c547cSRui Paulo if (str == NULL) 925*5b9c547cSRui Paulo return 0; 926*5b9c547cSRui Paulo ret = atoi(str); 927*5b9c547cSRui Paulo xml_node_get_text_free(ctx->xml, str); 928*5b9c547cSRui Paulo return ret; 929*5b9c547cSRui Paulo } 930*5b9c547cSRui Paulo 931*5b9c547cSRui Paulo 932*5b9c547cSRui Paulo static xml_node_t * oma_dm_send_recv(struct hs20_osu_client *ctx, 933*5b9c547cSRui Paulo const char *url, xml_node_t *syncml, 934*5b9c547cSRui Paulo const char *ext_hdr, 935*5b9c547cSRui Paulo const char *username, const char *password, 936*5b9c547cSRui Paulo const char *client_cert, 937*5b9c547cSRui Paulo const char *client_key) 938*5b9c547cSRui Paulo { 939*5b9c547cSRui Paulo xml_node_t *resp; 940*5b9c547cSRui Paulo char *str, *res; 941*5b9c547cSRui Paulo char *resp_uri = NULL; 942*5b9c547cSRui Paulo 943*5b9c547cSRui Paulo str = xml_node_to_str(ctx->xml, syncml); 944*5b9c547cSRui Paulo xml_node_free(ctx->xml, syncml); 945*5b9c547cSRui Paulo if (str == NULL) 946*5b9c547cSRui Paulo return NULL; 947*5b9c547cSRui Paulo 948*5b9c547cSRui Paulo wpa_printf(MSG_INFO, "Send OMA DM Package"); 949*5b9c547cSRui Paulo write_summary(ctx, "Send OMA DM Package"); 950*5b9c547cSRui Paulo os_free(ctx->server_url); 951*5b9c547cSRui Paulo ctx->server_url = os_strdup(url); 952*5b9c547cSRui Paulo res = http_post(ctx->http, url, str, "application/vnd.syncml.dm+xml", 953*5b9c547cSRui Paulo ext_hdr, ctx->ca_fname, username, password, 954*5b9c547cSRui Paulo client_cert, client_key, NULL); 955*5b9c547cSRui Paulo os_free(str); 956*5b9c547cSRui Paulo os_free(resp_uri); 957*5b9c547cSRui Paulo resp_uri = NULL; 958*5b9c547cSRui Paulo 959*5b9c547cSRui Paulo if (res == NULL) { 960*5b9c547cSRui Paulo const char *err = http_get_err(ctx->http); 961*5b9c547cSRui Paulo if (err) { 962*5b9c547cSRui Paulo wpa_printf(MSG_INFO, "HTTP error: %s", err); 963*5b9c547cSRui Paulo write_result(ctx, "HTTP error: %s", err); 964*5b9c547cSRui Paulo } else { 965*5b9c547cSRui Paulo write_summary(ctx, "Failed to send OMA DM Package"); 966*5b9c547cSRui Paulo } 967*5b9c547cSRui Paulo return NULL; 968*5b9c547cSRui Paulo } 969*5b9c547cSRui Paulo wpa_printf(MSG_DEBUG, "Server response: %s", res); 970*5b9c547cSRui Paulo 971*5b9c547cSRui Paulo wpa_printf(MSG_INFO, "Process OMA DM Package"); 972*5b9c547cSRui Paulo write_summary(ctx, "Process received OMA DM Package"); 973*5b9c547cSRui Paulo resp = xml_node_from_buf(ctx->xml, res); 974*5b9c547cSRui Paulo os_free(res); 975*5b9c547cSRui Paulo if (resp == NULL) { 976*5b9c547cSRui Paulo wpa_printf(MSG_INFO, "Failed to parse OMA DM response"); 977*5b9c547cSRui Paulo return NULL; 978*5b9c547cSRui Paulo } 979*5b9c547cSRui Paulo 980*5b9c547cSRui Paulo debug_dump_node(ctx, "OMA DM Package", resp); 981*5b9c547cSRui Paulo 982*5b9c547cSRui Paulo return resp; 983*5b9c547cSRui Paulo } 984*5b9c547cSRui Paulo 985*5b9c547cSRui Paulo 986*5b9c547cSRui Paulo static xml_node_t * oma_dm_process(struct hs20_osu_client *ctx, const char *url, 987*5b9c547cSRui Paulo xml_node_t *resp, int msgid, 988*5b9c547cSRui Paulo char **ret_resp_uri, 989*5b9c547cSRui Paulo xml_node_t *pps, const char *pps_fname) 990*5b9c547cSRui Paulo { 991*5b9c547cSRui Paulo xml_node_t *syncml, *syncbody, *hdr, *body, *child; 992*5b9c547cSRui Paulo const char *name; 993*5b9c547cSRui Paulo char *resp_uri = NULL; 994*5b9c547cSRui Paulo int server_msgid = 0; 995*5b9c547cSRui Paulo int cmdid = 0; 996*5b9c547cSRui Paulo int server_cmdid; 997*5b9c547cSRui Paulo int resp_needed = 0; 998*5b9c547cSRui Paulo char *tmp; 999*5b9c547cSRui Paulo int final = 0; 1000*5b9c547cSRui Paulo char *locuri; 1001*5b9c547cSRui Paulo 1002*5b9c547cSRui Paulo *ret_resp_uri = NULL; 1003*5b9c547cSRui Paulo 1004*5b9c547cSRui Paulo name = xml_node_get_localname(ctx->xml, resp); 1005*5b9c547cSRui Paulo if (name == NULL || os_strcasecmp(name, "SyncML") != 0) { 1006*5b9c547cSRui Paulo wpa_printf(MSG_INFO, "SyncML node not found"); 1007*5b9c547cSRui Paulo return NULL; 1008*5b9c547cSRui Paulo } 1009*5b9c547cSRui Paulo 1010*5b9c547cSRui Paulo hdr = get_node(ctx->xml, resp, "SyncHdr"); 1011*5b9c547cSRui Paulo body = get_node(ctx->xml, resp, "SyncBody"); 1012*5b9c547cSRui Paulo if (hdr == NULL || body == NULL) { 1013*5b9c547cSRui Paulo wpa_printf(MSG_INFO, "Could not find SyncHdr or SyncBody"); 1014*5b9c547cSRui Paulo return NULL; 1015*5b9c547cSRui Paulo } 1016*5b9c547cSRui Paulo 1017*5b9c547cSRui Paulo xml_node_for_each_child(ctx->xml, child, hdr) { 1018*5b9c547cSRui Paulo xml_node_for_each_check(ctx->xml, child); 1019*5b9c547cSRui Paulo name = xml_node_get_localname(ctx->xml, child); 1020*5b9c547cSRui Paulo wpa_printf(MSG_INFO, "SyncHdr %s", name); 1021*5b9c547cSRui Paulo if (os_strcasecmp(name, "RespURI") == 0) { 1022*5b9c547cSRui Paulo tmp = xml_node_get_text(ctx->xml, child); 1023*5b9c547cSRui Paulo if (tmp) 1024*5b9c547cSRui Paulo resp_uri = os_strdup(tmp); 1025*5b9c547cSRui Paulo xml_node_get_text_free(ctx->xml, tmp); 1026*5b9c547cSRui Paulo } else if (os_strcasecmp(name, "MsgID") == 0) { 1027*5b9c547cSRui Paulo tmp = xml_node_get_text(ctx->xml, child); 1028*5b9c547cSRui Paulo if (tmp) 1029*5b9c547cSRui Paulo server_msgid = atoi(tmp); 1030*5b9c547cSRui Paulo xml_node_get_text_free(ctx->xml, tmp); 1031*5b9c547cSRui Paulo } 1032*5b9c547cSRui Paulo } 1033*5b9c547cSRui Paulo 1034*5b9c547cSRui Paulo wpa_printf(MSG_INFO, "Server MsgID: %d", server_msgid); 1035*5b9c547cSRui Paulo if (resp_uri) 1036*5b9c547cSRui Paulo wpa_printf(MSG_INFO, "RespURI: %s", resp_uri); 1037*5b9c547cSRui Paulo 1038*5b9c547cSRui Paulo syncml = oma_dm_build_hdr(ctx, resp_uri ? resp_uri : url, msgid); 1039*5b9c547cSRui Paulo if (syncml == NULL) { 1040*5b9c547cSRui Paulo os_free(resp_uri); 1041*5b9c547cSRui Paulo return NULL; 1042*5b9c547cSRui Paulo } 1043*5b9c547cSRui Paulo 1044*5b9c547cSRui Paulo syncbody = xml_node_create(ctx->xml, syncml, NULL, "SyncBody"); 1045*5b9c547cSRui Paulo cmdid++; 1046*5b9c547cSRui Paulo add_status(ctx, syncbody, server_msgid, 0, cmdid, "SyncHdr", 1047*5b9c547cSRui Paulo DM_RESP_AUTH_ACCEPTED, NULL); 1048*5b9c547cSRui Paulo 1049*5b9c547cSRui Paulo xml_node_for_each_child(ctx->xml, child, body) { 1050*5b9c547cSRui Paulo xml_node_for_each_check(ctx->xml, child); 1051*5b9c547cSRui Paulo server_cmdid = oma_dm_get_cmdid(ctx, child); 1052*5b9c547cSRui Paulo name = xml_node_get_localname(ctx->xml, child); 1053*5b9c547cSRui Paulo wpa_printf(MSG_INFO, "SyncBody CmdID=%d - %s", 1054*5b9c547cSRui Paulo server_cmdid, name); 1055*5b9c547cSRui Paulo if (os_strcasecmp(name, "Exec") == 0) { 1056*5b9c547cSRui Paulo int res = oma_dm_exec(ctx, child); 1057*5b9c547cSRui Paulo cmdid++; 1058*5b9c547cSRui Paulo locuri = oma_dm_get_target_locuri(ctx, child); 1059*5b9c547cSRui Paulo if (locuri == NULL) 1060*5b9c547cSRui Paulo res = DM_RESP_BAD_REQUEST; 1061*5b9c547cSRui Paulo add_status(ctx, syncbody, server_msgid, server_cmdid, 1062*5b9c547cSRui Paulo cmdid, name, res, locuri); 1063*5b9c547cSRui Paulo os_free(locuri); 1064*5b9c547cSRui Paulo resp_needed = 1; 1065*5b9c547cSRui Paulo } else if (os_strcasecmp(name, "Add") == 0) { 1066*5b9c547cSRui Paulo int res = oma_dm_add(ctx, child, pps, pps_fname); 1067*5b9c547cSRui Paulo cmdid++; 1068*5b9c547cSRui Paulo locuri = oma_dm_get_target_locuri(ctx, child); 1069*5b9c547cSRui Paulo if (locuri == NULL) 1070*5b9c547cSRui Paulo res = DM_RESP_BAD_REQUEST; 1071*5b9c547cSRui Paulo add_status(ctx, syncbody, server_msgid, server_cmdid, 1072*5b9c547cSRui Paulo cmdid, name, res, locuri); 1073*5b9c547cSRui Paulo os_free(locuri); 1074*5b9c547cSRui Paulo resp_needed = 1; 1075*5b9c547cSRui Paulo } else if (os_strcasecmp(name, "Replace") == 0) { 1076*5b9c547cSRui Paulo int res; 1077*5b9c547cSRui Paulo res = oma_dm_replace(ctx, child, pps, pps_fname); 1078*5b9c547cSRui Paulo cmdid++; 1079*5b9c547cSRui Paulo locuri = oma_dm_get_target_locuri(ctx, child); 1080*5b9c547cSRui Paulo if (locuri == NULL) 1081*5b9c547cSRui Paulo res = DM_RESP_BAD_REQUEST; 1082*5b9c547cSRui Paulo add_status(ctx, syncbody, server_msgid, server_cmdid, 1083*5b9c547cSRui Paulo cmdid, name, res, locuri); 1084*5b9c547cSRui Paulo os_free(locuri); 1085*5b9c547cSRui Paulo resp_needed = 1; 1086*5b9c547cSRui Paulo } else if (os_strcasecmp(name, "Status") == 0) { 1087*5b9c547cSRui Paulo /* TODO: Verify success */ 1088*5b9c547cSRui Paulo } else if (os_strcasecmp(name, "Get") == 0) { 1089*5b9c547cSRui Paulo int res; 1090*5b9c547cSRui Paulo char *value; 1091*5b9c547cSRui Paulo res = oma_dm_get(ctx, child, pps, pps_fname, &value); 1092*5b9c547cSRui Paulo cmdid++; 1093*5b9c547cSRui Paulo locuri = oma_dm_get_target_locuri(ctx, child); 1094*5b9c547cSRui Paulo if (locuri == NULL) 1095*5b9c547cSRui Paulo res = DM_RESP_BAD_REQUEST; 1096*5b9c547cSRui Paulo add_status(ctx, syncbody, server_msgid, server_cmdid, 1097*5b9c547cSRui Paulo cmdid, name, res, locuri); 1098*5b9c547cSRui Paulo if (res == DM_RESP_OK && value) { 1099*5b9c547cSRui Paulo cmdid++; 1100*5b9c547cSRui Paulo add_results(ctx, syncbody, server_msgid, 1101*5b9c547cSRui Paulo server_cmdid, cmdid, locuri, value); 1102*5b9c547cSRui Paulo } 1103*5b9c547cSRui Paulo os_free(locuri); 1104*5b9c547cSRui Paulo xml_node_get_text_free(ctx->xml, value); 1105*5b9c547cSRui Paulo resp_needed = 1; 1106*5b9c547cSRui Paulo #if 0 /* TODO: MUST support */ 1107*5b9c547cSRui Paulo } else if (os_strcasecmp(name, "Delete") == 0) { 1108*5b9c547cSRui Paulo #endif 1109*5b9c547cSRui Paulo #if 0 /* TODO: MUST support */ 1110*5b9c547cSRui Paulo } else if (os_strcasecmp(name, "Sequence") == 0) { 1111*5b9c547cSRui Paulo #endif 1112*5b9c547cSRui Paulo } else if (os_strcasecmp(name, "Final") == 0) { 1113*5b9c547cSRui Paulo final = 1; 1114*5b9c547cSRui Paulo break; 1115*5b9c547cSRui Paulo } else { 1116*5b9c547cSRui Paulo locuri = oma_dm_get_target_locuri(ctx, child); 1117*5b9c547cSRui Paulo add_status(ctx, syncbody, server_msgid, server_cmdid, 1118*5b9c547cSRui Paulo cmdid, name, DM_RESP_COMMAND_NOT_IMPLEMENTED, 1119*5b9c547cSRui Paulo locuri); 1120*5b9c547cSRui Paulo os_free(locuri); 1121*5b9c547cSRui Paulo resp_needed = 1; 1122*5b9c547cSRui Paulo } 1123*5b9c547cSRui Paulo } 1124*5b9c547cSRui Paulo 1125*5b9c547cSRui Paulo if (!final) { 1126*5b9c547cSRui Paulo wpa_printf(MSG_INFO, "Final node not found"); 1127*5b9c547cSRui Paulo xml_node_free(ctx->xml, syncml); 1128*5b9c547cSRui Paulo os_free(resp_uri); 1129*5b9c547cSRui Paulo return NULL; 1130*5b9c547cSRui Paulo } 1131*5b9c547cSRui Paulo 1132*5b9c547cSRui Paulo if (!resp_needed) { 1133*5b9c547cSRui Paulo wpa_printf(MSG_INFO, "Exchange completed - no response needed"); 1134*5b9c547cSRui Paulo xml_node_free(ctx->xml, syncml); 1135*5b9c547cSRui Paulo os_free(resp_uri); 1136*5b9c547cSRui Paulo return NULL; 1137*5b9c547cSRui Paulo } 1138*5b9c547cSRui Paulo 1139*5b9c547cSRui Paulo xml_node_create(ctx->xml, syncbody, NULL, "Final"); 1140*5b9c547cSRui Paulo 1141*5b9c547cSRui Paulo debug_dump_node(ctx, "OMA-DM Package 3", syncml); 1142*5b9c547cSRui Paulo 1143*5b9c547cSRui Paulo *ret_resp_uri = resp_uri; 1144*5b9c547cSRui Paulo return syncml; 1145*5b9c547cSRui Paulo } 1146*5b9c547cSRui Paulo 1147*5b9c547cSRui Paulo 1148*5b9c547cSRui Paulo int cmd_oma_dm_prov(struct hs20_osu_client *ctx, const char *url) 1149*5b9c547cSRui Paulo { 1150*5b9c547cSRui Paulo xml_node_t *syncml, *resp; 1151*5b9c547cSRui Paulo char *resp_uri = NULL; 1152*5b9c547cSRui Paulo int msgid = 0; 1153*5b9c547cSRui Paulo 1154*5b9c547cSRui Paulo if (url == NULL) { 1155*5b9c547cSRui Paulo wpa_printf(MSG_INFO, "Invalid prov command (missing URL)"); 1156*5b9c547cSRui Paulo return -1; 1157*5b9c547cSRui Paulo } 1158*5b9c547cSRui Paulo 1159*5b9c547cSRui Paulo wpa_printf(MSG_INFO, "OMA-DM credential provisioning requested"); 1160*5b9c547cSRui Paulo write_summary(ctx, "OMA-DM credential provisioning"); 1161*5b9c547cSRui Paulo 1162*5b9c547cSRui Paulo msgid++; 1163*5b9c547cSRui Paulo syncml = build_oma_dm_1_sub_reg(ctx, url, msgid); 1164*5b9c547cSRui Paulo if (syncml == NULL) 1165*5b9c547cSRui Paulo return -1; 1166*5b9c547cSRui Paulo 1167*5b9c547cSRui Paulo while (syncml) { 1168*5b9c547cSRui Paulo resp = oma_dm_send_recv(ctx, resp_uri ? resp_uri : url, 1169*5b9c547cSRui Paulo syncml, NULL, NULL, NULL, NULL, NULL); 1170*5b9c547cSRui Paulo if (resp == NULL) 1171*5b9c547cSRui Paulo return -1; 1172*5b9c547cSRui Paulo 1173*5b9c547cSRui Paulo msgid++; 1174*5b9c547cSRui Paulo syncml = oma_dm_process(ctx, url, resp, msgid, &resp_uri, 1175*5b9c547cSRui Paulo NULL, NULL); 1176*5b9c547cSRui Paulo xml_node_free(ctx->xml, resp); 1177*5b9c547cSRui Paulo } 1178*5b9c547cSRui Paulo 1179*5b9c547cSRui Paulo os_free(resp_uri); 1180*5b9c547cSRui Paulo 1181*5b9c547cSRui Paulo return ctx->pps_cred_set ? 0 : -1; 1182*5b9c547cSRui Paulo } 1183*5b9c547cSRui Paulo 1184*5b9c547cSRui Paulo 1185*5b9c547cSRui Paulo int cmd_oma_dm_sim_prov(struct hs20_osu_client *ctx, const char *url) 1186*5b9c547cSRui Paulo { 1187*5b9c547cSRui Paulo xml_node_t *syncml, *resp; 1188*5b9c547cSRui Paulo char *resp_uri = NULL; 1189*5b9c547cSRui Paulo int msgid = 0; 1190*5b9c547cSRui Paulo 1191*5b9c547cSRui Paulo if (url == NULL) { 1192*5b9c547cSRui Paulo wpa_printf(MSG_INFO, "Invalid prov command (missing URL)"); 1193*5b9c547cSRui Paulo return -1; 1194*5b9c547cSRui Paulo } 1195*5b9c547cSRui Paulo 1196*5b9c547cSRui Paulo wpa_printf(MSG_INFO, "OMA-DM SIM provisioning requested"); 1197*5b9c547cSRui Paulo ctx->no_reconnect = 2; 1198*5b9c547cSRui Paulo 1199*5b9c547cSRui Paulo wpa_printf(MSG_INFO, "Wait for IP address before starting SIM provisioning"); 1200*5b9c547cSRui Paulo write_summary(ctx, "Wait for IP address before starting SIM provisioning"); 1201*5b9c547cSRui Paulo 1202*5b9c547cSRui Paulo if (wait_ip_addr(ctx->ifname, 15) < 0) { 1203*5b9c547cSRui Paulo wpa_printf(MSG_INFO, "Could not get IP address for WLAN - try connection anyway"); 1204*5b9c547cSRui Paulo } 1205*5b9c547cSRui Paulo write_summary(ctx, "OMA-DM SIM provisioning"); 1206*5b9c547cSRui Paulo 1207*5b9c547cSRui Paulo msgid++; 1208*5b9c547cSRui Paulo syncml = build_oma_dm_1_sub_prov(ctx, url, msgid); 1209*5b9c547cSRui Paulo if (syncml == NULL) 1210*5b9c547cSRui Paulo return -1; 1211*5b9c547cSRui Paulo 1212*5b9c547cSRui Paulo while (syncml) { 1213*5b9c547cSRui Paulo resp = oma_dm_send_recv(ctx, resp_uri ? resp_uri : url, 1214*5b9c547cSRui Paulo syncml, NULL, NULL, NULL, NULL, NULL); 1215*5b9c547cSRui Paulo if (resp == NULL) 1216*5b9c547cSRui Paulo return -1; 1217*5b9c547cSRui Paulo 1218*5b9c547cSRui Paulo msgid++; 1219*5b9c547cSRui Paulo syncml = oma_dm_process(ctx, url, resp, msgid, &resp_uri, 1220*5b9c547cSRui Paulo NULL, NULL); 1221*5b9c547cSRui Paulo xml_node_free(ctx->xml, resp); 1222*5b9c547cSRui Paulo } 1223*5b9c547cSRui Paulo 1224*5b9c547cSRui Paulo os_free(resp_uri); 1225*5b9c547cSRui Paulo 1226*5b9c547cSRui Paulo if (ctx->pps_cred_set) { 1227*5b9c547cSRui Paulo wpa_printf(MSG_INFO, "Updating wpa_supplicant credentials"); 1228*5b9c547cSRui Paulo cmd_set_pps(ctx, ctx->pps_fname); 1229*5b9c547cSRui Paulo 1230*5b9c547cSRui Paulo wpa_printf(MSG_INFO, "Requesting reconnection with updated configuration"); 1231*5b9c547cSRui Paulo write_summary(ctx, "Requesting reconnection with updated configuration"); 1232*5b9c547cSRui Paulo if (wpa_command(ctx->ifname, "INTERWORKING_SELECT auto") < 0) { 1233*5b9c547cSRui Paulo wpa_printf(MSG_INFO, "Failed to request wpa_supplicant to reconnect"); 1234*5b9c547cSRui Paulo write_summary(ctx, "Failed to request wpa_supplicant to reconnect"); 1235*5b9c547cSRui Paulo return -1; 1236*5b9c547cSRui Paulo } 1237*5b9c547cSRui Paulo } 1238*5b9c547cSRui Paulo 1239*5b9c547cSRui Paulo return ctx->pps_cred_set ? 0 : -1; 1240*5b9c547cSRui Paulo } 1241*5b9c547cSRui Paulo 1242*5b9c547cSRui Paulo 1243*5b9c547cSRui Paulo void oma_dm_pol_upd(struct hs20_osu_client *ctx, const char *address, 1244*5b9c547cSRui Paulo const char *pps_fname, 1245*5b9c547cSRui Paulo const char *client_cert, const char *client_key, 1246*5b9c547cSRui Paulo const char *cred_username, const char *cred_password, 1247*5b9c547cSRui Paulo xml_node_t *pps) 1248*5b9c547cSRui Paulo { 1249*5b9c547cSRui Paulo xml_node_t *syncml, *resp; 1250*5b9c547cSRui Paulo char *resp_uri = NULL; 1251*5b9c547cSRui Paulo int msgid = 0; 1252*5b9c547cSRui Paulo 1253*5b9c547cSRui Paulo wpa_printf(MSG_INFO, "OMA-DM policy update"); 1254*5b9c547cSRui Paulo write_summary(ctx, "OMA-DM policy update"); 1255*5b9c547cSRui Paulo 1256*5b9c547cSRui Paulo msgid++; 1257*5b9c547cSRui Paulo syncml = build_oma_dm_1_pol_upd(ctx, address, msgid); 1258*5b9c547cSRui Paulo if (syncml == NULL) 1259*5b9c547cSRui Paulo return; 1260*5b9c547cSRui Paulo 1261*5b9c547cSRui Paulo while (syncml) { 1262*5b9c547cSRui Paulo resp = oma_dm_send_recv(ctx, resp_uri ? resp_uri : address, 1263*5b9c547cSRui Paulo syncml, NULL, cred_username, 1264*5b9c547cSRui Paulo cred_password, client_cert, client_key); 1265*5b9c547cSRui Paulo if (resp == NULL) 1266*5b9c547cSRui Paulo return; 1267*5b9c547cSRui Paulo 1268*5b9c547cSRui Paulo msgid++; 1269*5b9c547cSRui Paulo syncml = oma_dm_process(ctx, address, resp, msgid, &resp_uri, 1270*5b9c547cSRui Paulo pps, pps_fname); 1271*5b9c547cSRui Paulo xml_node_free(ctx->xml, resp); 1272*5b9c547cSRui Paulo } 1273*5b9c547cSRui Paulo 1274*5b9c547cSRui Paulo os_free(resp_uri); 1275*5b9c547cSRui Paulo 1276*5b9c547cSRui Paulo if (ctx->pps_updated) { 1277*5b9c547cSRui Paulo wpa_printf(MSG_INFO, "Update wpa_supplicant credential based on updated PPS MO"); 1278*5b9c547cSRui Paulo write_summary(ctx, "Update wpa_supplicant credential based on updated PPS MO and request connection"); 1279*5b9c547cSRui Paulo cmd_set_pps(ctx, pps_fname); 1280*5b9c547cSRui Paulo if (wpa_command(ctx->ifname, "INTERWORKING_SELECT auto") < 0) { 1281*5b9c547cSRui Paulo wpa_printf(MSG_INFO, 1282*5b9c547cSRui Paulo "Failed to request wpa_supplicant to reconnect"); 1283*5b9c547cSRui Paulo write_summary(ctx, 1284*5b9c547cSRui Paulo "Failed to request wpa_supplicant to reconnect"); 1285*5b9c547cSRui Paulo } 1286*5b9c547cSRui Paulo } 1287*5b9c547cSRui Paulo } 1288*5b9c547cSRui Paulo 1289*5b9c547cSRui Paulo 1290*5b9c547cSRui Paulo void oma_dm_sub_rem(struct hs20_osu_client *ctx, const char *address, 1291*5b9c547cSRui Paulo const char *pps_fname, 1292*5b9c547cSRui Paulo const char *client_cert, const char *client_key, 1293*5b9c547cSRui Paulo const char *cred_username, const char *cred_password, 1294*5b9c547cSRui Paulo xml_node_t *pps) 1295*5b9c547cSRui Paulo { 1296*5b9c547cSRui Paulo xml_node_t *syncml, *resp; 1297*5b9c547cSRui Paulo char *resp_uri = NULL; 1298*5b9c547cSRui Paulo int msgid = 0; 1299*5b9c547cSRui Paulo 1300*5b9c547cSRui Paulo wpa_printf(MSG_INFO, "OMA-DM subscription remediation"); 1301*5b9c547cSRui Paulo write_summary(ctx, "OMA-DM subscription remediation"); 1302*5b9c547cSRui Paulo 1303*5b9c547cSRui Paulo msgid++; 1304*5b9c547cSRui Paulo syncml = build_oma_dm_1_sub_rem(ctx, address, msgid); 1305*5b9c547cSRui Paulo if (syncml == NULL) 1306*5b9c547cSRui Paulo return; 1307*5b9c547cSRui Paulo 1308*5b9c547cSRui Paulo while (syncml) { 1309*5b9c547cSRui Paulo resp = oma_dm_send_recv(ctx, resp_uri ? resp_uri : address, 1310*5b9c547cSRui Paulo syncml, NULL, cred_username, 1311*5b9c547cSRui Paulo cred_password, client_cert, client_key); 1312*5b9c547cSRui Paulo if (resp == NULL) 1313*5b9c547cSRui Paulo return; 1314*5b9c547cSRui Paulo 1315*5b9c547cSRui Paulo msgid++; 1316*5b9c547cSRui Paulo syncml = oma_dm_process(ctx, address, resp, msgid, &resp_uri, 1317*5b9c547cSRui Paulo pps, pps_fname); 1318*5b9c547cSRui Paulo xml_node_free(ctx->xml, resp); 1319*5b9c547cSRui Paulo } 1320*5b9c547cSRui Paulo 1321*5b9c547cSRui Paulo os_free(resp_uri); 1322*5b9c547cSRui Paulo 1323*5b9c547cSRui Paulo wpa_printf(MSG_INFO, "Update wpa_supplicant credential based on updated PPS MO and request reconnection"); 1324*5b9c547cSRui Paulo write_summary(ctx, "Update wpa_supplicant credential based on updated PPS MO and request reconnection"); 1325*5b9c547cSRui Paulo cmd_set_pps(ctx, pps_fname); 1326*5b9c547cSRui Paulo if (wpa_command(ctx->ifname, "INTERWORKING_SELECT auto") < 0) { 1327*5b9c547cSRui Paulo wpa_printf(MSG_INFO, "Failed to request wpa_supplicant to reconnect"); 1328*5b9c547cSRui Paulo write_summary(ctx, "Failed to request wpa_supplicant to reconnect"); 1329*5b9c547cSRui Paulo } 1330*5b9c547cSRui Paulo } 1331*5b9c547cSRui Paulo 1332*5b9c547cSRui Paulo 1333*5b9c547cSRui Paulo void cmd_oma_dm_add(struct hs20_osu_client *ctx, const char *pps_fname, 1334*5b9c547cSRui Paulo const char *add_fname) 1335*5b9c547cSRui Paulo { 1336*5b9c547cSRui Paulo xml_node_t *pps, *add; 1337*5b9c547cSRui Paulo int res; 1338*5b9c547cSRui Paulo 1339*5b9c547cSRui Paulo ctx->fqdn = os_strdup("wi-fi.org"); 1340*5b9c547cSRui Paulo 1341*5b9c547cSRui Paulo pps = node_from_file(ctx->xml, pps_fname); 1342*5b9c547cSRui Paulo if (pps == NULL) { 1343*5b9c547cSRui Paulo wpa_printf(MSG_INFO, "PPS file %s could not be parsed", 1344*5b9c547cSRui Paulo pps_fname); 1345*5b9c547cSRui Paulo return; 1346*5b9c547cSRui Paulo } 1347*5b9c547cSRui Paulo 1348*5b9c547cSRui Paulo add = node_from_file(ctx->xml, add_fname); 1349*5b9c547cSRui Paulo if (add == NULL) { 1350*5b9c547cSRui Paulo wpa_printf(MSG_INFO, "Add file %s could not be parsed", 1351*5b9c547cSRui Paulo add_fname); 1352*5b9c547cSRui Paulo xml_node_free(ctx->xml, pps); 1353*5b9c547cSRui Paulo return; 1354*5b9c547cSRui Paulo } 1355*5b9c547cSRui Paulo 1356*5b9c547cSRui Paulo res = oma_dm_add(ctx, add, pps, pps_fname); 1357*5b9c547cSRui Paulo wpa_printf(MSG_INFO, "oma_dm_add --> %d", res); 1358*5b9c547cSRui Paulo 1359*5b9c547cSRui Paulo xml_node_free(ctx->xml, pps); 1360*5b9c547cSRui Paulo xml_node_free(ctx->xml, add); 1361*5b9c547cSRui Paulo } 1362*5b9c547cSRui Paulo 1363*5b9c547cSRui Paulo 1364*5b9c547cSRui Paulo void cmd_oma_dm_replace(struct hs20_osu_client *ctx, const char *pps_fname, 1365*5b9c547cSRui Paulo const char *replace_fname) 1366*5b9c547cSRui Paulo { 1367*5b9c547cSRui Paulo xml_node_t *pps, *replace; 1368*5b9c547cSRui Paulo int res; 1369*5b9c547cSRui Paulo 1370*5b9c547cSRui Paulo ctx->fqdn = os_strdup("wi-fi.org"); 1371*5b9c547cSRui Paulo 1372*5b9c547cSRui Paulo pps = node_from_file(ctx->xml, pps_fname); 1373*5b9c547cSRui Paulo if (pps == NULL) { 1374*5b9c547cSRui Paulo wpa_printf(MSG_INFO, "PPS file %s could not be parsed", 1375*5b9c547cSRui Paulo pps_fname); 1376*5b9c547cSRui Paulo return; 1377*5b9c547cSRui Paulo } 1378*5b9c547cSRui Paulo 1379*5b9c547cSRui Paulo replace = node_from_file(ctx->xml, replace_fname); 1380*5b9c547cSRui Paulo if (replace == NULL) { 1381*5b9c547cSRui Paulo wpa_printf(MSG_INFO, "Replace file %s could not be parsed", 1382*5b9c547cSRui Paulo replace_fname); 1383*5b9c547cSRui Paulo xml_node_free(ctx->xml, pps); 1384*5b9c547cSRui Paulo return; 1385*5b9c547cSRui Paulo } 1386*5b9c547cSRui Paulo 1387*5b9c547cSRui Paulo res = oma_dm_replace(ctx, replace, pps, pps_fname); 1388*5b9c547cSRui Paulo wpa_printf(MSG_INFO, "oma_dm_replace --> %d", res); 1389*5b9c547cSRui Paulo 1390*5b9c547cSRui Paulo xml_node_free(ctx->xml, pps); 1391*5b9c547cSRui Paulo xml_node_free(ctx->xml, replace); 1392*5b9c547cSRui Paulo } 1393