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