dbus_dict_helpers.c revision 8d520ff1dc2da35cdca849e982051b86468016d8
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 */
31dbus_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 */
62dbus_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
72const 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
105static 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
122static 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
135static 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
170static 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 */
221dbus_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 */
241dbus_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 */
259dbus_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 */
277dbus_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 */
296dbus_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 */
315dbus_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 */
334dbus_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 */
353dbus_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 */
372dbus_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 */
391dbus_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 */
409dbus_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 */
431dbus_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 */
460dbus_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_STRING_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 */
499dbus_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 */
524dbus_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 */
554dbus_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 */
599dbus_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
617static 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
666done:
667	return success;
668}
669
670
671#define STR_ARRAY_CHUNK_SIZE 8
672#define STR_ARRAY_ITEM_SIZE (sizeof(char *))
673
674static 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
731done:
732	return success;
733}
734
735
736static 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
767static 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 */
833dbus_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
864error:
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 */
883dbus_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 */
897void 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