dbus_dict_helpers.c 31 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131
  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->array_len = 0;
  611. while (dbus_message_iter_get_arg_type(iter) == DBUS_TYPE_BYTE) {
  612. char byte;
  613. if ((count % BYTE_ARRAY_CHUNK_SIZE) == 0 && count != 0) {
  614. nbuffer = os_realloc_array(
  615. buffer, count + BYTE_ARRAY_CHUNK_SIZE,
  616. BYTE_ARRAY_ITEM_SIZE);
  617. if (nbuffer == NULL) {
  618. os_free(buffer);
  619. wpa_printf(MSG_ERROR,
  620. "dbus: %s out of memory trying to retrieve the string array",
  621. __func__);
  622. goto done;
  623. }
  624. buffer = nbuffer;
  625. }
  626. dbus_message_iter_get_basic(iter, &byte);
  627. buffer[count] = byte;
  628. entry->array_len = ++count;
  629. dbus_message_iter_next(iter);
  630. }
  631. entry->bytearray_value = buffer;
  632. wpa_hexdump_key(MSG_MSGDUMP, "dbus: byte array contents",
  633. entry->bytearray_value, entry->array_len);
  634. /* Zero-length arrays are valid. */
  635. if (entry->array_len == 0) {
  636. os_free(entry->bytearray_value);
  637. entry->bytearray_value = NULL;
  638. }
  639. success = TRUE;
  640. done:
  641. return success;
  642. }
  643. #define STR_ARRAY_CHUNK_SIZE 8
  644. #define STR_ARRAY_ITEM_SIZE (sizeof(char *))
  645. static dbus_bool_t _wpa_dbus_dict_entry_get_string_array(
  646. DBusMessageIter *iter, int array_type,
  647. struct wpa_dbus_dict_entry *entry)
  648. {
  649. dbus_uint32_t count = 0;
  650. dbus_bool_t success = FALSE;
  651. char **buffer, **nbuffer;
  652. entry->strarray_value = NULL;
  653. entry->array_type = DBUS_TYPE_STRING;
  654. buffer = os_calloc(STR_ARRAY_CHUNK_SIZE, STR_ARRAY_ITEM_SIZE);
  655. if (buffer == NULL)
  656. return FALSE;
  657. entry->strarray_value = buffer;
  658. entry->array_len = 0;
  659. while (dbus_message_iter_get_arg_type(iter) == DBUS_TYPE_STRING) {
  660. const char *value;
  661. char *str;
  662. if ((count % STR_ARRAY_CHUNK_SIZE) == 0 && count != 0) {
  663. nbuffer = os_realloc_array(
  664. buffer, count + STR_ARRAY_CHUNK_SIZE,
  665. STR_ARRAY_ITEM_SIZE);
  666. if (nbuffer == NULL) {
  667. os_free(buffer);
  668. wpa_printf(MSG_ERROR,
  669. "dbus: %s out of memory trying to retrieve the string array",
  670. __func__);
  671. goto done;
  672. }
  673. buffer = nbuffer;
  674. }
  675. entry->strarray_value = buffer;
  676. dbus_message_iter_get_basic(iter, &value);
  677. wpa_printf(MSG_MSGDUMP, "%s: string_array value: %s",
  678. __func__, wpa_debug_show_keys ? value : "[omitted]");
  679. str = os_strdup(value);
  680. if (str == NULL) {
  681. wpa_printf(MSG_ERROR,
  682. "dbus: %s out of memory trying to duplicate the string array",
  683. __func__);
  684. goto done;
  685. }
  686. entry->strarray_value[count] = str;
  687. entry->array_len = ++count;
  688. dbus_message_iter_next(iter);
  689. }
  690. wpa_printf(MSG_MSGDUMP, "%s: string_array length %u",
  691. __func__, entry->array_len);
  692. /* Zero-length arrays are valid. */
  693. if (entry->array_len == 0) {
  694. os_free(entry->strarray_value);
  695. entry->strarray_value = NULL;
  696. }
  697. success = TRUE;
  698. done:
  699. return success;
  700. }
  701. #define BIN_ARRAY_CHUNK_SIZE 10
  702. #define BIN_ARRAY_ITEM_SIZE (sizeof(struct wpabuf *))
  703. static dbus_bool_t _wpa_dbus_dict_entry_get_binarray(
  704. DBusMessageIter *iter, struct wpa_dbus_dict_entry *entry)
  705. {
  706. struct wpa_dbus_dict_entry tmpentry;
  707. size_t buflen = 0;
  708. int i, type;
  709. entry->array_type = WPAS_DBUS_TYPE_BINARRAY;
  710. entry->array_len = 0;
  711. entry->binarray_value = NULL;
  712. type = dbus_message_iter_get_arg_type(iter);
  713. wpa_printf(MSG_MSGDUMP, "%s: parsing binarray type %c", __func__, type);
  714. if (type == DBUS_TYPE_INVALID) {
  715. /* Likely an empty array of arrays */
  716. return TRUE;
  717. }
  718. if (type != DBUS_TYPE_ARRAY) {
  719. wpa_printf(MSG_DEBUG, "%s: not an array type: %c",
  720. __func__, type);
  721. return FALSE;
  722. }
  723. type = dbus_message_iter_get_element_type(iter);
  724. if (type != DBUS_TYPE_BYTE) {
  725. wpa_printf(MSG_DEBUG, "%s: unexpected element type %c",
  726. __func__, type);
  727. return FALSE;
  728. }
  729. while (dbus_message_iter_get_arg_type(iter) == DBUS_TYPE_ARRAY) {
  730. DBusMessageIter iter_array;
  731. if (entry->array_len == buflen) {
  732. struct wpabuf **newbuf;
  733. buflen += BIN_ARRAY_CHUNK_SIZE;
  734. newbuf = os_realloc_array(entry->binarray_value,
  735. buflen, BIN_ARRAY_ITEM_SIZE);
  736. if (!newbuf)
  737. goto cleanup;
  738. entry->binarray_value = newbuf;
  739. }
  740. dbus_message_iter_recurse(iter, &iter_array);
  741. os_memset(&tmpentry, 0, sizeof(tmpentry));
  742. tmpentry.type = DBUS_TYPE_ARRAY;
  743. if (_wpa_dbus_dict_entry_get_byte_array(&iter_array, &tmpentry)
  744. == FALSE)
  745. goto cleanup;
  746. entry->binarray_value[entry->array_len] =
  747. wpabuf_alloc_ext_data((u8 *) tmpentry.bytearray_value,
  748. tmpentry.array_len);
  749. if (entry->binarray_value[entry->array_len] == NULL) {
  750. wpa_dbus_dict_entry_clear(&tmpentry);
  751. goto cleanup;
  752. }
  753. entry->array_len++;
  754. dbus_message_iter_next(iter);
  755. }
  756. wpa_printf(MSG_MSGDUMP, "%s: binarray length %u",
  757. __func__, entry->array_len);
  758. return TRUE;
  759. cleanup:
  760. for (i = 0; i < (int) entry->array_len; i++)
  761. wpabuf_free(entry->binarray_value[i]);
  762. os_free(entry->binarray_value);
  763. entry->array_len = 0;
  764. entry->binarray_value = NULL;
  765. return FALSE;
  766. }
  767. static dbus_bool_t _wpa_dbus_dict_entry_get_array(
  768. DBusMessageIter *iter_dict_val, struct wpa_dbus_dict_entry *entry)
  769. {
  770. int array_type = dbus_message_iter_get_element_type(iter_dict_val);
  771. dbus_bool_t success = FALSE;
  772. DBusMessageIter iter_array;
  773. wpa_printf(MSG_MSGDUMP, "%s: array_type %c", __func__, array_type);
  774. dbus_message_iter_recurse(iter_dict_val, &iter_array);
  775. switch (array_type) {
  776. case DBUS_TYPE_BYTE:
  777. success = _wpa_dbus_dict_entry_get_byte_array(&iter_array,
  778. entry);
  779. break;
  780. case DBUS_TYPE_STRING:
  781. success = _wpa_dbus_dict_entry_get_string_array(&iter_array,
  782. array_type,
  783. entry);
  784. break;
  785. case DBUS_TYPE_ARRAY:
  786. success = _wpa_dbus_dict_entry_get_binarray(&iter_array, entry);
  787. break;
  788. default:
  789. wpa_printf(MSG_MSGDUMP, "%s: unsupported array type %c",
  790. __func__, array_type);
  791. break;
  792. }
  793. return success;
  794. }
  795. static dbus_bool_t _wpa_dbus_dict_fill_value_from_variant(
  796. struct wpa_dbus_dict_entry *entry, DBusMessageIter *iter)
  797. {
  798. const char *v;
  799. switch (entry->type) {
  800. case DBUS_TYPE_OBJECT_PATH:
  801. dbus_message_iter_get_basic(iter, &v);
  802. wpa_printf(MSG_MSGDUMP, "%s: object path value: %s",
  803. __func__, v);
  804. entry->str_value = os_strdup(v);
  805. if (entry->str_value == NULL)
  806. return FALSE;
  807. break;
  808. case DBUS_TYPE_STRING:
  809. dbus_message_iter_get_basic(iter, &v);
  810. wpa_printf(MSG_MSGDUMP, "%s: string value: %s",
  811. __func__, wpa_debug_show_keys ? v : "[omitted]");
  812. entry->str_value = os_strdup(v);
  813. if (entry->str_value == NULL)
  814. return FALSE;
  815. break;
  816. case DBUS_TYPE_BOOLEAN:
  817. dbus_message_iter_get_basic(iter, &entry->bool_value);
  818. wpa_printf(MSG_MSGDUMP, "%s: boolean value: %d",
  819. __func__, entry->bool_value);
  820. break;
  821. case DBUS_TYPE_BYTE:
  822. dbus_message_iter_get_basic(iter, &entry->byte_value);
  823. wpa_printf(MSG_MSGDUMP, "%s: byte value: %d",
  824. __func__, entry->byte_value);
  825. break;
  826. case DBUS_TYPE_INT16:
  827. dbus_message_iter_get_basic(iter, &entry->int16_value);
  828. wpa_printf(MSG_MSGDUMP, "%s: int16 value: %d",
  829. __func__, entry->int16_value);
  830. break;
  831. case DBUS_TYPE_UINT16:
  832. dbus_message_iter_get_basic(iter, &entry->uint16_value);
  833. wpa_printf(MSG_MSGDUMP, "%s: uint16 value: %d",
  834. __func__, entry->uint16_value);
  835. break;
  836. case DBUS_TYPE_INT32:
  837. dbus_message_iter_get_basic(iter, &entry->int32_value);
  838. wpa_printf(MSG_MSGDUMP, "%s: int32 value: %d",
  839. __func__, entry->int32_value);
  840. break;
  841. case DBUS_TYPE_UINT32:
  842. dbus_message_iter_get_basic(iter, &entry->uint32_value);
  843. wpa_printf(MSG_MSGDUMP, "%s: uint32 value: %d",
  844. __func__, entry->uint32_value);
  845. break;
  846. case DBUS_TYPE_INT64:
  847. dbus_message_iter_get_basic(iter, &entry->int64_value);
  848. wpa_printf(MSG_MSGDUMP, "%s: int64 value: %lld",
  849. __func__, (long long int) entry->int64_value);
  850. break;
  851. case DBUS_TYPE_UINT64:
  852. dbus_message_iter_get_basic(iter, &entry->uint64_value);
  853. wpa_printf(MSG_MSGDUMP, "%s: uint64 value: %llu",
  854. __func__,
  855. (unsigned long long int) entry->uint64_value);
  856. break;
  857. case DBUS_TYPE_DOUBLE:
  858. dbus_message_iter_get_basic(iter, &entry->double_value);
  859. wpa_printf(MSG_MSGDUMP, "%s: double value: %f",
  860. __func__, entry->double_value);
  861. break;
  862. case DBUS_TYPE_ARRAY:
  863. return _wpa_dbus_dict_entry_get_array(iter, entry);
  864. default:
  865. wpa_printf(MSG_MSGDUMP, "%s: unsupported type %c",
  866. __func__, entry->type);
  867. return FALSE;
  868. }
  869. return TRUE;
  870. }
  871. /**
  872. * Read the current key/value entry from the dict. Entries are dynamically
  873. * allocated when needed and must be freed after use with the
  874. * wpa_dbus_dict_entry_clear() function.
  875. *
  876. * The returned entry object will be filled with the type and value of the next
  877. * entry in the dict, or the type will be DBUS_TYPE_INVALID if an error
  878. * occurred.
  879. *
  880. * @param iter_dict A valid DBusMessageIter returned from
  881. * wpa_dbus_dict_open_read()
  882. * @param entry A valid dict entry object into which the dict key and value
  883. * will be placed
  884. * @return TRUE on success, FALSE on failure
  885. *
  886. */
  887. dbus_bool_t wpa_dbus_dict_get_entry(DBusMessageIter *iter_dict,
  888. struct wpa_dbus_dict_entry * entry)
  889. {
  890. DBusMessageIter iter_dict_entry, iter_dict_val;
  891. int type;
  892. const char *key;
  893. if (!iter_dict || !entry ||
  894. dbus_message_iter_get_arg_type(iter_dict) != DBUS_TYPE_DICT_ENTRY) {
  895. wpa_printf(MSG_DEBUG, "%s: not a dict entry", __func__);
  896. goto error;
  897. }
  898. dbus_message_iter_recurse(iter_dict, &iter_dict_entry);
  899. dbus_message_iter_get_basic(&iter_dict_entry, &key);
  900. wpa_printf(MSG_MSGDUMP, "%s: dict entry key: %s", __func__, key);
  901. entry->key = key;
  902. if (!dbus_message_iter_next(&iter_dict_entry)) {
  903. wpa_printf(MSG_DEBUG, "%s: no variant in dict entry", __func__);
  904. goto error;
  905. }
  906. type = dbus_message_iter_get_arg_type(&iter_dict_entry);
  907. if (type != DBUS_TYPE_VARIANT) {
  908. wpa_printf(MSG_DEBUG,
  909. "%s: unexpected dict entry variant type: %c",
  910. __func__, type);
  911. goto error;
  912. }
  913. dbus_message_iter_recurse(&iter_dict_entry, &iter_dict_val);
  914. entry->type = dbus_message_iter_get_arg_type(&iter_dict_val);
  915. wpa_printf(MSG_MSGDUMP, "%s: dict entry variant content type: %c",
  916. __func__, entry->type);
  917. entry->array_type = DBUS_TYPE_INVALID;
  918. if (!_wpa_dbus_dict_fill_value_from_variant(entry, &iter_dict_val)) {
  919. wpa_printf(MSG_DEBUG,
  920. "%s: failed to fetch dict values from variant",
  921. __func__);
  922. goto error;
  923. }
  924. dbus_message_iter_next(iter_dict);
  925. return TRUE;
  926. error:
  927. if (entry) {
  928. wpa_dbus_dict_entry_clear(entry);
  929. entry->type = DBUS_TYPE_INVALID;
  930. entry->array_type = DBUS_TYPE_INVALID;
  931. }
  932. return FALSE;
  933. }
  934. /**
  935. * Return whether or not there are additional dictionary entries.
  936. *
  937. * @param iter_dict A valid DBusMessageIter returned from
  938. * wpa_dbus_dict_open_read()
  939. * @return TRUE if more dict entries exists, FALSE if no more dict entries
  940. * exist
  941. */
  942. dbus_bool_t wpa_dbus_dict_has_dict_entry(DBusMessageIter *iter_dict)
  943. {
  944. if (!iter_dict)
  945. return FALSE;
  946. return dbus_message_iter_get_arg_type(iter_dict) ==
  947. DBUS_TYPE_DICT_ENTRY;
  948. }
  949. /**
  950. * Free any memory used by the entry object.
  951. *
  952. * @param entry The entry object
  953. */
  954. void wpa_dbus_dict_entry_clear(struct wpa_dbus_dict_entry *entry)
  955. {
  956. unsigned int i;
  957. if (!entry)
  958. return;
  959. switch (entry->type) {
  960. case DBUS_TYPE_OBJECT_PATH:
  961. case DBUS_TYPE_STRING:
  962. os_free(entry->str_value);
  963. break;
  964. case DBUS_TYPE_ARRAY:
  965. switch (entry->array_type) {
  966. case DBUS_TYPE_BYTE:
  967. os_free(entry->bytearray_value);
  968. break;
  969. case DBUS_TYPE_STRING:
  970. for (i = 0; i < entry->array_len; i++)
  971. os_free(entry->strarray_value[i]);
  972. os_free(entry->strarray_value);
  973. break;
  974. case WPAS_DBUS_TYPE_BINARRAY:
  975. for (i = 0; i < entry->array_len; i++)
  976. wpabuf_free(entry->binarray_value[i]);
  977. os_free(entry->binarray_value);
  978. break;
  979. }
  980. break;
  981. }
  982. os_memset(entry, 0, sizeof(struct wpa_dbus_dict_entry));
  983. }