xref: /freebsd/contrib/wpa/wpa_supplicant/dbus/dbus_dict_helpers.c (revision 7d99ab9fd0cc2c1ce2ecef0ed6d0672c2a50b0cb)
1 /*
2  * WPA Supplicant / dbus-based control interface
3  * Copyright (c) 2006, Dan Williams <dcbw@redhat.com> and Red Hat, Inc.
4  *
5  * This program is free software; you can redistribute it and/or modify
6  * it under the terms of the GNU General Public License version 2 as
7  * published by the Free Software Foundation.
8  *
9  * Alternatively, this software may be distributed under the terms of BSD
10  * license.
11  *
12  * See README and COPYING for more details.
13  */
14 
15 #include "includes.h"
16 #include <dbus/dbus.h>
17 
18 #include "common.h"
19 #include "dbus_dict_helpers.h"
20 
21 
22 /**
23  * Start a dict in a dbus message.  Should be paired with a call to
24  * wpa_dbus_dict_close_write().
25  *
26  * @param iter A valid dbus message iterator
27  * @param iter_dict (out) A dict iterator to pass to further dict functions
28  * @return TRUE on success, FALSE on failure
29  *
30  */
31 dbus_bool_t wpa_dbus_dict_open_write(DBusMessageIter *iter,
32 				     DBusMessageIter *iter_dict)
33 {
34 	dbus_bool_t result;
35 
36 	if (!iter || !iter_dict)
37 		return FALSE;
38 
39 	result = dbus_message_iter_open_container(
40 		iter,
41 		DBUS_TYPE_ARRAY,
42 		DBUS_DICT_ENTRY_BEGIN_CHAR_AS_STRING
43 		DBUS_TYPE_STRING_AS_STRING
44 		DBUS_TYPE_VARIANT_AS_STRING
45 		DBUS_DICT_ENTRY_END_CHAR_AS_STRING,
46 		iter_dict);
47 	return result;
48 }
49 
50 
51 /**
52  * End a dict element in a dbus message.  Should be paired with
53  * a call to wpa_dbus_dict_open_write().
54  *
55  * @param iter valid dbus message iterator, same as passed to
56  *    wpa_dbus_dict_open_write()
57  * @param iter_dict a dbus dict iterator returned from
58  *    wpa_dbus_dict_open_write()
59  * @return TRUE on success, FALSE on failure
60  *
61  */
62 dbus_bool_t wpa_dbus_dict_close_write(DBusMessageIter *iter,
63 				      DBusMessageIter *iter_dict)
64 {
65 	if (!iter || !iter_dict)
66 		return FALSE;
67 
68 	return dbus_message_iter_close_container(iter, iter_dict);
69 }
70 
71 
72 const char * wpa_dbus_type_as_string(const int type)
73 {
74 	switch(type) {
75 	case DBUS_TYPE_BYTE:
76 		return DBUS_TYPE_BYTE_AS_STRING;
77 	case DBUS_TYPE_BOOLEAN:
78 		return DBUS_TYPE_BOOLEAN_AS_STRING;
79 	case DBUS_TYPE_INT16:
80 		return DBUS_TYPE_INT16_AS_STRING;
81 	case DBUS_TYPE_UINT16:
82 		return DBUS_TYPE_UINT16_AS_STRING;
83 	case DBUS_TYPE_INT32:
84 		return DBUS_TYPE_INT32_AS_STRING;
85 	case DBUS_TYPE_UINT32:
86 		return DBUS_TYPE_UINT32_AS_STRING;
87 	case DBUS_TYPE_INT64:
88 		return DBUS_TYPE_INT64_AS_STRING;
89 	case DBUS_TYPE_UINT64:
90 		return DBUS_TYPE_UINT64_AS_STRING;
91 	case DBUS_TYPE_DOUBLE:
92 		return DBUS_TYPE_DOUBLE_AS_STRING;
93 	case DBUS_TYPE_STRING:
94 		return DBUS_TYPE_STRING_AS_STRING;
95 	case DBUS_TYPE_OBJECT_PATH:
96 		return DBUS_TYPE_OBJECT_PATH_AS_STRING;
97 	case DBUS_TYPE_ARRAY:
98 		return DBUS_TYPE_ARRAY_AS_STRING;
99 	default:
100 		return NULL;
101 	}
102 }
103 
104 
105 static dbus_bool_t _wpa_dbus_add_dict_entry_start(
106 	DBusMessageIter *iter_dict, DBusMessageIter *iter_dict_entry,
107 	const char *key, const int value_type)
108 {
109 	if (!dbus_message_iter_open_container(iter_dict,
110 					      DBUS_TYPE_DICT_ENTRY, NULL,
111 					      iter_dict_entry))
112 		return FALSE;
113 
114 	if (!dbus_message_iter_append_basic(iter_dict_entry, DBUS_TYPE_STRING,
115 					    &key))
116 		return FALSE;
117 
118 	return TRUE;
119 }
120 
121 
122 static dbus_bool_t _wpa_dbus_add_dict_entry_end(
123 	DBusMessageIter *iter_dict, DBusMessageIter *iter_dict_entry,
124 	DBusMessageIter *iter_dict_val)
125 {
126 	if (!dbus_message_iter_close_container(iter_dict_entry, iter_dict_val))
127 		return FALSE;
128 	if (!dbus_message_iter_close_container(iter_dict, iter_dict_entry))
129 		return FALSE;
130 
131 	return TRUE;
132 }
133 
134 
135 static dbus_bool_t _wpa_dbus_add_dict_entry_basic(DBusMessageIter *iter_dict,
136 						  const char *key,
137 						  const int value_type,
138 						  const void *value)
139 {
140 	DBusMessageIter iter_dict_entry, iter_dict_val;
141 	const char *type_as_string = NULL;
142 
143 	if (key == NULL)
144 		return FALSE;
145 
146 	type_as_string = wpa_dbus_type_as_string(value_type);
147 	if (!type_as_string)
148 		return FALSE;
149 
150 	if (!_wpa_dbus_add_dict_entry_start(iter_dict, &iter_dict_entry,
151 					    key, value_type))
152 		return FALSE;
153 
154 	if (!dbus_message_iter_open_container(&iter_dict_entry,
155 					      DBUS_TYPE_VARIANT,
156 					      type_as_string, &iter_dict_val))
157 		return FALSE;
158 
159 	if (!dbus_message_iter_append_basic(&iter_dict_val, value_type, value))
160 		return FALSE;
161 
162 	if (!_wpa_dbus_add_dict_entry_end(iter_dict, &iter_dict_entry,
163 					  &iter_dict_val))
164 		return FALSE;
165 
166 	return TRUE;
167 }
168 
169 
170 static dbus_bool_t _wpa_dbus_add_dict_entry_byte_array(
171 	DBusMessageIter *iter_dict, const char *key,
172 	const char *value, const dbus_uint32_t value_len)
173 {
174 	DBusMessageIter iter_dict_entry, iter_dict_val, iter_array;
175 	dbus_uint32_t i;
176 
177 	if (!_wpa_dbus_add_dict_entry_start(iter_dict, &iter_dict_entry,
178 					    key, DBUS_TYPE_ARRAY))
179 		return FALSE;
180 
181 	if (!dbus_message_iter_open_container(&iter_dict_entry,
182 					      DBUS_TYPE_VARIANT,
183 					      DBUS_TYPE_ARRAY_AS_STRING
184 					      DBUS_TYPE_BYTE_AS_STRING,
185 					      &iter_dict_val))
186 		return FALSE;
187 
188 	if (!dbus_message_iter_open_container(&iter_dict_val, DBUS_TYPE_ARRAY,
189 					      DBUS_TYPE_BYTE_AS_STRING,
190 					      &iter_array))
191 		return FALSE;
192 
193 	for (i = 0; i < value_len; i++) {
194 		if (!dbus_message_iter_append_basic(&iter_array,
195 						    DBUS_TYPE_BYTE,
196 						    &(value[i])))
197 			return FALSE;
198 	}
199 
200 	if (!dbus_message_iter_close_container(&iter_dict_val, &iter_array))
201 		return FALSE;
202 
203 	if (!_wpa_dbus_add_dict_entry_end(iter_dict, &iter_dict_entry,
204 					  &iter_dict_val))
205 		return FALSE;
206 
207 	return TRUE;
208 }
209 
210 
211 /**
212  * Add a string entry to the dict.
213  *
214  * @param iter_dict A valid DBusMessageIter returned from
215  *    wpa_dbus_dict_open_write()
216  * @param key The key of the dict item
217  * @param value The string value
218  * @return TRUE on success, FALSE on failure
219  *
220  */
221 dbus_bool_t wpa_dbus_dict_append_string(DBusMessageIter *iter_dict,
222 					const char *key, const char *value)
223 {
224 	if (!value)
225 		return FALSE;
226 	return _wpa_dbus_add_dict_entry_basic(iter_dict, key, DBUS_TYPE_STRING,
227 					      &value);
228 }
229 
230 
231 /**
232  * Add a byte entry to the dict.
233  *
234  * @param iter_dict A valid DBusMessageIter returned from
235  *    wpa_dbus_dict_open_write()
236  * @param key The key of the dict item
237  * @param value The byte value
238  * @return TRUE on success, FALSE on failure
239  *
240  */
241 dbus_bool_t wpa_dbus_dict_append_byte(DBusMessageIter *iter_dict,
242 				      const char *key, const char value)
243 {
244 	return _wpa_dbus_add_dict_entry_basic(iter_dict, key, DBUS_TYPE_BYTE,
245 					      &value);
246 }
247 
248 
249 /**
250  * Add a boolean entry to the dict.
251  *
252  * @param iter_dict A valid DBusMessageIter returned from
253  *    wpa_dbus_dict_open_write()
254  * @param key The key of the dict item
255  * @param value The boolean value
256  * @return TRUE on success, FALSE on failure
257  *
258  */
259 dbus_bool_t wpa_dbus_dict_append_bool(DBusMessageIter *iter_dict,
260 				      const char *key, const dbus_bool_t value)
261 {
262 	return _wpa_dbus_add_dict_entry_basic(iter_dict, key,
263 					      DBUS_TYPE_BOOLEAN, &value);
264 }
265 
266 
267 /**
268  * Add a 16-bit signed integer entry to the dict.
269  *
270  * @param iter_dict A valid DBusMessageIter returned from
271  *    wpa_dbus_dict_open_write()
272  * @param key The key of the dict item
273  * @param value The 16-bit signed integer value
274  * @return TRUE on success, FALSE on failure
275  *
276  */
277 dbus_bool_t wpa_dbus_dict_append_int16(DBusMessageIter *iter_dict,
278 				       const char *key,
279 				       const dbus_int16_t value)
280 {
281 	return _wpa_dbus_add_dict_entry_basic(iter_dict, key, DBUS_TYPE_INT16,
282 					      &value);
283 }
284 
285 
286 /**
287  * Add a 16-bit unsigned integer entry to the dict.
288  *
289  * @param iter_dict A valid DBusMessageIter returned from
290  *    wpa_dbus_dict_open_write()
291  * @param key The key of the dict item
292  * @param value The 16-bit unsigned integer value
293  * @return TRUE on success, FALSE on failure
294  *
295  */
296 dbus_bool_t wpa_dbus_dict_append_uint16(DBusMessageIter *iter_dict,
297 					const char *key,
298 					const dbus_uint16_t value)
299 {
300 	return _wpa_dbus_add_dict_entry_basic(iter_dict, key, DBUS_TYPE_UINT16,
301 					      &value);
302 }
303 
304 
305 /**
306  * Add a 32-bit signed integer to the dict.
307  *
308  * @param iter_dict A valid DBusMessageIter returned from
309  *    wpa_dbus_dict_open_write()
310  * @param key The key of the dict item
311  * @param value The 32-bit signed integer value
312  * @return TRUE on success, FALSE on failure
313  *
314  */
315 dbus_bool_t wpa_dbus_dict_append_int32(DBusMessageIter *iter_dict,
316 				       const char *key,
317 				       const dbus_int32_t value)
318 {
319 	return _wpa_dbus_add_dict_entry_basic(iter_dict, key, DBUS_TYPE_INT32,
320 					      &value);
321 }
322 
323 
324 /**
325  * Add a 32-bit unsigned integer entry to the dict.
326  *
327  * @param iter_dict A valid DBusMessageIter returned from
328  *    wpa_dbus_dict_open_write()
329  * @param key The key of the dict item
330  * @param value The 32-bit unsigned integer value
331  * @return TRUE on success, FALSE on failure
332  *
333  */
334 dbus_bool_t wpa_dbus_dict_append_uint32(DBusMessageIter *iter_dict,
335 					const char *key,
336 					const dbus_uint32_t value)
337 {
338 	return _wpa_dbus_add_dict_entry_basic(iter_dict, key, DBUS_TYPE_UINT32,
339 					      &value);
340 }
341 
342 
343 /**
344  * Add a 64-bit integer entry to the dict.
345  *
346  * @param iter_dict A valid DBusMessageIter returned from
347  *    wpa_dbus_dict_open_write()
348  * @param key The key of the dict item
349  * @param value The 64-bit integer value
350  * @return TRUE on success, FALSE on failure
351  *
352  */
353 dbus_bool_t wpa_dbus_dict_append_int64(DBusMessageIter *iter_dict,
354 				       const char *key,
355 				       const dbus_int64_t value)
356 {
357 	return _wpa_dbus_add_dict_entry_basic(iter_dict, key, DBUS_TYPE_INT64,
358 					      &value);
359 }
360 
361 
362 /**
363  * Add a 64-bit unsigned integer entry to the dict.
364  *
365  * @param iter_dict A valid DBusMessageIter returned from
366  *    wpa_dbus_dict_open_write()
367  * @param key The key of the dict item
368  * @param value The 64-bit unsigned integer value
369  * @return TRUE on success, FALSE on failure
370  *
371  */
372 dbus_bool_t wpa_dbus_dict_append_uint64(DBusMessageIter *iter_dict,
373 					const char *key,
374 					const dbus_uint64_t value)
375 {
376 	return _wpa_dbus_add_dict_entry_basic(iter_dict, key, DBUS_TYPE_UINT64,
377 					      &value);
378 }
379 
380 
381 /**
382  * Add a double-precision floating point entry to the dict.
383  *
384  * @param iter_dict A valid DBusMessageIter returned from
385  *    wpa_dbus_dict_open_write()
386  * @param key The key of the dict item
387  * @param value The double-precision floating point value
388  * @return TRUE on success, FALSE on failure
389  *
390  */
391 dbus_bool_t wpa_dbus_dict_append_double(DBusMessageIter *iter_dict,
392 					const char *key, const double value)
393 {
394 	return _wpa_dbus_add_dict_entry_basic(iter_dict, key, DBUS_TYPE_DOUBLE,
395 					      &value);
396 }
397 
398 
399 /**
400  * Add a DBus object path entry to the dict.
401  *
402  * @param iter_dict A valid DBusMessageIter returned from
403  *    wpa_dbus_dict_open_write()
404  * @param key The key of the dict item
405  * @param value The DBus object path value
406  * @return TRUE on success, FALSE on failure
407  *
408  */
409 dbus_bool_t wpa_dbus_dict_append_object_path(DBusMessageIter *iter_dict,
410 					     const char *key,
411 					     const char *value)
412 {
413 	if (!value)
414 		return FALSE;
415 	return _wpa_dbus_add_dict_entry_basic(iter_dict, key,
416 					      DBUS_TYPE_OBJECT_PATH, &value);
417 }
418 
419 
420 /**
421  * Add a byte array entry to the dict.
422  *
423  * @param iter_dict A valid DBusMessageIter returned from
424  *    wpa_dbus_dict_open_write()
425  * @param key The key of the dict item
426  * @param value The byte array
427  * @param value_len The length of the byte array, in bytes
428  * @return TRUE on success, FALSE on failure
429  *
430  */
431 dbus_bool_t wpa_dbus_dict_append_byte_array(DBusMessageIter *iter_dict,
432 					    const char *key,
433 					    const char *value,
434 					    const dbus_uint32_t value_len)
435 {
436 	if (!key)
437 		return FALSE;
438 	if (!value && (value_len != 0))
439 		return FALSE;
440 	return _wpa_dbus_add_dict_entry_byte_array(iter_dict, key, value,
441 						   value_len);
442 }
443 
444 
445 /**
446  * Begin a string array entry in the dict
447  *
448  * @param iter_dict A valid DBusMessageIter returned from
449  *                  wpa_dbus_dict_open_write()
450  * @param key The key of the dict item
451  * @param iter_dict_entry A private DBusMessageIter provided by the caller to
452  *                        be passed to wpa_dbus_dict_end_string_array()
453  * @param iter_dict_val A private DBusMessageIter provided by the caller to
454  *                      be passed to wpa_dbus_dict_end_string_array()
455  * @param iter_array On return, the DBusMessageIter to be passed to
456  *                   wpa_dbus_dict_string_array_add_element()
457  * @return TRUE on success, FALSE on failure
458  *
459  */
460 dbus_bool_t wpa_dbus_dict_begin_string_array(DBusMessageIter *iter_dict,
461 					     const char *key,
462 					     DBusMessageIter *iter_dict_entry,
463 					     DBusMessageIter *iter_dict_val,
464 					     DBusMessageIter *iter_array)
465 {
466 	if (!iter_dict || !iter_dict_entry || !iter_dict_val || !iter_array)
467 		return FALSE;
468 
469 	if (!_wpa_dbus_add_dict_entry_start(iter_dict, iter_dict_entry,
470 					    key, DBUS_TYPE_ARRAY))
471 		return FALSE;
472 
473 	if (!dbus_message_iter_open_container(iter_dict_entry,
474 					      DBUS_TYPE_VARIANT,
475 					      DBUS_TYPE_ARRAY_AS_STRING
476 					      DBUS_TYPE_STRING_AS_STRING,
477 					      iter_dict_val))
478 		return FALSE;
479 
480 	if (!dbus_message_iter_open_container(iter_dict_val, DBUS_TYPE_ARRAY,
481 					      DBUS_TYPE_BYTE_AS_STRING,
482 					      iter_array))
483 		return FALSE;
484 
485 	return TRUE;
486 }
487 
488 
489 /**
490  * Add a single string element to a string array dict entry
491  *
492  * @param iter_array A valid DBusMessageIter returned from
493  *                   wpa_dbus_dict_begin_string_array()'s
494  *                   iter_array parameter
495  * @param elem The string element to be added to the dict entry's string array
496  * @return TRUE on success, FALSE on failure
497  *
498  */
499 dbus_bool_t wpa_dbus_dict_string_array_add_element(DBusMessageIter *iter_array,
500 						   const char *elem)
501 {
502 	if (!iter_array || !elem)
503 		return FALSE;
504 
505 	return dbus_message_iter_append_basic(iter_array, DBUS_TYPE_STRING,
506 					      &elem);
507 }
508 
509 
510 /**
511  * End a string array dict entry
512  *
513  * @param iter_dict A valid DBusMessageIter returned from
514  *                  wpa_dbus_dict_open_write()
515  * @param iter_dict_entry A private DBusMessageIter returned from
516  *                        wpa_dbus_dict_end_string_array()
517  * @param iter_dict_val A private DBusMessageIter returned from
518  *                      wpa_dbus_dict_end_string_array()
519  * @param iter_array A DBusMessageIter returned from
520  *                   wpa_dbus_dict_end_string_array()
521  * @return TRUE on success, FALSE on failure
522  *
523  */
524 dbus_bool_t wpa_dbus_dict_end_string_array(DBusMessageIter *iter_dict,
525 					   DBusMessageIter *iter_dict_entry,
526 					   DBusMessageIter *iter_dict_val,
527 					   DBusMessageIter *iter_array)
528 {
529 	if (!iter_dict || !iter_dict_entry || !iter_dict_val || !iter_array)
530 		return FALSE;
531 
532 	if (!dbus_message_iter_close_container(iter_dict_val, iter_array))
533 		return FALSE;
534 
535 	if (!_wpa_dbus_add_dict_entry_end(iter_dict, iter_dict_entry,
536 					  iter_dict_val))
537 		return FALSE;
538 
539 	return TRUE;
540 }
541 
542 
543 /**
544  * Convenience function to add an entire string array to the dict.
545  *
546  * @param iter_dict A valid DBusMessageIter returned from
547  *                  wpa_dbus_dict_open_write()
548  * @param key The key of the dict item
549  * @param items The array of strings
550  * @param num_items The number of strings in the array
551  * @return TRUE on success, FALSE on failure
552  *
553  */
554 dbus_bool_t wpa_dbus_dict_append_string_array(DBusMessageIter *iter_dict,
555 					      const char *key,
556 					      const char **items,
557 					      const dbus_uint32_t num_items)
558 {
559 	DBusMessageIter iter_dict_entry, iter_dict_val, iter_array;
560 	dbus_uint32_t i;
561 
562 	if (!key)
563 		return FALSE;
564 	if (!items && (num_items != 0))
565 		return FALSE;
566 
567 	if (!wpa_dbus_dict_begin_string_array(iter_dict, key,
568 					      &iter_dict_entry, &iter_dict_val,
569 					      &iter_array))
570 		return FALSE;
571 
572 	for (i = 0; i < num_items; i++) {
573 		if (!wpa_dbus_dict_string_array_add_element(&iter_array,
574 							    items[i]))
575 			return FALSE;
576 	}
577 
578 	if (!wpa_dbus_dict_end_string_array(iter_dict, &iter_dict_entry,
579 					    &iter_dict_val, &iter_array))
580 		return FALSE;
581 
582 	return TRUE;
583 }
584 
585 
586 /*****************************************************/
587 /* Stuff for reading dicts                           */
588 /*****************************************************/
589 
590 /**
591  * Start reading from a dbus dict.
592  *
593  * @param iter A valid DBusMessageIter pointing to the start of the dict
594  * @param iter_dict (out) A DBusMessageIter to be passed to
595  *    wpa_dbus_dict_read_next_entry()
596  * @return TRUE on success, FALSE on failure
597  *
598  */
599 dbus_bool_t wpa_dbus_dict_open_read(DBusMessageIter *iter,
600 				    DBusMessageIter *iter_dict)
601 {
602 	if (!iter || !iter_dict)
603 		return FALSE;
604 
605 	if (dbus_message_iter_get_arg_type(iter) != DBUS_TYPE_ARRAY ||
606 	    dbus_message_iter_get_element_type(iter) != DBUS_TYPE_DICT_ENTRY)
607 		return FALSE;
608 
609 	dbus_message_iter_recurse(iter, iter_dict);
610 	return TRUE;
611 }
612 
613 
614 #define BYTE_ARRAY_CHUNK_SIZE 34
615 #define BYTE_ARRAY_ITEM_SIZE (sizeof(char))
616 
617 static dbus_bool_t _wpa_dbus_dict_entry_get_byte_array(
618 	DBusMessageIter *iter, int array_type,
619 	struct wpa_dbus_dict_entry *entry)
620 {
621 	dbus_uint32_t count = 0;
622 	dbus_bool_t success = FALSE;
623 	char *buffer, *nbuffer;;
624 
625 	entry->bytearray_value = NULL;
626 	entry->array_type = DBUS_TYPE_BYTE;
627 
628 	buffer = os_zalloc(BYTE_ARRAY_ITEM_SIZE * BYTE_ARRAY_CHUNK_SIZE);
629 	if (!buffer)
630 		return FALSE;
631 
632 	entry->bytearray_value = buffer;
633 	entry->array_len = 0;
634 	while (dbus_message_iter_get_arg_type(iter) == DBUS_TYPE_BYTE) {
635 		char byte;
636 
637 		if ((count % BYTE_ARRAY_CHUNK_SIZE) == 0 && count != 0) {
638 			nbuffer = os_realloc(buffer, BYTE_ARRAY_ITEM_SIZE *
639 					     (count + BYTE_ARRAY_CHUNK_SIZE));
640 			if (nbuffer == NULL) {
641 				os_free(buffer);
642 				wpa_printf(MSG_ERROR, "dbus: _wpa_dbus_dict_"
643 					   "entry_get_byte_array out of "
644 					   "memory trying to retrieve the "
645 					   "string array");
646 				goto done;
647 			}
648 			buffer = nbuffer;
649 		}
650 		entry->bytearray_value = buffer;
651 
652 		dbus_message_iter_get_basic(iter, &byte);
653 		entry->bytearray_value[count] = byte;
654 		entry->array_len = ++count;
655 		dbus_message_iter_next(iter);
656 	}
657 
658 	/* Zero-length arrays are valid. */
659 	if (entry->array_len == 0) {
660 		os_free(entry->bytearray_value);
661 		entry->bytearray_value = NULL;
662 	}
663 
664 	success = TRUE;
665 
666 done:
667 	return success;
668 }
669 
670 
671 #define STR_ARRAY_CHUNK_SIZE 8
672 #define STR_ARRAY_ITEM_SIZE (sizeof(char *))
673 
674 static dbus_bool_t _wpa_dbus_dict_entry_get_string_array(
675 	DBusMessageIter *iter, int array_type,
676 	struct wpa_dbus_dict_entry *entry)
677 {
678 	dbus_uint32_t count = 0;
679 	dbus_bool_t success = FALSE;
680 	char **buffer, **nbuffer;
681 
682 	entry->strarray_value = NULL;
683 	entry->array_type = DBUS_TYPE_STRING;
684 
685 	buffer = os_zalloc(STR_ARRAY_ITEM_SIZE * STR_ARRAY_CHUNK_SIZE);
686 	if (buffer == NULL)
687 		return FALSE;
688 
689 	entry->strarray_value = buffer;
690 	entry->array_len = 0;
691 	while (dbus_message_iter_get_arg_type(iter) == DBUS_TYPE_STRING) {
692 		const char *value;
693 		char *str;
694 
695 		if ((count % STR_ARRAY_CHUNK_SIZE) == 0 && count != 0) {
696 			nbuffer = os_realloc(buffer, STR_ARRAY_ITEM_SIZE *
697 					     (count + STR_ARRAY_CHUNK_SIZE));
698 			if (nbuffer == NULL) {
699 				os_free(buffer);
700 				wpa_printf(MSG_ERROR, "dbus: _wpa_dbus_dict_"
701 					   "entry_get_string_array out of "
702 					   "memory trying to retrieve the "
703 					   "string array");
704 				goto done;
705 			}
706 			buffer = nbuffer;
707 		}
708 		entry->strarray_value = buffer;
709 
710 		dbus_message_iter_get_basic(iter, &value);
711 		str = os_strdup(value);
712 		if (str == NULL) {
713 			wpa_printf(MSG_ERROR, "dbus: _wpa_dbus_dict_entry_get_"
714 				   "string_array out of memory trying to "
715 				   "duplicate the string array");
716 			goto done;
717 		}
718 		entry->strarray_value[count] = str;
719 		entry->array_len = ++count;
720 		dbus_message_iter_next(iter);
721 	}
722 
723 	/* Zero-length arrays are valid. */
724 	if (entry->array_len == 0) {
725 		os_free(entry->strarray_value);
726 		entry->strarray_value = NULL;
727 	}
728 
729 	success = TRUE;
730 
731 done:
732 	return success;
733 }
734 
735 
736 static dbus_bool_t _wpa_dbus_dict_entry_get_array(
737 	DBusMessageIter *iter_dict_val, struct wpa_dbus_dict_entry *entry)
738 {
739 	int array_type = dbus_message_iter_get_element_type(iter_dict_val);
740 	dbus_bool_t success = FALSE;
741 	DBusMessageIter iter_array;
742 
743 	if (!entry)
744 		return FALSE;
745 
746 	dbus_message_iter_recurse(iter_dict_val, &iter_array);
747 
748  	switch (array_type) {
749 	case DBUS_TYPE_BYTE:
750 		success = _wpa_dbus_dict_entry_get_byte_array(&iter_array,
751 							      array_type,
752 							      entry);
753 		break;
754 	case DBUS_TYPE_STRING:
755 		success = _wpa_dbus_dict_entry_get_string_array(&iter_array,
756 								array_type,
757 								entry);
758 		break;
759 	default:
760 		break;
761 	}
762 
763 	return success;
764 }
765 
766 
767 static dbus_bool_t _wpa_dbus_dict_fill_value_from_variant(
768 	struct wpa_dbus_dict_entry *entry, DBusMessageIter *iter)
769 {
770 	const char *v;
771 
772 	switch (entry->type) {
773 	case DBUS_TYPE_OBJECT_PATH:
774 	case DBUS_TYPE_STRING:
775 		dbus_message_iter_get_basic(iter, &v);
776 		entry->str_value = os_strdup(v);
777 		if (entry->str_value == NULL)
778 			return FALSE;
779 		break;
780 	case DBUS_TYPE_BOOLEAN:
781 		dbus_message_iter_get_basic(iter, &entry->bool_value);
782 		break;
783 	case DBUS_TYPE_BYTE:
784 		dbus_message_iter_get_basic(iter, &entry->byte_value);
785 		break;
786 	case DBUS_TYPE_INT16:
787 		dbus_message_iter_get_basic(iter, &entry->int16_value);
788 		break;
789 	case DBUS_TYPE_UINT16:
790 		dbus_message_iter_get_basic(iter, &entry->uint16_value);
791 		break;
792 	case DBUS_TYPE_INT32:
793 		dbus_message_iter_get_basic(iter, &entry->int32_value);
794 		break;
795 	case DBUS_TYPE_UINT32:
796 		dbus_message_iter_get_basic(iter, &entry->uint32_value);
797 		break;
798 	case DBUS_TYPE_INT64:
799 		dbus_message_iter_get_basic(iter, &entry->int64_value);
800 		break;
801 	case DBUS_TYPE_UINT64:
802 		dbus_message_iter_get_basic(iter, &entry->uint64_value);
803 		break;
804 	case DBUS_TYPE_DOUBLE:
805 		dbus_message_iter_get_basic(iter, &entry->double_value);
806 		break;
807 	case DBUS_TYPE_ARRAY:
808 		return _wpa_dbus_dict_entry_get_array(iter, entry);
809 	default:
810 		return FALSE;
811 	}
812 
813 	return TRUE;
814 }
815 
816 
817 /**
818  * Read the current key/value entry from the dict.  Entries are dynamically
819  * allocated when needed and must be freed after use with the
820  * wpa_dbus_dict_entry_clear() function.
821  *
822  * The returned entry object will be filled with the type and value of the next
823  * entry in the dict, or the type will be DBUS_TYPE_INVALID if an error
824  * occurred.
825  *
826  * @param iter_dict A valid DBusMessageIter returned from
827  *    wpa_dbus_dict_open_read()
828  * @param entry A valid dict entry object into which the dict key and value
829  *    will be placed
830  * @return TRUE on success, FALSE on failure
831  *
832  */
833 dbus_bool_t wpa_dbus_dict_get_entry(DBusMessageIter *iter_dict,
834 				    struct wpa_dbus_dict_entry * entry)
835 {
836 	DBusMessageIter iter_dict_entry, iter_dict_val;
837 	int type;
838 	const char *key;
839 
840 	if (!iter_dict || !entry)
841 		goto error;
842 
843 	if (dbus_message_iter_get_arg_type(iter_dict) != DBUS_TYPE_DICT_ENTRY)
844 		goto error;
845 
846 	dbus_message_iter_recurse(iter_dict, &iter_dict_entry);
847 	dbus_message_iter_get_basic(&iter_dict_entry, &key);
848 	entry->key = key;
849 
850 	if (!dbus_message_iter_next(&iter_dict_entry))
851 		goto error;
852 	type = dbus_message_iter_get_arg_type(&iter_dict_entry);
853 	if (type != DBUS_TYPE_VARIANT)
854 		goto error;
855 
856 	dbus_message_iter_recurse(&iter_dict_entry, &iter_dict_val);
857 	entry->type = dbus_message_iter_get_arg_type(&iter_dict_val);
858 	if (!_wpa_dbus_dict_fill_value_from_variant(entry, &iter_dict_val))
859 		goto error;
860 
861 	dbus_message_iter_next(iter_dict);
862 	return TRUE;
863 
864 error:
865 	if (entry) {
866 		wpa_dbus_dict_entry_clear(entry);
867 		entry->type = DBUS_TYPE_INVALID;
868 		entry->array_type = DBUS_TYPE_INVALID;
869 	}
870 
871 	return FALSE;
872 }
873 
874 
875 /**
876  * Return whether or not there are additional dictionary entries.
877  *
878  * @param iter_dict A valid DBusMessageIter returned from
879  *    wpa_dbus_dict_open_read()
880  * @return TRUE if more dict entries exists, FALSE if no more dict entries
881  * exist
882  */
883 dbus_bool_t wpa_dbus_dict_has_dict_entry(DBusMessageIter *iter_dict)
884 {
885 	if (!iter_dict)
886 		return FALSE;
887 	return dbus_message_iter_get_arg_type(iter_dict) ==
888 		DBUS_TYPE_DICT_ENTRY;
889 }
890 
891 
892 /**
893  * Free any memory used by the entry object.
894  *
895  * @param entry The entry object
896  */
897 void wpa_dbus_dict_entry_clear(struct wpa_dbus_dict_entry *entry)
898 {
899 	unsigned int i;
900 
901 	if (!entry)
902 		return;
903 	switch (entry->type) {
904 	case DBUS_TYPE_OBJECT_PATH:
905 	case DBUS_TYPE_STRING:
906 		os_free(entry->str_value);
907 		break;
908 	case DBUS_TYPE_ARRAY:
909 		switch (entry->array_type) {
910 		case DBUS_TYPE_BYTE:
911 			os_free(entry->bytearray_value);
912 			break;
913 		case DBUS_TYPE_STRING:
914 			for (i = 0; i < entry->array_len; i++)
915 				os_free(entry->strarray_value[i]);
916 			os_free(entry->strarray_value);
917 			break;
918 		}
919 		break;
920 	}
921 
922 	memset(entry, 0, sizeof(struct wpa_dbus_dict_entry));
923 }
924