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