D-Bus: Simplify message building error paths
[mech_eap.git] / 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->bytearray_value = buffer;
704         entry->array_len = 0;
705         while (dbus_message_iter_get_arg_type(iter) == DBUS_TYPE_BYTE) {
706                 char byte;
707
708                 if ((count % BYTE_ARRAY_CHUNK_SIZE) == 0 && count != 0) {
709                         nbuffer = os_realloc_array(
710                                 buffer, count + BYTE_ARRAY_CHUNK_SIZE,
711                                 BYTE_ARRAY_ITEM_SIZE);
712                         if (nbuffer == NULL) {
713                                 os_free(buffer);
714                                 wpa_printf(MSG_ERROR, "dbus: _wpa_dbus_dict_"
715                                            "entry_get_byte_array out of "
716                                            "memory trying to retrieve the "
717                                            "string array");
718                                 goto done;
719                         }
720                         buffer = nbuffer;
721                 }
722                 entry->bytearray_value = buffer;
723
724                 dbus_message_iter_get_basic(iter, &byte);
725                 entry->bytearray_value[count] = byte;
726                 entry->array_len = ++count;
727                 dbus_message_iter_next(iter);
728         }
729         wpa_hexdump_key(MSG_MSGDUMP, "dbus: byte array contents",
730                         entry->bytearray_value, entry->array_len);
731
732         /* Zero-length arrays are valid. */
733         if (entry->array_len == 0) {
734                 os_free(entry->bytearray_value);
735                 entry->bytearray_value = NULL;
736         }
737
738         success = TRUE;
739
740 done:
741         return success;
742 }
743
744
745 #define STR_ARRAY_CHUNK_SIZE 8
746 #define STR_ARRAY_ITEM_SIZE (sizeof(char *))
747
748 static dbus_bool_t _wpa_dbus_dict_entry_get_string_array(
749         DBusMessageIter *iter, int array_type,
750         struct wpa_dbus_dict_entry *entry)
751 {
752         dbus_uint32_t count = 0;
753         dbus_bool_t success = FALSE;
754         char **buffer, **nbuffer;
755
756         entry->strarray_value = NULL;
757         entry->array_type = DBUS_TYPE_STRING;
758
759         buffer = os_calloc(STR_ARRAY_CHUNK_SIZE, STR_ARRAY_ITEM_SIZE);
760         if (buffer == NULL)
761                 return FALSE;
762
763         entry->strarray_value = buffer;
764         entry->array_len = 0;
765         while (dbus_message_iter_get_arg_type(iter) == DBUS_TYPE_STRING) {
766                 const char *value;
767                 char *str;
768
769                 if ((count % STR_ARRAY_CHUNK_SIZE) == 0 && count != 0) {
770                         nbuffer = os_realloc_array(
771                                 buffer, count + STR_ARRAY_CHUNK_SIZE,
772                                 STR_ARRAY_ITEM_SIZE);
773                         if (nbuffer == NULL) {
774                                 os_free(buffer);
775                                 wpa_printf(MSG_ERROR, "dbus: _wpa_dbus_dict_"
776                                            "entry_get_string_array out of "
777                                            "memory trying to retrieve the "
778                                            "string array");
779                                 goto done;
780                         }
781                         buffer = nbuffer;
782                 }
783                 entry->strarray_value = buffer;
784
785                 dbus_message_iter_get_basic(iter, &value);
786                 wpa_printf(MSG_MSGDUMP, "%s: string_array value: %s",
787                            __func__, wpa_debug_show_keys ? value : "[omitted]");
788                 str = os_strdup(value);
789                 if (str == NULL) {
790                         wpa_printf(MSG_ERROR, "dbus: _wpa_dbus_dict_entry_get_"
791                                    "string_array out of memory trying to "
792                                    "duplicate the string array");
793                         goto done;
794                 }
795                 entry->strarray_value[count] = str;
796                 entry->array_len = ++count;
797                 dbus_message_iter_next(iter);
798         }
799         wpa_printf(MSG_MSGDUMP, "%s: string_array length %u",
800                    __func__, entry->array_len);
801
802         /* Zero-length arrays are valid. */
803         if (entry->array_len == 0) {
804                 os_free(entry->strarray_value);
805                 entry->strarray_value = NULL;
806         }
807
808         success = TRUE;
809
810 done:
811         return success;
812 }
813
814
815 #define BIN_ARRAY_CHUNK_SIZE 10
816 #define BIN_ARRAY_ITEM_SIZE (sizeof(struct wpabuf *))
817
818 static dbus_bool_t _wpa_dbus_dict_entry_get_binarray(
819         DBusMessageIter *iter, struct wpa_dbus_dict_entry *entry)
820 {
821         struct wpa_dbus_dict_entry tmpentry;
822         size_t buflen = 0;
823         int i, type;
824
825         entry->array_type = WPAS_DBUS_TYPE_BINARRAY;
826         entry->array_len = 0;
827         entry->binarray_value = NULL;
828
829         type = dbus_message_iter_get_arg_type(iter);
830         wpa_printf(MSG_MSGDUMP, "%s: parsing binarray type %c", __func__, type);
831         if (type == DBUS_TYPE_INVALID) {
832                 /* Likely an empty array of arrays */
833                 return TRUE;
834         }
835         if (type != DBUS_TYPE_ARRAY) {
836                 wpa_printf(MSG_DEBUG, "%s: not an array type: %c",
837                            __func__, type);
838                 return FALSE;
839         }
840
841         type = dbus_message_iter_get_element_type(iter);
842         if (type != DBUS_TYPE_BYTE) {
843                 wpa_printf(MSG_DEBUG, "%s: unexpected element type %c",
844                            __func__, type);
845                 return FALSE;
846         }
847
848         while (dbus_message_iter_get_arg_type(iter) == DBUS_TYPE_ARRAY) {
849                 DBusMessageIter iter_array;
850
851                 if (entry->array_len == buflen) {
852                         struct wpabuf **newbuf;
853
854                         buflen += BIN_ARRAY_CHUNK_SIZE;
855
856                         newbuf = os_realloc_array(entry->binarray_value,
857                                                   buflen, BIN_ARRAY_ITEM_SIZE);
858                         if (!newbuf)
859                                 goto cleanup;
860                         entry->binarray_value = newbuf;
861                 }
862
863                 dbus_message_iter_recurse(iter, &iter_array);
864                 os_memset(&tmpentry, 0, sizeof(tmpentry));
865                 tmpentry.type = DBUS_TYPE_ARRAY;
866                 if (_wpa_dbus_dict_entry_get_byte_array(&iter_array, &tmpentry)
867                                         == FALSE)
868                         goto cleanup;
869
870                 entry->binarray_value[entry->array_len] =
871                         wpabuf_alloc_ext_data((u8 *) tmpentry.bytearray_value,
872                                               tmpentry.array_len);
873                 if (entry->binarray_value[entry->array_len] == NULL) {
874                         wpa_dbus_dict_entry_clear(&tmpentry);
875                         goto cleanup;
876                 }
877                 entry->array_len++;
878                 dbus_message_iter_next(iter);
879         }
880         wpa_printf(MSG_MSGDUMP, "%s: binarray length %u",
881                    __func__, entry->array_len);
882
883         return TRUE;
884
885  cleanup:
886         for (i = 0; i < (int) entry->array_len; i++)
887                 wpabuf_free(entry->binarray_value[i]);
888         os_free(entry->binarray_value);
889         entry->array_len = 0;
890         entry->binarray_value = NULL;
891         return FALSE;
892 }
893
894
895 static dbus_bool_t _wpa_dbus_dict_entry_get_array(
896         DBusMessageIter *iter_dict_val, struct wpa_dbus_dict_entry *entry)
897 {
898         int array_type = dbus_message_iter_get_element_type(iter_dict_val);
899         dbus_bool_t success = FALSE;
900         DBusMessageIter iter_array;
901
902         wpa_printf(MSG_MSGDUMP, "%s: array_type %c", __func__, array_type);
903
904         dbus_message_iter_recurse(iter_dict_val, &iter_array);
905
906         switch (array_type) {
907         case DBUS_TYPE_BYTE:
908                 success = _wpa_dbus_dict_entry_get_byte_array(&iter_array,
909                                                               entry);
910                 break;
911         case DBUS_TYPE_STRING:
912                 success = _wpa_dbus_dict_entry_get_string_array(&iter_array,
913                                                                 array_type,
914                                                                 entry);
915                 break;
916         case DBUS_TYPE_ARRAY:
917                 success = _wpa_dbus_dict_entry_get_binarray(&iter_array, entry);
918                 break;
919         default:
920                 wpa_printf(MSG_MSGDUMP, "%s: unsupported array type %c",
921                            __func__, array_type);
922                 break;
923         }
924
925         return success;
926 }
927
928
929 static dbus_bool_t _wpa_dbus_dict_fill_value_from_variant(
930         struct wpa_dbus_dict_entry *entry, DBusMessageIter *iter)
931 {
932         const char *v;
933
934         switch (entry->type) {
935         case DBUS_TYPE_OBJECT_PATH:
936                 dbus_message_iter_get_basic(iter, &v);
937                 wpa_printf(MSG_MSGDUMP, "%s: object path value: %s",
938                            __func__, v);
939                 entry->str_value = os_strdup(v);
940                 if (entry->str_value == NULL)
941                         return FALSE;
942                 break;
943         case DBUS_TYPE_STRING:
944                 dbus_message_iter_get_basic(iter, &v);
945                 wpa_printf(MSG_MSGDUMP, "%s: string value: %s",
946                            __func__, wpa_debug_show_keys ? v : "[omitted]");
947                 entry->str_value = os_strdup(v);
948                 if (entry->str_value == NULL)
949                         return FALSE;
950                 break;
951         case DBUS_TYPE_BOOLEAN:
952                 dbus_message_iter_get_basic(iter, &entry->bool_value);
953                 wpa_printf(MSG_MSGDUMP, "%s: boolean value: %d",
954                            __func__, entry->bool_value);
955                 break;
956         case DBUS_TYPE_BYTE:
957                 dbus_message_iter_get_basic(iter, &entry->byte_value);
958                 wpa_printf(MSG_MSGDUMP, "%s: byte value: %d",
959                            __func__, entry->byte_value);
960                 break;
961         case DBUS_TYPE_INT16:
962                 dbus_message_iter_get_basic(iter, &entry->int16_value);
963                 wpa_printf(MSG_MSGDUMP, "%s: int16 value: %d",
964                            __func__, entry->int16_value);
965                 break;
966         case DBUS_TYPE_UINT16:
967                 dbus_message_iter_get_basic(iter, &entry->uint16_value);
968                 wpa_printf(MSG_MSGDUMP, "%s: uint16 value: %d",
969                            __func__, entry->uint16_value);
970                 break;
971         case DBUS_TYPE_INT32:
972                 dbus_message_iter_get_basic(iter, &entry->int32_value);
973                 wpa_printf(MSG_MSGDUMP, "%s: int32 value: %d",
974                            __func__, entry->int32_value);
975                 break;
976         case DBUS_TYPE_UINT32:
977                 dbus_message_iter_get_basic(iter, &entry->uint32_value);
978                 wpa_printf(MSG_MSGDUMP, "%s: uint32 value: %d",
979                            __func__, entry->uint32_value);
980                 break;
981         case DBUS_TYPE_INT64:
982                 dbus_message_iter_get_basic(iter, &entry->int64_value);
983                 wpa_printf(MSG_MSGDUMP, "%s: int64 value: %lld",
984                            __func__, (long long int) entry->int64_value);
985                 break;
986         case DBUS_TYPE_UINT64:
987                 dbus_message_iter_get_basic(iter, &entry->uint64_value);
988                 wpa_printf(MSG_MSGDUMP, "%s: uint64 value: %llu",
989                            __func__,
990                            (unsigned long long int) entry->uint64_value);
991                 break;
992         case DBUS_TYPE_DOUBLE:
993                 dbus_message_iter_get_basic(iter, &entry->double_value);
994                 wpa_printf(MSG_MSGDUMP, "%s: double value: %f",
995                            __func__, entry->double_value);
996                 break;
997         case DBUS_TYPE_ARRAY:
998                 return _wpa_dbus_dict_entry_get_array(iter, entry);
999         default:
1000                 wpa_printf(MSG_MSGDUMP, "%s: unsupported type %c",
1001                            __func__, entry->type);
1002                 return FALSE;
1003         }
1004
1005         return TRUE;
1006 }
1007
1008
1009 /**
1010  * Read the current key/value entry from the dict.  Entries are dynamically
1011  * allocated when needed and must be freed after use with the
1012  * wpa_dbus_dict_entry_clear() function.
1013  *
1014  * The returned entry object will be filled with the type and value of the next
1015  * entry in the dict, or the type will be DBUS_TYPE_INVALID if an error
1016  * occurred.
1017  *
1018  * @param iter_dict A valid DBusMessageIter returned from
1019  *    wpa_dbus_dict_open_read()
1020  * @param entry A valid dict entry object into which the dict key and value
1021  *    will be placed
1022  * @return TRUE on success, FALSE on failure
1023  *
1024  */
1025 dbus_bool_t wpa_dbus_dict_get_entry(DBusMessageIter *iter_dict,
1026                                     struct wpa_dbus_dict_entry * entry)
1027 {
1028         DBusMessageIter iter_dict_entry, iter_dict_val;
1029         int type;
1030         const char *key;
1031
1032         if (!iter_dict || !entry ||
1033             dbus_message_iter_get_arg_type(iter_dict) != DBUS_TYPE_DICT_ENTRY) {
1034                 wpa_printf(MSG_DEBUG, "%s: not a dict entry", __func__);
1035                 goto error;
1036         }
1037
1038         dbus_message_iter_recurse(iter_dict, &iter_dict_entry);
1039         dbus_message_iter_get_basic(&iter_dict_entry, &key);
1040         wpa_printf(MSG_MSGDUMP, "%s: dict entry key: %s", __func__, key);
1041         entry->key = key;
1042
1043         if (!dbus_message_iter_next(&iter_dict_entry)) {
1044                 wpa_printf(MSG_DEBUG, "%s: no variant in dict entry", __func__);
1045                 goto error;
1046         }
1047         type = dbus_message_iter_get_arg_type(&iter_dict_entry);
1048         if (type != DBUS_TYPE_VARIANT) {
1049                 wpa_printf(MSG_DEBUG,
1050                            "%s: unexpected dict entry variant type: %c",
1051                            __func__, type);
1052                 goto error;
1053         }
1054
1055         dbus_message_iter_recurse(&iter_dict_entry, &iter_dict_val);
1056         entry->type = dbus_message_iter_get_arg_type(&iter_dict_val);
1057         wpa_printf(MSG_MSGDUMP, "%s: dict entry variant content type: %c",
1058                    __func__, entry->type);
1059         entry->array_type = DBUS_TYPE_INVALID;
1060         if (!_wpa_dbus_dict_fill_value_from_variant(entry, &iter_dict_val)) {
1061                 wpa_printf(MSG_DEBUG,
1062                            "%s: failed to fetch dict values from variant",
1063                            __func__);
1064                 goto error;
1065         }
1066
1067         dbus_message_iter_next(iter_dict);
1068         return TRUE;
1069
1070 error:
1071         if (entry) {
1072                 wpa_dbus_dict_entry_clear(entry);
1073                 entry->type = DBUS_TYPE_INVALID;
1074                 entry->array_type = DBUS_TYPE_INVALID;
1075         }
1076
1077         return FALSE;
1078 }
1079
1080
1081 /**
1082  * Return whether or not there are additional dictionary entries.
1083  *
1084  * @param iter_dict A valid DBusMessageIter returned from
1085  *    wpa_dbus_dict_open_read()
1086  * @return TRUE if more dict entries exists, FALSE if no more dict entries
1087  * exist
1088  */
1089 dbus_bool_t wpa_dbus_dict_has_dict_entry(DBusMessageIter *iter_dict)
1090 {
1091         if (!iter_dict)
1092                 return FALSE;
1093         return dbus_message_iter_get_arg_type(iter_dict) ==
1094                 DBUS_TYPE_DICT_ENTRY;
1095 }
1096
1097
1098 /**
1099  * Free any memory used by the entry object.
1100  *
1101  * @param entry The entry object
1102  */
1103 void wpa_dbus_dict_entry_clear(struct wpa_dbus_dict_entry *entry)
1104 {
1105         unsigned int i;
1106
1107         if (!entry)
1108                 return;
1109         switch (entry->type) {
1110         case DBUS_TYPE_OBJECT_PATH:
1111         case DBUS_TYPE_STRING:
1112                 os_free(entry->str_value);
1113                 break;
1114         case DBUS_TYPE_ARRAY:
1115                 switch (entry->array_type) {
1116                 case DBUS_TYPE_BYTE:
1117                         os_free(entry->bytearray_value);
1118                         break;
1119                 case DBUS_TYPE_STRING:
1120                         for (i = 0; i < entry->array_len; i++)
1121                                 os_free(entry->strarray_value[i]);
1122                         os_free(entry->strarray_value);
1123                         break;
1124                 case WPAS_DBUS_TYPE_BINARRAY:
1125                         for (i = 0; i < entry->array_len; i++)
1126                                 wpabuf_free(entry->binarray_value[i]);
1127                         os_free(entry->binarray_value);
1128                         break;
1129                 }
1130                 break;
1131         }
1132
1133         os_memset(entry, 0, sizeof(struct wpa_dbus_dict_entry));
1134 }