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