dbus_dict_helpers.c 31 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132
  1. /*
  2. * WPA Supplicant / dbus-based control interface
  3. * Copyright (c) 2006, Dan Williams <dcbw@redhat.com> and Red Hat, 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 <dbus/dbus.h>
  10. #include "common.h"
  11. #include "wpabuf.h"
  12. #include "dbus_dict_helpers.h"
  13. /**
  14. * Start a dict in a dbus message. Should be paired with a call to
  15. * wpa_dbus_dict_close_write().
  16. *
  17. * @param iter A valid dbus message iterator
  18. * @param iter_dict (out) A dict iterator to pass to further dict functions
  19. * @return TRUE on success, FALSE on failure
  20. *
  21. */
  22. dbus_bool_t wpa_dbus_dict_open_write(DBusMessageIter *iter,
  23. DBusMessageIter *iter_dict)
  24. {
  25. dbus_bool_t result;
  26. if (!iter || !iter_dict)
  27. return FALSE;
  28. result = dbus_message_iter_open_container(
  29. iter,
  30. DBUS_TYPE_ARRAY,
  31. DBUS_DICT_ENTRY_BEGIN_CHAR_AS_STRING
  32. DBUS_TYPE_STRING_AS_STRING
  33. DBUS_TYPE_VARIANT_AS_STRING
  34. DBUS_DICT_ENTRY_END_CHAR_AS_STRING,
  35. iter_dict);
  36. return result;
  37. }
  38. /**
  39. * End a dict element in a dbus message. Should be paired with
  40. * a call to wpa_dbus_dict_open_write().
  41. *
  42. * @param iter valid dbus message iterator, same as passed to
  43. * wpa_dbus_dict_open_write()
  44. * @param iter_dict a dbus dict iterator returned from
  45. * wpa_dbus_dict_open_write()
  46. * @return TRUE on success, FALSE on failure
  47. *
  48. */
  49. dbus_bool_t wpa_dbus_dict_close_write(DBusMessageIter *iter,
  50. DBusMessageIter *iter_dict)
  51. {
  52. if (!iter || !iter_dict)
  53. return FALSE;
  54. return dbus_message_iter_close_container(iter, iter_dict);
  55. }
  56. const char * wpa_dbus_type_as_string(const int type)
  57. {
  58. switch (type) {
  59. case DBUS_TYPE_BYTE:
  60. return DBUS_TYPE_BYTE_AS_STRING;
  61. case DBUS_TYPE_BOOLEAN:
  62. return DBUS_TYPE_BOOLEAN_AS_STRING;
  63. case DBUS_TYPE_INT16:
  64. return DBUS_TYPE_INT16_AS_STRING;
  65. case DBUS_TYPE_UINT16:
  66. return DBUS_TYPE_UINT16_AS_STRING;
  67. case DBUS_TYPE_INT32:
  68. return DBUS_TYPE_INT32_AS_STRING;
  69. case DBUS_TYPE_UINT32:
  70. return DBUS_TYPE_UINT32_AS_STRING;
  71. case DBUS_TYPE_INT64:
  72. return DBUS_TYPE_INT64_AS_STRING;
  73. case DBUS_TYPE_UINT64:
  74. return DBUS_TYPE_UINT64_AS_STRING;
  75. case DBUS_TYPE_DOUBLE:
  76. return DBUS_TYPE_DOUBLE_AS_STRING;
  77. case DBUS_TYPE_STRING:
  78. return DBUS_TYPE_STRING_AS_STRING;
  79. case DBUS_TYPE_OBJECT_PATH:
  80. return DBUS_TYPE_OBJECT_PATH_AS_STRING;
  81. case DBUS_TYPE_ARRAY:
  82. return DBUS_TYPE_ARRAY_AS_STRING;
  83. default:
  84. return NULL;
  85. }
  86. }
  87. static dbus_bool_t _wpa_dbus_add_dict_entry_start(
  88. DBusMessageIter *iter_dict, DBusMessageIter *iter_dict_entry,
  89. const char *key, const int value_type)
  90. {
  91. if (!dbus_message_iter_open_container(iter_dict,
  92. DBUS_TYPE_DICT_ENTRY, NULL,
  93. iter_dict_entry))
  94. return FALSE;
  95. return dbus_message_iter_append_basic(iter_dict_entry, DBUS_TYPE_STRING,
  96. &key);
  97. }
  98. static dbus_bool_t _wpa_dbus_add_dict_entry_end(
  99. DBusMessageIter *iter_dict, DBusMessageIter *iter_dict_entry,
  100. DBusMessageIter *iter_dict_val)
  101. {
  102. if (!dbus_message_iter_close_container(iter_dict_entry, iter_dict_val))
  103. return FALSE;
  104. return dbus_message_iter_close_container(iter_dict, iter_dict_entry);
  105. }
  106. static dbus_bool_t _wpa_dbus_add_dict_entry_basic(DBusMessageIter *iter_dict,
  107. const char *key,
  108. const int value_type,
  109. const void *value)
  110. {
  111. DBusMessageIter iter_dict_entry, iter_dict_val;
  112. const char *type_as_string = NULL;
  113. if (key == NULL)
  114. return FALSE;
  115. type_as_string = wpa_dbus_type_as_string(value_type);
  116. if (!type_as_string)
  117. return FALSE;
  118. if (!_wpa_dbus_add_dict_entry_start(iter_dict, &iter_dict_entry,
  119. key, value_type) ||
  120. !dbus_message_iter_open_container(&iter_dict_entry,
  121. DBUS_TYPE_VARIANT,
  122. type_as_string, &iter_dict_val) ||
  123. !dbus_message_iter_append_basic(&iter_dict_val, value_type, value))
  124. return FALSE;
  125. return _wpa_dbus_add_dict_entry_end(iter_dict, &iter_dict_entry,
  126. &iter_dict_val);
  127. }
  128. static dbus_bool_t _wpa_dbus_add_dict_entry_byte_array(
  129. DBusMessageIter *iter_dict, const char *key,
  130. const char *value, const dbus_uint32_t value_len)
  131. {
  132. DBusMessageIter iter_dict_entry, iter_dict_val, iter_array;
  133. dbus_uint32_t i;
  134. if (!_wpa_dbus_add_dict_entry_start(iter_dict, &iter_dict_entry,
  135. key, DBUS_TYPE_ARRAY) ||
  136. !dbus_message_iter_open_container(&iter_dict_entry,
  137. DBUS_TYPE_VARIANT,
  138. DBUS_TYPE_ARRAY_AS_STRING
  139. DBUS_TYPE_BYTE_AS_STRING,
  140. &iter_dict_val) ||
  141. !dbus_message_iter_open_container(&iter_dict_val, DBUS_TYPE_ARRAY,
  142. DBUS_TYPE_BYTE_AS_STRING,
  143. &iter_array))
  144. return FALSE;
  145. for (i = 0; i < value_len; i++) {
  146. if (!dbus_message_iter_append_basic(&iter_array,
  147. DBUS_TYPE_BYTE,
  148. &(value[i])))
  149. return FALSE;
  150. }
  151. if (!dbus_message_iter_close_container(&iter_dict_val, &iter_array))
  152. return FALSE;
  153. return _wpa_dbus_add_dict_entry_end(iter_dict, &iter_dict_entry,
  154. &iter_dict_val);
  155. }
  156. /**
  157. * Add a string entry to the dict.
  158. *
  159. * @param iter_dict A valid DBusMessageIter returned from
  160. * wpa_dbus_dict_open_write()
  161. * @param key The key of the dict item
  162. * @param value The string value
  163. * @return TRUE on success, FALSE on failure
  164. *
  165. */
  166. dbus_bool_t wpa_dbus_dict_append_string(DBusMessageIter *iter_dict,
  167. const char *key, const char *value)
  168. {
  169. if (!value)
  170. return FALSE;
  171. return _wpa_dbus_add_dict_entry_basic(iter_dict, key, DBUS_TYPE_STRING,
  172. &value);
  173. }
  174. /**
  175. * Add a byte entry to the dict.
  176. *
  177. * @param iter_dict A valid DBusMessageIter returned from
  178. * wpa_dbus_dict_open_write()
  179. * @param key The key of the dict item
  180. * @param value The byte value
  181. * @return TRUE on success, FALSE on failure
  182. *
  183. */
  184. dbus_bool_t wpa_dbus_dict_append_byte(DBusMessageIter *iter_dict,
  185. const char *key, const char value)
  186. {
  187. return _wpa_dbus_add_dict_entry_basic(iter_dict, key, DBUS_TYPE_BYTE,
  188. &value);
  189. }
  190. /**
  191. * Add a boolean entry to the dict.
  192. *
  193. * @param iter_dict A valid DBusMessageIter returned from
  194. * wpa_dbus_dict_open_write()
  195. * @param key The key of the dict item
  196. * @param value The boolean value
  197. * @return TRUE on success, FALSE on failure
  198. *
  199. */
  200. dbus_bool_t wpa_dbus_dict_append_bool(DBusMessageIter *iter_dict,
  201. const char *key, const dbus_bool_t value)
  202. {
  203. return _wpa_dbus_add_dict_entry_basic(iter_dict, key,
  204. DBUS_TYPE_BOOLEAN, &value);
  205. }
  206. /**
  207. * Add a 16-bit signed integer entry to the dict.
  208. *
  209. * @param iter_dict A valid DBusMessageIter returned from
  210. * wpa_dbus_dict_open_write()
  211. * @param key The key of the dict item
  212. * @param value The 16-bit signed integer value
  213. * @return TRUE on success, FALSE on failure
  214. *
  215. */
  216. dbus_bool_t wpa_dbus_dict_append_int16(DBusMessageIter *iter_dict,
  217. const char *key,
  218. const dbus_int16_t value)
  219. {
  220. return _wpa_dbus_add_dict_entry_basic(iter_dict, key, DBUS_TYPE_INT16,
  221. &value);
  222. }
  223. /**
  224. * Add a 16-bit unsigned integer entry to the dict.
  225. *
  226. * @param iter_dict A valid DBusMessageIter returned from
  227. * wpa_dbus_dict_open_write()
  228. * @param key The key of the dict item
  229. * @param value The 16-bit unsigned integer value
  230. * @return TRUE on success, FALSE on failure
  231. *
  232. */
  233. dbus_bool_t wpa_dbus_dict_append_uint16(DBusMessageIter *iter_dict,
  234. const char *key,
  235. const dbus_uint16_t value)
  236. {
  237. return _wpa_dbus_add_dict_entry_basic(iter_dict, key, DBUS_TYPE_UINT16,
  238. &value);
  239. }
  240. /**
  241. * Add a 32-bit signed integer to the dict.
  242. *
  243. * @param iter_dict A valid DBusMessageIter returned from
  244. * wpa_dbus_dict_open_write()
  245. * @param key The key of the dict item
  246. * @param value The 32-bit signed integer value
  247. * @return TRUE on success, FALSE on failure
  248. *
  249. */
  250. dbus_bool_t wpa_dbus_dict_append_int32(DBusMessageIter *iter_dict,
  251. const char *key,
  252. const dbus_int32_t value)
  253. {
  254. return _wpa_dbus_add_dict_entry_basic(iter_dict, key, DBUS_TYPE_INT32,
  255. &value);
  256. }
  257. /**
  258. * Add a 32-bit unsigned integer entry to the dict.
  259. *
  260. * @param iter_dict A valid DBusMessageIter returned from
  261. * wpa_dbus_dict_open_write()
  262. * @param key The key of the dict item
  263. * @param value The 32-bit unsigned integer value
  264. * @return TRUE on success, FALSE on failure
  265. *
  266. */
  267. dbus_bool_t wpa_dbus_dict_append_uint32(DBusMessageIter *iter_dict,
  268. const char *key,
  269. const dbus_uint32_t value)
  270. {
  271. return _wpa_dbus_add_dict_entry_basic(iter_dict, key, DBUS_TYPE_UINT32,
  272. &value);
  273. }
  274. /**
  275. * Add a 64-bit integer entry to the dict.
  276. *
  277. * @param iter_dict A valid DBusMessageIter returned from
  278. * wpa_dbus_dict_open_write()
  279. * @param key The key of the dict item
  280. * @param value The 64-bit integer value
  281. * @return TRUE on success, FALSE on failure
  282. *
  283. */
  284. dbus_bool_t wpa_dbus_dict_append_int64(DBusMessageIter *iter_dict,
  285. const char *key,
  286. const dbus_int64_t value)
  287. {
  288. return _wpa_dbus_add_dict_entry_basic(iter_dict, key, DBUS_TYPE_INT64,
  289. &value);
  290. }
  291. /**
  292. * Add a 64-bit unsigned integer entry to the dict.
  293. *
  294. * @param iter_dict A valid DBusMessageIter returned from
  295. * wpa_dbus_dict_open_write()
  296. * @param key The key of the dict item
  297. * @param value The 64-bit unsigned integer value
  298. * @return TRUE on success, FALSE on failure
  299. *
  300. */
  301. dbus_bool_t wpa_dbus_dict_append_uint64(DBusMessageIter *iter_dict,
  302. const char *key,
  303. const dbus_uint64_t value)
  304. {
  305. return _wpa_dbus_add_dict_entry_basic(iter_dict, key, DBUS_TYPE_UINT64,
  306. &value);
  307. }
  308. /**
  309. * Add a double-precision floating point entry to the dict.
  310. *
  311. * @param iter_dict A valid DBusMessageIter returned from
  312. * wpa_dbus_dict_open_write()
  313. * @param key The key of the dict item
  314. * @param value The double-precision floating point value
  315. * @return TRUE on success, FALSE on failure
  316. *
  317. */
  318. dbus_bool_t wpa_dbus_dict_append_double(DBusMessageIter *iter_dict,
  319. const char *key, const double value)
  320. {
  321. return _wpa_dbus_add_dict_entry_basic(iter_dict, key, DBUS_TYPE_DOUBLE,
  322. &value);
  323. }
  324. /**
  325. * Add a DBus object path entry to the dict.
  326. *
  327. * @param iter_dict A valid DBusMessageIter returned from
  328. * wpa_dbus_dict_open_write()
  329. * @param key The key of the dict item
  330. * @param value The DBus object path value
  331. * @return TRUE on success, FALSE on failure
  332. *
  333. */
  334. dbus_bool_t wpa_dbus_dict_append_object_path(DBusMessageIter *iter_dict,
  335. const char *key,
  336. const char *value)
  337. {
  338. if (!value)
  339. return FALSE;
  340. return _wpa_dbus_add_dict_entry_basic(iter_dict, key,
  341. DBUS_TYPE_OBJECT_PATH, &value);
  342. }
  343. /**
  344. * Add a byte array entry to the dict.
  345. *
  346. * @param iter_dict A valid DBusMessageIter returned from
  347. * wpa_dbus_dict_open_write()
  348. * @param key The key of the dict item
  349. * @param value The byte array
  350. * @param value_len The length of the byte array, in bytes
  351. * @return TRUE on success, FALSE on failure
  352. *
  353. */
  354. dbus_bool_t wpa_dbus_dict_append_byte_array(DBusMessageIter *iter_dict,
  355. const char *key,
  356. const char *value,
  357. const dbus_uint32_t value_len)
  358. {
  359. if (!key || (!value && value_len != 0))
  360. return FALSE;
  361. return _wpa_dbus_add_dict_entry_byte_array(iter_dict, key, value,
  362. value_len);
  363. }
  364. /**
  365. * Begin an array entry in the dict
  366. *
  367. * @param iter_dict A valid DBusMessageIter returned from
  368. * wpa_dbus_dict_open_write()
  369. * @param key The key of the dict item
  370. * @param type The type of the contained data
  371. * @param iter_dict_entry A private DBusMessageIter provided by the caller to
  372. * be passed to wpa_dbus_dict_end_string_array()
  373. * @param iter_dict_val A private DBusMessageIter provided by the caller to
  374. * be passed to wpa_dbus_dict_end_string_array()
  375. * @param iter_array On return, the DBusMessageIter to be passed to
  376. * wpa_dbus_dict_string_array_add_element()
  377. * @return TRUE on success, FALSE on failure
  378. *
  379. */
  380. dbus_bool_t wpa_dbus_dict_begin_array(DBusMessageIter *iter_dict,
  381. const char *key, const char *type,
  382. DBusMessageIter *iter_dict_entry,
  383. DBusMessageIter *iter_dict_val,
  384. DBusMessageIter *iter_array)
  385. {
  386. char array_type[10];
  387. int err;
  388. err = os_snprintf(array_type, sizeof(array_type),
  389. DBUS_TYPE_ARRAY_AS_STRING "%s",
  390. type);
  391. if (os_snprintf_error(sizeof(array_type), err))
  392. return FALSE;
  393. if (!iter_dict || !iter_dict_entry || !iter_dict_val || !iter_array ||
  394. !_wpa_dbus_add_dict_entry_start(iter_dict, iter_dict_entry,
  395. key, DBUS_TYPE_ARRAY) ||
  396. !dbus_message_iter_open_container(iter_dict_entry,
  397. DBUS_TYPE_VARIANT,
  398. array_type,
  399. iter_dict_val))
  400. return FALSE;
  401. return dbus_message_iter_open_container(iter_dict_val, DBUS_TYPE_ARRAY,
  402. type, iter_array);
  403. }
  404. dbus_bool_t wpa_dbus_dict_begin_string_array(DBusMessageIter *iter_dict,
  405. const char *key,
  406. DBusMessageIter *iter_dict_entry,
  407. DBusMessageIter *iter_dict_val,
  408. DBusMessageIter *iter_array)
  409. {
  410. return wpa_dbus_dict_begin_array(
  411. iter_dict, key,
  412. DBUS_TYPE_STRING_AS_STRING,
  413. iter_dict_entry, iter_dict_val, iter_array);
  414. }
  415. /**
  416. * Add a single string element to a string array dict entry
  417. *
  418. * @param iter_array A valid DBusMessageIter returned from
  419. * wpa_dbus_dict_begin_string_array()'s
  420. * iter_array parameter
  421. * @param elem The string element to be added to the dict entry's string array
  422. * @return TRUE on success, FALSE on failure
  423. *
  424. */
  425. dbus_bool_t wpa_dbus_dict_string_array_add_element(DBusMessageIter *iter_array,
  426. const char *elem)
  427. {
  428. if (!iter_array || !elem)
  429. return FALSE;
  430. return dbus_message_iter_append_basic(iter_array, DBUS_TYPE_STRING,
  431. &elem);
  432. }
  433. /**
  434. * Add a single byte array element to a string array dict entry
  435. *
  436. * @param iter_array A valid DBusMessageIter returned from
  437. * wpa_dbus_dict_begin_array()'s iter_array
  438. * parameter -- note that wpa_dbus_dict_begin_array()
  439. * must have been called with "ay" as the type
  440. * @param value The data to be added to the dict entry's array
  441. * @param value_len The length of the data
  442. * @return TRUE on success, FALSE on failure
  443. *
  444. */
  445. dbus_bool_t wpa_dbus_dict_bin_array_add_element(DBusMessageIter *iter_array,
  446. const u8 *value,
  447. size_t value_len)
  448. {
  449. DBusMessageIter iter_bytes;
  450. size_t i;
  451. if (!iter_array || !value ||
  452. !dbus_message_iter_open_container(iter_array, DBUS_TYPE_ARRAY,
  453. DBUS_TYPE_BYTE_AS_STRING,
  454. &iter_bytes))
  455. return FALSE;
  456. for (i = 0; i < value_len; i++) {
  457. if (!dbus_message_iter_append_basic(&iter_bytes,
  458. DBUS_TYPE_BYTE,
  459. &(value[i])))
  460. return FALSE;
  461. }
  462. return dbus_message_iter_close_container(iter_array, &iter_bytes);
  463. }
  464. /**
  465. * End an array dict entry
  466. *
  467. * @param iter_dict A valid DBusMessageIter returned from
  468. * wpa_dbus_dict_open_write()
  469. * @param iter_dict_entry A private DBusMessageIter returned from
  470. * wpa_dbus_dict_begin_string_array() or
  471. * wpa_dbus_dict_begin_array()
  472. * @param iter_dict_val A private DBusMessageIter returned from
  473. * wpa_dbus_dict_begin_string_array() or
  474. * wpa_dbus_dict_begin_array()
  475. * @param iter_array A DBusMessageIter returned from
  476. * wpa_dbus_dict_begin_string_array() or
  477. * wpa_dbus_dict_begin_array()
  478. * @return TRUE on success, FALSE on failure
  479. *
  480. */
  481. dbus_bool_t wpa_dbus_dict_end_array(DBusMessageIter *iter_dict,
  482. DBusMessageIter *iter_dict_entry,
  483. DBusMessageIter *iter_dict_val,
  484. DBusMessageIter *iter_array)
  485. {
  486. if (!iter_dict || !iter_dict_entry || !iter_dict_val || !iter_array ||
  487. !dbus_message_iter_close_container(iter_dict_val, iter_array))
  488. return FALSE;
  489. return _wpa_dbus_add_dict_entry_end(iter_dict, iter_dict_entry,
  490. iter_dict_val);
  491. }
  492. /**
  493. * Convenience function to add an entire string array to the dict.
  494. *
  495. * @param iter_dict A valid DBusMessageIter returned from
  496. * wpa_dbus_dict_open_write()
  497. * @param key The key of the dict item
  498. * @param items The array of strings
  499. * @param num_items The number of strings in the array
  500. * @return TRUE on success, FALSE on failure
  501. *
  502. */
  503. dbus_bool_t wpa_dbus_dict_append_string_array(DBusMessageIter *iter_dict,
  504. const char *key,
  505. const char **items,
  506. const dbus_uint32_t num_items)
  507. {
  508. DBusMessageIter iter_dict_entry, iter_dict_val, iter_array;
  509. dbus_uint32_t i;
  510. if (!key || (!items && num_items != 0) ||
  511. !wpa_dbus_dict_begin_string_array(iter_dict, key,
  512. &iter_dict_entry, &iter_dict_val,
  513. &iter_array))
  514. return FALSE;
  515. for (i = 0; i < num_items; i++) {
  516. if (!wpa_dbus_dict_string_array_add_element(&iter_array,
  517. items[i]))
  518. return FALSE;
  519. }
  520. return wpa_dbus_dict_end_string_array(iter_dict, &iter_dict_entry,
  521. &iter_dict_val, &iter_array);
  522. }
  523. /**
  524. * Convenience function to add an wpabuf binary array to the dict.
  525. *
  526. * @param iter_dict A valid DBusMessageIter returned from
  527. * wpa_dbus_dict_open_write()
  528. * @param key The key of the dict item
  529. * @param items The array of wpabuf structures
  530. * @param num_items The number of strings in the array
  531. * @return TRUE on success, FALSE on failure
  532. *
  533. */
  534. dbus_bool_t wpa_dbus_dict_append_wpabuf_array(DBusMessageIter *iter_dict,
  535. const char *key,
  536. const struct wpabuf **items,
  537. const dbus_uint32_t num_items)
  538. {
  539. DBusMessageIter iter_dict_entry, iter_dict_val, iter_array;
  540. dbus_uint32_t i;
  541. if (!key ||
  542. (!items && num_items != 0) ||
  543. !wpa_dbus_dict_begin_array(iter_dict, key,
  544. DBUS_TYPE_ARRAY_AS_STRING
  545. DBUS_TYPE_BYTE_AS_STRING,
  546. &iter_dict_entry, &iter_dict_val,
  547. &iter_array))
  548. return FALSE;
  549. for (i = 0; i < num_items; i++) {
  550. if (!wpa_dbus_dict_bin_array_add_element(&iter_array,
  551. wpabuf_head(items[i]),
  552. wpabuf_len(items[i])))
  553. return FALSE;
  554. }
  555. return wpa_dbus_dict_end_array(iter_dict, &iter_dict_entry,
  556. &iter_dict_val, &iter_array);
  557. }
  558. /*****************************************************/
  559. /* Stuff for reading dicts */
  560. /*****************************************************/
  561. /**
  562. * Start reading from a dbus dict.
  563. *
  564. * @param iter A valid DBusMessageIter pointing to the start of the dict
  565. * @param iter_dict (out) A DBusMessageIter to be passed to
  566. * wpa_dbus_dict_read_next_entry()
  567. * @error on failure a descriptive error
  568. * @return TRUE on success, FALSE on failure
  569. *
  570. */
  571. dbus_bool_t wpa_dbus_dict_open_read(DBusMessageIter *iter,
  572. DBusMessageIter *iter_dict,
  573. DBusError *error)
  574. {
  575. int type;
  576. wpa_printf(MSG_MSGDUMP, "%s: start reading a dict entry", __func__);
  577. if (!iter || !iter_dict) {
  578. dbus_set_error_const(error, DBUS_ERROR_FAILED,
  579. "[internal] missing message iterators");
  580. return FALSE;
  581. }
  582. type = dbus_message_iter_get_arg_type(iter);
  583. if (type != DBUS_TYPE_ARRAY ||
  584. dbus_message_iter_get_element_type(iter) != DBUS_TYPE_DICT_ENTRY) {
  585. wpa_printf(MSG_DEBUG,
  586. "%s: unexpected message argument types (arg=%c element=%c)",
  587. __func__, type,
  588. type != DBUS_TYPE_ARRAY ? '?' :
  589. dbus_message_iter_get_element_type(iter));
  590. dbus_set_error_const(error, DBUS_ERROR_INVALID_ARGS,
  591. "unexpected message argument types");
  592. return FALSE;
  593. }
  594. dbus_message_iter_recurse(iter, iter_dict);
  595. return TRUE;
  596. }
  597. #define BYTE_ARRAY_CHUNK_SIZE 34
  598. #define BYTE_ARRAY_ITEM_SIZE (sizeof(char))
  599. static dbus_bool_t _wpa_dbus_dict_entry_get_byte_array(
  600. DBusMessageIter *iter, struct wpa_dbus_dict_entry *entry)
  601. {
  602. dbus_uint32_t count = 0;
  603. dbus_bool_t success = FALSE;
  604. char *buffer, *nbuffer;
  605. entry->bytearray_value = NULL;
  606. entry->array_type = DBUS_TYPE_BYTE;
  607. buffer = os_calloc(BYTE_ARRAY_CHUNK_SIZE, BYTE_ARRAY_ITEM_SIZE);
  608. if (!buffer)
  609. return FALSE;
  610. entry->bytearray_value = buffer;
  611. entry->array_len = 0;
  612. while (dbus_message_iter_get_arg_type(iter) == DBUS_TYPE_BYTE) {
  613. char byte;
  614. if ((count % BYTE_ARRAY_CHUNK_SIZE) == 0 && count != 0) {
  615. nbuffer = os_realloc_array(
  616. buffer, count + BYTE_ARRAY_CHUNK_SIZE,
  617. BYTE_ARRAY_ITEM_SIZE);
  618. if (nbuffer == NULL) {
  619. os_free(buffer);
  620. wpa_printf(MSG_ERROR,
  621. "dbus: %s out of memory trying to retrieve the string array",
  622. __func__);
  623. goto done;
  624. }
  625. buffer = nbuffer;
  626. }
  627. entry->bytearray_value = buffer;
  628. dbus_message_iter_get_basic(iter, &byte);
  629. entry->bytearray_value[count] = byte;
  630. entry->array_len = ++count;
  631. dbus_message_iter_next(iter);
  632. }
  633. wpa_hexdump_key(MSG_MSGDUMP, "dbus: byte array contents",
  634. entry->bytearray_value, entry->array_len);
  635. /* Zero-length arrays are valid. */
  636. if (entry->array_len == 0) {
  637. os_free(entry->bytearray_value);
  638. entry->bytearray_value = NULL;
  639. }
  640. success = TRUE;
  641. done:
  642. return success;
  643. }
  644. #define STR_ARRAY_CHUNK_SIZE 8
  645. #define STR_ARRAY_ITEM_SIZE (sizeof(char *))
  646. static dbus_bool_t _wpa_dbus_dict_entry_get_string_array(
  647. DBusMessageIter *iter, int array_type,
  648. struct wpa_dbus_dict_entry *entry)
  649. {
  650. dbus_uint32_t count = 0;
  651. dbus_bool_t success = FALSE;
  652. char **buffer, **nbuffer;
  653. entry->strarray_value = NULL;
  654. entry->array_type = DBUS_TYPE_STRING;
  655. buffer = os_calloc(STR_ARRAY_CHUNK_SIZE, STR_ARRAY_ITEM_SIZE);
  656. if (buffer == NULL)
  657. return FALSE;
  658. entry->strarray_value = buffer;
  659. entry->array_len = 0;
  660. while (dbus_message_iter_get_arg_type(iter) == DBUS_TYPE_STRING) {
  661. const char *value;
  662. char *str;
  663. if ((count % STR_ARRAY_CHUNK_SIZE) == 0 && count != 0) {
  664. nbuffer = os_realloc_array(
  665. buffer, count + STR_ARRAY_CHUNK_SIZE,
  666. STR_ARRAY_ITEM_SIZE);
  667. if (nbuffer == NULL) {
  668. os_free(buffer);
  669. wpa_printf(MSG_ERROR,
  670. "dbus: %s out of memory trying to retrieve the string array",
  671. __func__);
  672. goto done;
  673. }
  674. buffer = nbuffer;
  675. }
  676. entry->strarray_value = buffer;
  677. dbus_message_iter_get_basic(iter, &value);
  678. wpa_printf(MSG_MSGDUMP, "%s: string_array value: %s",
  679. __func__, wpa_debug_show_keys ? value : "[omitted]");
  680. str = os_strdup(value);
  681. if (str == NULL) {
  682. wpa_printf(MSG_ERROR,
  683. "dbus: %s out of memory trying to duplicate the string array",
  684. __func__);
  685. goto done;
  686. }
  687. entry->strarray_value[count] = str;
  688. entry->array_len = ++count;
  689. dbus_message_iter_next(iter);
  690. }
  691. wpa_printf(MSG_MSGDUMP, "%s: string_array length %u",
  692. __func__, entry->array_len);
  693. /* Zero-length arrays are valid. */
  694. if (entry->array_len == 0) {
  695. os_free(entry->strarray_value);
  696. entry->strarray_value = NULL;
  697. }
  698. success = TRUE;
  699. done:
  700. return success;
  701. }
  702. #define BIN_ARRAY_CHUNK_SIZE 10
  703. #define BIN_ARRAY_ITEM_SIZE (sizeof(struct wpabuf *))
  704. static dbus_bool_t _wpa_dbus_dict_entry_get_binarray(
  705. DBusMessageIter *iter, struct wpa_dbus_dict_entry *entry)
  706. {
  707. struct wpa_dbus_dict_entry tmpentry;
  708. size_t buflen = 0;
  709. int i, type;
  710. entry->array_type = WPAS_DBUS_TYPE_BINARRAY;
  711. entry->array_len = 0;
  712. entry->binarray_value = NULL;
  713. type = dbus_message_iter_get_arg_type(iter);
  714. wpa_printf(MSG_MSGDUMP, "%s: parsing binarray type %c", __func__, type);
  715. if (type == DBUS_TYPE_INVALID) {
  716. /* Likely an empty array of arrays */
  717. return TRUE;
  718. }
  719. if (type != DBUS_TYPE_ARRAY) {
  720. wpa_printf(MSG_DEBUG, "%s: not an array type: %c",
  721. __func__, type);
  722. return FALSE;
  723. }
  724. type = dbus_message_iter_get_element_type(iter);
  725. if (type != DBUS_TYPE_BYTE) {
  726. wpa_printf(MSG_DEBUG, "%s: unexpected element type %c",
  727. __func__, type);
  728. return FALSE;
  729. }
  730. while (dbus_message_iter_get_arg_type(iter) == DBUS_TYPE_ARRAY) {
  731. DBusMessageIter iter_array;
  732. if (entry->array_len == buflen) {
  733. struct wpabuf **newbuf;
  734. buflen += BIN_ARRAY_CHUNK_SIZE;
  735. newbuf = os_realloc_array(entry->binarray_value,
  736. buflen, BIN_ARRAY_ITEM_SIZE);
  737. if (!newbuf)
  738. goto cleanup;
  739. entry->binarray_value = newbuf;
  740. }
  741. dbus_message_iter_recurse(iter, &iter_array);
  742. os_memset(&tmpentry, 0, sizeof(tmpentry));
  743. tmpentry.type = DBUS_TYPE_ARRAY;
  744. if (_wpa_dbus_dict_entry_get_byte_array(&iter_array, &tmpentry)
  745. == FALSE)
  746. goto cleanup;
  747. entry->binarray_value[entry->array_len] =
  748. wpabuf_alloc_ext_data((u8 *) tmpentry.bytearray_value,
  749. tmpentry.array_len);
  750. if (entry->binarray_value[entry->array_len] == NULL) {
  751. wpa_dbus_dict_entry_clear(&tmpentry);
  752. goto cleanup;
  753. }
  754. entry->array_len++;
  755. dbus_message_iter_next(iter);
  756. }
  757. wpa_printf(MSG_MSGDUMP, "%s: binarray length %u",
  758. __func__, entry->array_len);
  759. return TRUE;
  760. cleanup:
  761. for (i = 0; i < (int) entry->array_len; i++)
  762. wpabuf_free(entry->binarray_value[i]);
  763. os_free(entry->binarray_value);
  764. entry->array_len = 0;
  765. entry->binarray_value = NULL;
  766. return FALSE;
  767. }
  768. static dbus_bool_t _wpa_dbus_dict_entry_get_array(
  769. DBusMessageIter *iter_dict_val, struct wpa_dbus_dict_entry *entry)
  770. {
  771. int array_type = dbus_message_iter_get_element_type(iter_dict_val);
  772. dbus_bool_t success = FALSE;
  773. DBusMessageIter iter_array;
  774. wpa_printf(MSG_MSGDUMP, "%s: array_type %c", __func__, array_type);
  775. dbus_message_iter_recurse(iter_dict_val, &iter_array);
  776. switch (array_type) {
  777. case DBUS_TYPE_BYTE:
  778. success = _wpa_dbus_dict_entry_get_byte_array(&iter_array,
  779. entry);
  780. break;
  781. case DBUS_TYPE_STRING:
  782. success = _wpa_dbus_dict_entry_get_string_array(&iter_array,
  783. array_type,
  784. entry);
  785. break;
  786. case DBUS_TYPE_ARRAY:
  787. success = _wpa_dbus_dict_entry_get_binarray(&iter_array, entry);
  788. break;
  789. default:
  790. wpa_printf(MSG_MSGDUMP, "%s: unsupported array type %c",
  791. __func__, array_type);
  792. break;
  793. }
  794. return success;
  795. }
  796. static dbus_bool_t _wpa_dbus_dict_fill_value_from_variant(
  797. struct wpa_dbus_dict_entry *entry, DBusMessageIter *iter)
  798. {
  799. const char *v;
  800. switch (entry->type) {
  801. case DBUS_TYPE_OBJECT_PATH:
  802. dbus_message_iter_get_basic(iter, &v);
  803. wpa_printf(MSG_MSGDUMP, "%s: object path value: %s",
  804. __func__, v);
  805. entry->str_value = os_strdup(v);
  806. if (entry->str_value == NULL)
  807. return FALSE;
  808. break;
  809. case DBUS_TYPE_STRING:
  810. dbus_message_iter_get_basic(iter, &v);
  811. wpa_printf(MSG_MSGDUMP, "%s: string value: %s",
  812. __func__, wpa_debug_show_keys ? v : "[omitted]");
  813. entry->str_value = os_strdup(v);
  814. if (entry->str_value == NULL)
  815. return FALSE;
  816. break;
  817. case DBUS_TYPE_BOOLEAN:
  818. dbus_message_iter_get_basic(iter, &entry->bool_value);
  819. wpa_printf(MSG_MSGDUMP, "%s: boolean value: %d",
  820. __func__, entry->bool_value);
  821. break;
  822. case DBUS_TYPE_BYTE:
  823. dbus_message_iter_get_basic(iter, &entry->byte_value);
  824. wpa_printf(MSG_MSGDUMP, "%s: byte value: %d",
  825. __func__, entry->byte_value);
  826. break;
  827. case DBUS_TYPE_INT16:
  828. dbus_message_iter_get_basic(iter, &entry->int16_value);
  829. wpa_printf(MSG_MSGDUMP, "%s: int16 value: %d",
  830. __func__, entry->int16_value);
  831. break;
  832. case DBUS_TYPE_UINT16:
  833. dbus_message_iter_get_basic(iter, &entry->uint16_value);
  834. wpa_printf(MSG_MSGDUMP, "%s: uint16 value: %d",
  835. __func__, entry->uint16_value);
  836. break;
  837. case DBUS_TYPE_INT32:
  838. dbus_message_iter_get_basic(iter, &entry->int32_value);
  839. wpa_printf(MSG_MSGDUMP, "%s: int32 value: %d",
  840. __func__, entry->int32_value);
  841. break;
  842. case DBUS_TYPE_UINT32:
  843. dbus_message_iter_get_basic(iter, &entry->uint32_value);
  844. wpa_printf(MSG_MSGDUMP, "%s: uint32 value: %d",
  845. __func__, entry->uint32_value);
  846. break;
  847. case DBUS_TYPE_INT64:
  848. dbus_message_iter_get_basic(iter, &entry->int64_value);
  849. wpa_printf(MSG_MSGDUMP, "%s: int64 value: %lld",
  850. __func__, (long long int) entry->int64_value);
  851. break;
  852. case DBUS_TYPE_UINT64:
  853. dbus_message_iter_get_basic(iter, &entry->uint64_value);
  854. wpa_printf(MSG_MSGDUMP, "%s: uint64 value: %llu",
  855. __func__,
  856. (unsigned long long int) entry->uint64_value);
  857. break;
  858. case DBUS_TYPE_DOUBLE:
  859. dbus_message_iter_get_basic(iter, &entry->double_value);
  860. wpa_printf(MSG_MSGDUMP, "%s: double value: %f",
  861. __func__, entry->double_value);
  862. break;
  863. case DBUS_TYPE_ARRAY:
  864. return _wpa_dbus_dict_entry_get_array(iter, entry);
  865. default:
  866. wpa_printf(MSG_MSGDUMP, "%s: unsupported type %c",
  867. __func__, entry->type);
  868. return FALSE;
  869. }
  870. return TRUE;
  871. }
  872. /**
  873. * Read the current key/value entry from the dict. Entries are dynamically
  874. * allocated when needed and must be freed after use with the
  875. * wpa_dbus_dict_entry_clear() function.
  876. *
  877. * The returned entry object will be filled with the type and value of the next
  878. * entry in the dict, or the type will be DBUS_TYPE_INVALID if an error
  879. * occurred.
  880. *
  881. * @param iter_dict A valid DBusMessageIter returned from
  882. * wpa_dbus_dict_open_read()
  883. * @param entry A valid dict entry object into which the dict key and value
  884. * will be placed
  885. * @return TRUE on success, FALSE on failure
  886. *
  887. */
  888. dbus_bool_t wpa_dbus_dict_get_entry(DBusMessageIter *iter_dict,
  889. struct wpa_dbus_dict_entry * entry)
  890. {
  891. DBusMessageIter iter_dict_entry, iter_dict_val;
  892. int type;
  893. const char *key;
  894. if (!iter_dict || !entry ||
  895. dbus_message_iter_get_arg_type(iter_dict) != DBUS_TYPE_DICT_ENTRY) {
  896. wpa_printf(MSG_DEBUG, "%s: not a dict entry", __func__);
  897. goto error;
  898. }
  899. dbus_message_iter_recurse(iter_dict, &iter_dict_entry);
  900. dbus_message_iter_get_basic(&iter_dict_entry, &key);
  901. wpa_printf(MSG_MSGDUMP, "%s: dict entry key: %s", __func__, key);
  902. entry->key = key;
  903. if (!dbus_message_iter_next(&iter_dict_entry)) {
  904. wpa_printf(MSG_DEBUG, "%s: no variant in dict entry", __func__);
  905. goto error;
  906. }
  907. type = dbus_message_iter_get_arg_type(&iter_dict_entry);
  908. if (type != DBUS_TYPE_VARIANT) {
  909. wpa_printf(MSG_DEBUG,
  910. "%s: unexpected dict entry variant type: %c",
  911. __func__, type);
  912. goto error;
  913. }
  914. dbus_message_iter_recurse(&iter_dict_entry, &iter_dict_val);
  915. entry->type = dbus_message_iter_get_arg_type(&iter_dict_val);
  916. wpa_printf(MSG_MSGDUMP, "%s: dict entry variant content type: %c",
  917. __func__, entry->type);
  918. entry->array_type = DBUS_TYPE_INVALID;
  919. if (!_wpa_dbus_dict_fill_value_from_variant(entry, &iter_dict_val)) {
  920. wpa_printf(MSG_DEBUG,
  921. "%s: failed to fetch dict values from variant",
  922. __func__);
  923. goto error;
  924. }
  925. dbus_message_iter_next(iter_dict);
  926. return TRUE;
  927. error:
  928. if (entry) {
  929. wpa_dbus_dict_entry_clear(entry);
  930. entry->type = DBUS_TYPE_INVALID;
  931. entry->array_type = DBUS_TYPE_INVALID;
  932. }
  933. return FALSE;
  934. }
  935. /**
  936. * Return whether or not there are additional dictionary entries.
  937. *
  938. * @param iter_dict A valid DBusMessageIter returned from
  939. * wpa_dbus_dict_open_read()
  940. * @return TRUE if more dict entries exists, FALSE if no more dict entries
  941. * exist
  942. */
  943. dbus_bool_t wpa_dbus_dict_has_dict_entry(DBusMessageIter *iter_dict)
  944. {
  945. if (!iter_dict)
  946. return FALSE;
  947. return dbus_message_iter_get_arg_type(iter_dict) ==
  948. DBUS_TYPE_DICT_ENTRY;
  949. }
  950. /**
  951. * Free any memory used by the entry object.
  952. *
  953. * @param entry The entry object
  954. */
  955. void wpa_dbus_dict_entry_clear(struct wpa_dbus_dict_entry *entry)
  956. {
  957. unsigned int i;
  958. if (!entry)
  959. return;
  960. switch (entry->type) {
  961. case DBUS_TYPE_OBJECT_PATH:
  962. case DBUS_TYPE_STRING:
  963. os_free(entry->str_value);
  964. break;
  965. case DBUS_TYPE_ARRAY:
  966. switch (entry->array_type) {
  967. case DBUS_TYPE_BYTE:
  968. os_free(entry->bytearray_value);
  969. break;
  970. case DBUS_TYPE_STRING:
  971. for (i = 0; i < entry->array_len; i++)
  972. os_free(entry->strarray_value[i]);
  973. os_free(entry->strarray_value);
  974. break;
  975. case WPAS_DBUS_TYPE_BINARRAY:
  976. for (i = 0; i < entry->array_len; i++)
  977. wpabuf_free(entry->binarray_value[i]);
  978. os_free(entry->binarray_value);
  979. break;
  980. }
  981. break;
  982. }
  983. os_memset(entry, 0, sizeof(struct wpa_dbus_dict_entry));
  984. }