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