oma_dm_client.c 36 KB

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