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 	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 }
   1136