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
72static const char * _wpa_get_type_as_string_from_type(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	type_as_string = _wpa_get_type_as_string_from_type(value_type);
144	if (!type_as_string)
145		return FALSE;
146
147	if (!_wpa_dbus_add_dict_entry_start(iter_dict, &iter_dict_entry,
148					    key, value_type))
149		return FALSE;
150
151	if (!dbus_message_iter_open_container(&iter_dict_entry,
152					      DBUS_TYPE_VARIANT,
153					      type_as_string, &iter_dict_val))
154		return FALSE;
155
156	if (!dbus_message_iter_append_basic(&iter_dict_val, value_type, value))
157		return FALSE;
158
159	if (!_wpa_dbus_add_dict_entry_end(iter_dict, &iter_dict_entry,
160					  &iter_dict_val))
161		return FALSE;
162
163	return TRUE;
164}
165
166
167static dbus_bool_t _wpa_dbus_add_dict_entry_byte_array(
168	DBusMessageIter *iter_dict, const char *key,
169	const char *value, const dbus_uint32_t value_len)
170{
171	DBusMessageIter iter_dict_entry, iter_dict_val, iter_array;
172	dbus_uint32_t i;
173
174	if (!_wpa_dbus_add_dict_entry_start(iter_dict, &iter_dict_entry,
175					    key, DBUS_TYPE_ARRAY))
176		return FALSE;
177
178	if (!dbus_message_iter_open_container(&iter_dict_entry,
179					      DBUS_TYPE_VARIANT,
180					      DBUS_TYPE_ARRAY_AS_STRING
181					      DBUS_TYPE_BYTE_AS_STRING,
182					      &iter_dict_val))
183		return FALSE;
184
185	if (!dbus_message_iter_open_container(&iter_dict_val, DBUS_TYPE_ARRAY,
186					      DBUS_TYPE_BYTE_AS_STRING,
187					      &iter_array))
188		return FALSE;
189
190	for (i = 0; i < value_len; i++) {
191		if (!dbus_message_iter_append_basic(&iter_array,
192						    DBUS_TYPE_BYTE,
193						    &(value[i])))
194			return FALSE;
195	}
196
197	if (!dbus_message_iter_close_container(&iter_dict_val, &iter_array))
198		return FALSE;
199
200	if (!_wpa_dbus_add_dict_entry_end(iter_dict, &iter_dict_entry,
201					  &iter_dict_val))
202		return FALSE;
203
204	return TRUE;
205}
206
207
208/**
209 * Add a string entry to the dict.
210 *
211 * @param iter_dict A valid DBusMessageIter returned from
212 *    wpa_dbus_dict_open_write()
213 * @param key The key of the dict item
214 * @param value The string value
215 * @return TRUE on success, FALSE on failure
216 *
217 */
218dbus_bool_t wpa_dbus_dict_append_string(DBusMessageIter *iter_dict,
219					const char *key, const char *value)
220{
221	if (!key || !value)
222		return FALSE;
223	return _wpa_dbus_add_dict_entry_basic(iter_dict, key, DBUS_TYPE_STRING,
224					      &value);
225}
226
227
228/**
229 * Add a byte entry to the dict.
230 *
231 * @param iter_dict A valid DBusMessageIter returned from
232 *    wpa_dbus_dict_open_write()
233 * @param key The key of the dict item
234 * @param value The byte value
235 * @return TRUE on success, FALSE on failure
236 *
237 */
238dbus_bool_t wpa_dbus_dict_append_byte(DBusMessageIter *iter_dict,
239				      const char *key, const char value)
240{
241	if (!key)
242		return FALSE;
243	return _wpa_dbus_add_dict_entry_basic(iter_dict, key, DBUS_TYPE_BYTE,
244					      &value);
245}
246
247
248/**
249 * Add a boolean entry to the dict.
250 *
251 * @param iter_dict A valid DBusMessageIter returned from
252 *    wpa_dbus_dict_open_write()
253 * @param key The key of the dict item
254 * @param value The boolean value
255 * @return TRUE on success, FALSE on failure
256 *
257 */
258dbus_bool_t wpa_dbus_dict_append_bool(DBusMessageIter *iter_dict,
259				      const char *key, const dbus_bool_t value)
260{
261	if (!key)
262		return FALSE;
263	return _wpa_dbus_add_dict_entry_basic(iter_dict, key,
264					      DBUS_TYPE_BOOLEAN, &value);
265}
266
267
268/**
269 * Add a 16-bit signed integer entry to the dict.
270 *
271 * @param iter_dict A valid DBusMessageIter returned from
272 *    wpa_dbus_dict_open_write()
273 * @param key The key of the dict item
274 * @param value The 16-bit signed integer value
275 * @return TRUE on success, FALSE on failure
276 *
277 */
278dbus_bool_t wpa_dbus_dict_append_int16(DBusMessageIter *iter_dict,
279				       const char *key,
280				       const dbus_int16_t value)
281{
282	if (!key)
283		return FALSE;
284	return _wpa_dbus_add_dict_entry_basic(iter_dict, key, DBUS_TYPE_INT16,
285					      &value);
286}
287
288
289/**
290 * Add a 16-bit unsigned integer entry to the dict.
291 *
292 * @param iter_dict A valid DBusMessageIter returned from
293 *    wpa_dbus_dict_open_write()
294 * @param key The key of the dict item
295 * @param value The 16-bit unsigned integer value
296 * @return TRUE on success, FALSE on failure
297 *
298 */
299dbus_bool_t wpa_dbus_dict_append_uint16(DBusMessageIter *iter_dict,
300					const char *key,
301					const dbus_uint16_t value)
302{
303	if (!key)
304		return FALSE;
305	return _wpa_dbus_add_dict_entry_basic(iter_dict, key, DBUS_TYPE_UINT16,
306					      &value);
307}
308
309
310/**
311 * Add a 32-bit signed integer to the dict.
312 *
313 * @param iter_dict A valid DBusMessageIter returned from
314 *    wpa_dbus_dict_open_write()
315 * @param key The key of the dict item
316 * @param value The 32-bit signed integer value
317 * @return TRUE on success, FALSE on failure
318 *
319 */
320dbus_bool_t wpa_dbus_dict_append_int32(DBusMessageIter *iter_dict,
321				       const char *key,
322				       const dbus_int32_t value)
323{
324	if (!key)
325		return FALSE;
326	return _wpa_dbus_add_dict_entry_basic(iter_dict, key, DBUS_TYPE_INT32,
327					      &value);
328}
329
330
331/**
332 * Add a 32-bit unsigned integer entry to the dict.
333 *
334 * @param iter_dict A valid DBusMessageIter returned from
335 *    wpa_dbus_dict_open_write()
336 * @param key The key of the dict item
337 * @param value The 32-bit unsigned integer value
338 * @return TRUE on success, FALSE on failure
339 *
340 */
341dbus_bool_t wpa_dbus_dict_append_uint32(DBusMessageIter *iter_dict,
342					const char *key,
343					const dbus_uint32_t value)
344{
345	if (!key)
346		return FALSE;
347	return _wpa_dbus_add_dict_entry_basic(iter_dict, key, DBUS_TYPE_UINT32,
348					      &value);
349}
350
351
352/**
353 * Add a 64-bit integer entry to the dict.
354 *
355 * @param iter_dict A valid DBusMessageIter returned from
356 *    wpa_dbus_dict_open_write()
357 * @param key The key of the dict item
358 * @param value The 64-bit integer value
359 * @return TRUE on success, FALSE on failure
360 *
361 */
362dbus_bool_t wpa_dbus_dict_append_int64(DBusMessageIter *iter_dict,
363				       const char *key,
364				       const dbus_int64_t value)
365{
366	if (!key)
367		return FALSE;
368	return _wpa_dbus_add_dict_entry_basic(iter_dict, key, DBUS_TYPE_INT64,
369					      &value);
370}
371
372
373/**
374 * Add a 64-bit unsigned integer entry to the dict.
375 *
376 * @param iter_dict A valid DBusMessageIter returned from
377 *    wpa_dbus_dict_open_write()
378 * @param key The key of the dict item
379 * @param value The 64-bit unsigned integer value
380 * @return TRUE on success, FALSE on failure
381 *
382 */
383dbus_bool_t wpa_dbus_dict_append_uint64(DBusMessageIter *iter_dict,
384					const char *key,
385					const dbus_uint64_t value)
386{
387	if (!key)
388		return FALSE;
389	return _wpa_dbus_add_dict_entry_basic(iter_dict, key, DBUS_TYPE_UINT64,
390					      &value);
391}
392
393
394/**
395 * Add a double-precision floating point entry to the dict.
396 *
397 * @param iter_dict A valid DBusMessageIter returned from
398 *    wpa_dbus_dict_open_write()
399 * @param key The key of the dict item
400 * @param value The double-precision floating point value
401 * @return TRUE on success, FALSE on failure
402 *
403 */
404dbus_bool_t wpa_dbus_dict_append_double(DBusMessageIter *iter_dict,
405					const char * key,
406					const double value)
407{
408	if (!key)
409		return FALSE;
410	return _wpa_dbus_add_dict_entry_basic(iter_dict, key, DBUS_TYPE_DOUBLE,
411					      &value);
412}
413
414
415/**
416 * Add a DBus object path entry to the dict.
417 *
418 * @param iter_dict A valid DBusMessageIter returned from
419 *    wpa_dbus_dict_open_write()
420 * @param key The key of the dict item
421 * @param value The DBus object path value
422 * @return TRUE on success, FALSE on failure
423 *
424 */
425dbus_bool_t wpa_dbus_dict_append_object_path(DBusMessageIter *iter_dict,
426					     const char *key,
427					     const char *value)
428{
429	if (!key || !value)
430		return FALSE;
431	return _wpa_dbus_add_dict_entry_basic(iter_dict, key,
432					      DBUS_TYPE_OBJECT_PATH, &value);
433}
434
435
436/**
437 * Add a byte array entry to the dict.
438 *
439 * @param iter_dict A valid DBusMessageIter returned from
440 *    wpa_dbus_dict_open_write()
441 * @param key The key of the dict item
442 * @param value The byte array
443 * @param value_len The length of the byte array, in bytes
444 * @return TRUE on success, FALSE on failure
445 *
446 */
447dbus_bool_t wpa_dbus_dict_append_byte_array(DBusMessageIter *iter_dict,
448					    const char *key,
449					    const char *value,
450					    const dbus_uint32_t value_len)
451{
452	if (!key)
453		return FALSE;
454	if (!value && (value_len != 0))
455		return FALSE;
456	return _wpa_dbus_add_dict_entry_byte_array(iter_dict, key, value,
457						   value_len);
458}
459
460
461/**
462 * Begin a string array entry in the dict
463 *
464 * @param iter_dict A valid DBusMessageIter returned from
465 *                  wpa_dbus_dict_open_write()
466 * @param key The key of the dict item
467 * @param iter_dict_entry A private DBusMessageIter provided by the caller to
468 *                        be passed to wpa_dbus_dict_end_string_array()
469 * @param iter_dict_val A private DBusMessageIter provided by the caller to
470 *                      be passed to wpa_dbus_dict_end_string_array()
471 * @param iter_array On return, the DBusMessageIter to be passed to
472 *                   wpa_dbus_dict_string_array_add_element()
473 * @return TRUE on success, FALSE on failure
474 *
475 */
476dbus_bool_t wpa_dbus_dict_begin_string_array(DBusMessageIter *iter_dict,
477					     const char *key,
478					     DBusMessageIter *iter_dict_entry,
479					     DBusMessageIter *iter_dict_val,
480					     DBusMessageIter *iter_array)
481{
482	if (!iter_dict || !iter_dict_entry || !iter_dict_val || !iter_array)
483		return FALSE;
484
485	if (!_wpa_dbus_add_dict_entry_start(iter_dict, iter_dict_entry,
486					    key, DBUS_TYPE_ARRAY))
487		return FALSE;
488
489	if (!dbus_message_iter_open_container(iter_dict_entry,
490					      DBUS_TYPE_VARIANT,
491					      DBUS_TYPE_ARRAY_AS_STRING
492					      DBUS_TYPE_STRING_AS_STRING,
493					      iter_dict_val))
494		return FALSE;
495
496	if (!dbus_message_iter_open_container(iter_dict_val, DBUS_TYPE_ARRAY,
497					      DBUS_TYPE_BYTE_AS_STRING,
498					      iter_array))
499		return FALSE;
500
501	return TRUE;
502}
503
504
505/**
506 * Add a single string element to a string array dict entry
507 *
508 * @param iter_array A valid DBusMessageIter returned from
509 *                   wpa_dbus_dict_begin_string_array()'s
510 *                   iter_array parameter
511 * @param elem The string element to be added to the dict entry's string array
512 * @return TRUE on success, FALSE on failure
513 *
514 */
515dbus_bool_t wpa_dbus_dict_string_array_add_element(DBusMessageIter *iter_array,
516						   const char *elem)
517{
518	if (!iter_array || !elem)
519		return FALSE;
520
521	return dbus_message_iter_append_basic(iter_array, DBUS_TYPE_STRING,
522					      &elem);
523}
524
525
526/**
527 * End a string array dict entry
528 *
529 * @param iter_dict A valid DBusMessageIter returned from
530 *                  wpa_dbus_dict_open_write()
531 * @param iter_dict_entry A private DBusMessageIter returned from
532 *                        wpa_dbus_dict_end_string_array()
533 * @param iter_dict_val A private DBusMessageIter returned from
534 *                      wpa_dbus_dict_end_string_array()
535 * @param iter_array A DBusMessageIter returned from
536 *                   wpa_dbus_dict_end_string_array()
537 * @return TRUE on success, FALSE on failure
538 *
539 */
540dbus_bool_t wpa_dbus_dict_end_string_array(DBusMessageIter *iter_dict,
541					   DBusMessageIter *iter_dict_entry,
542					   DBusMessageIter *iter_dict_val,
543					   DBusMessageIter *iter_array)
544{
545	if (!iter_dict || !iter_dict_entry || !iter_dict_val || !iter_array)
546		return FALSE;
547
548	if (!dbus_message_iter_close_container(iter_dict_val, iter_array))
549		return FALSE;
550
551	if (!_wpa_dbus_add_dict_entry_end(iter_dict, iter_dict_entry,
552					  iter_dict_val))
553		return FALSE;
554
555	return TRUE;
556}
557
558
559/**
560 * Convenience function to add an entire string array to the dict.
561 *
562 * @param iter_dict A valid DBusMessageIter returned from
563 *                  wpa_dbus_dict_open_write()
564 * @param key The key of the dict item
565 * @param items The array of strings
566 * @param num_items The number of strings in the array
567 * @return TRUE on success, FALSE on failure
568 *
569 */
570dbus_bool_t wpa_dbus_dict_append_string_array(DBusMessageIter *iter_dict,
571					      const char *key,
572					      const char **items,
573					      const dbus_uint32_t num_items)
574{
575	DBusMessageIter iter_dict_entry, iter_dict_val, iter_array;
576	dbus_uint32_t i;
577
578	if (!key)
579		return FALSE;
580	if (!items && (num_items != 0))
581		return FALSE;
582
583	if (!wpa_dbus_dict_begin_string_array(iter_dict, key,
584					      &iter_dict_entry, &iter_dict_val,
585					      &iter_array))
586		return FALSE;
587
588	for (i = 0; i < num_items; i++) {
589		if (!wpa_dbus_dict_string_array_add_element(&iter_array,
590							    items[i]))
591			return FALSE;
592	}
593
594	if (!wpa_dbus_dict_end_string_array(iter_dict, &iter_dict_entry,
595					    &iter_dict_val, &iter_array))
596		return FALSE;
597
598	return TRUE;
599}
600
601
602/*****************************************************/
603/* Stuff for reading dicts                           */
604/*****************************************************/
605
606/**
607 * Start reading from a dbus dict.
608 *
609 * @param iter A valid DBusMessageIter pointing to the start of the dict
610 * @param iter_dict (out) A DBusMessageIter to be passed to
611 *    wpa_dbus_dict_read_next_entry()
612 * @return TRUE on success, FALSE on failure
613 *
614 */
615dbus_bool_t wpa_dbus_dict_open_read(DBusMessageIter *iter,
616				    DBusMessageIter *iter_dict)
617{
618	if (!iter || !iter_dict)
619		return FALSE;
620
621	if (dbus_message_iter_get_arg_type(iter) != DBUS_TYPE_ARRAY ||
622	    dbus_message_iter_get_element_type(iter) != DBUS_TYPE_DICT_ENTRY)
623		return FALSE;
624
625	dbus_message_iter_recurse(iter, iter_dict);
626	return TRUE;
627}
628
629
630#define BYTE_ARRAY_CHUNK_SIZE 34
631#define BYTE_ARRAY_ITEM_SIZE (sizeof(char))
632
633static dbus_bool_t _wpa_dbus_dict_entry_get_byte_array(
634	DBusMessageIter *iter, int array_type,
635	struct wpa_dbus_dict_entry *entry)
636{
637	dbus_uint32_t count = 0;
638	dbus_bool_t success = FALSE;
639	char *buffer;
640
641	entry->bytearray_value = NULL;
642	entry->array_type = DBUS_TYPE_BYTE;
643
644	buffer = os_zalloc(BYTE_ARRAY_ITEM_SIZE * BYTE_ARRAY_CHUNK_SIZE);
645	if (!buffer) {
646		perror("_wpa_dbus_dict_entry_get_byte_array[dbus]: out of "
647		       "memory");
648		goto done;
649	}
650
651	entry->bytearray_value = buffer;
652	entry->array_len = 0;
653	while (dbus_message_iter_get_arg_type(iter) == DBUS_TYPE_BYTE) {
654		char byte;
655
656		if ((count % BYTE_ARRAY_CHUNK_SIZE) == 0 && count != 0) {
657			buffer = realloc(buffer, BYTE_ARRAY_ITEM_SIZE *
658					 (count + BYTE_ARRAY_CHUNK_SIZE));
659			if (buffer == NULL) {
660				perror("_wpa_dbus_dict_entry_get_byte_array["
661				       "dbus] out of memory trying to "
662				       "retrieve the string array");
663				goto done;
664			}
665		}
666		entry->bytearray_value = buffer;
667
668		dbus_message_iter_get_basic(iter, &byte);
669		entry->bytearray_value[count] = byte;
670		entry->array_len = ++count;
671		dbus_message_iter_next(iter);
672	}
673
674	/* Zero-length arrays are valid. */
675	if (entry->array_len == 0) {
676		free(entry->bytearray_value);
677		entry->bytearray_value = NULL;
678	}
679
680	success = TRUE;
681
682done:
683	return success;
684}
685
686
687#define STR_ARRAY_CHUNK_SIZE 8
688#define STR_ARRAY_ITEM_SIZE (sizeof(char *))
689
690static dbus_bool_t _wpa_dbus_dict_entry_get_string_array(
691	DBusMessageIter *iter, int array_type,
692	struct wpa_dbus_dict_entry *entry)
693{
694	dbus_uint32_t count = 0;
695	dbus_bool_t success = FALSE;
696	char **buffer;
697
698	entry->strarray_value = NULL;
699	entry->array_type = DBUS_TYPE_STRING;
700
701	buffer = os_zalloc(STR_ARRAY_ITEM_SIZE * STR_ARRAY_CHUNK_SIZE);
702	if (buffer == NULL) {
703		perror("_wpa_dbus_dict_entry_get_string_array[dbus] out of "
704		       "memory trying to retrieve a string array");
705		goto done;
706	}
707
708	entry->strarray_value = buffer;
709	entry->array_len = 0;
710	while (dbus_message_iter_get_arg_type(iter) == DBUS_TYPE_STRING) {
711		const char *value;
712		char *str;
713
714		if ((count % STR_ARRAY_CHUNK_SIZE) == 0 && count != 0) {
715			buffer = realloc(buffer, STR_ARRAY_ITEM_SIZE *
716					 (count + STR_ARRAY_CHUNK_SIZE));
717			if (buffer == NULL) {
718				perror("_wpa_dbus_dict_entry_get_string_array["
719				       "dbus] out of memory trying to "
720				       "retrieve the string array");
721				goto done;
722			}
723		}
724		entry->strarray_value = buffer;
725
726		dbus_message_iter_get_basic(iter, &value);
727		str = strdup(value);
728		if (str == NULL) {
729			perror("_wpa_dbus_dict_entry_get_string_array[dbus] "
730			       "out of memory trying to duplicate the string "
731			       "array");
732			goto done;
733		}
734		entry->strarray_value[count] = str;
735		entry->array_len = ++count;
736		dbus_message_iter_next(iter);
737	}
738
739	/* Zero-length arrays are valid. */
740	if (entry->array_len == 0) {
741		free(entry->strarray_value);
742		entry->strarray_value = NULL;
743	}
744
745	success = TRUE;
746
747done:
748	return success;
749}
750
751
752static dbus_bool_t _wpa_dbus_dict_entry_get_array(
753	DBusMessageIter *iter_dict_val, struct wpa_dbus_dict_entry *entry)
754{
755	int array_type = dbus_message_iter_get_element_type(iter_dict_val);
756	dbus_bool_t success = FALSE;
757	DBusMessageIter iter_array;
758
759	if (!entry)
760		return FALSE;
761
762	dbus_message_iter_recurse(iter_dict_val, &iter_array);
763
764 	switch (array_type) {
765	case DBUS_TYPE_BYTE:
766		success = _wpa_dbus_dict_entry_get_byte_array(&iter_array,
767							      array_type,
768							      entry);
769		break;
770	case DBUS_TYPE_STRING:
771		success = _wpa_dbus_dict_entry_get_string_array(&iter_array,
772								array_type,
773								entry);
774		break;
775	default:
776		break;
777	}
778
779	return success;
780}
781
782
783static dbus_bool_t _wpa_dbus_dict_fill_value_from_variant(
784	struct wpa_dbus_dict_entry *entry, DBusMessageIter *iter_dict_val)
785{
786	dbus_bool_t success = TRUE;
787
788	switch (entry->type) {
789	case DBUS_TYPE_STRING: {
790		const char *v;
791		dbus_message_iter_get_basic(iter_dict_val, &v);
792		entry->str_value = strdup(v);
793		break;
794	}
795	case DBUS_TYPE_BOOLEAN: {
796		dbus_bool_t v;
797		dbus_message_iter_get_basic(iter_dict_val, &v);
798		entry->bool_value = v;
799		break;
800	}
801	case DBUS_TYPE_BYTE: {
802		char v;
803		dbus_message_iter_get_basic(iter_dict_val, &v);
804		entry->byte_value = v;
805		break;
806	}
807	case DBUS_TYPE_INT16: {
808		dbus_int16_t v;
809		dbus_message_iter_get_basic(iter_dict_val, &v);
810		entry->int16_value = v;
811		break;
812	}
813	case DBUS_TYPE_UINT16: {
814		dbus_uint16_t v;
815		dbus_message_iter_get_basic(iter_dict_val, &v);
816		entry->uint16_value = v;
817		break;
818	}
819	case DBUS_TYPE_INT32: {
820		dbus_int32_t v;
821		dbus_message_iter_get_basic(iter_dict_val, &v);
822		entry->int32_value = v;
823		break;
824	}
825	case DBUS_TYPE_UINT32: {
826		dbus_uint32_t v;
827		dbus_message_iter_get_basic(iter_dict_val, &v);
828		entry->uint32_value = v;
829		break;
830	}
831	case DBUS_TYPE_INT64: {
832		dbus_int64_t v;
833		dbus_message_iter_get_basic(iter_dict_val, &v);
834		entry->int64_value = v;
835		break;
836	}
837	case DBUS_TYPE_UINT64: {
838		dbus_uint64_t v;
839		dbus_message_iter_get_basic(iter_dict_val, &v);
840		entry->uint64_value = v;
841		break;
842	}
843	case DBUS_TYPE_DOUBLE: {
844		double v;
845		dbus_message_iter_get_basic(iter_dict_val, &v);
846		entry->double_value = v;
847		break;
848	}
849	case DBUS_TYPE_OBJECT_PATH: {
850		char *v;
851		dbus_message_iter_get_basic(iter_dict_val, &v);
852		entry->str_value = strdup(v);
853		break;
854	}
855	case DBUS_TYPE_ARRAY: {
856		success = _wpa_dbus_dict_entry_get_array(iter_dict_val, entry);
857		break;
858	}
859	default:
860		success = FALSE;
861		break;
862	}
863
864	return success;
865}
866
867
868/**
869 * Read the current key/value entry from the dict.  Entries are dynamically
870 * allocated when needed and must be freed after use with the
871 * wpa_dbus_dict_entry_clear() function.
872 *
873 * The returned entry object will be filled with the type and value of the next
874 * entry in the dict, or the type will be DBUS_TYPE_INVALID if an error
875 * occurred.
876 *
877 * @param iter_dict A valid DBusMessageIter returned from
878 *    wpa_dbus_dict_open_read()
879 * @param entry A valid dict entry object into which the dict key and value
880 *    will be placed
881 * @return TRUE on success, FALSE on failure
882 *
883 */
884dbus_bool_t wpa_dbus_dict_get_entry(DBusMessageIter *iter_dict,
885				    struct wpa_dbus_dict_entry * entry)
886{
887	DBusMessageIter iter_dict_entry, iter_dict_val;
888	int type;
889	const char *key;
890
891	if (!iter_dict || !entry)
892		goto error;
893
894	if (dbus_message_iter_get_arg_type(iter_dict) != DBUS_TYPE_DICT_ENTRY)
895		goto error;
896
897	dbus_message_iter_recurse(iter_dict, &iter_dict_entry);
898	dbus_message_iter_get_basic(&iter_dict_entry, &key);
899	entry->key = key;
900
901	if (!dbus_message_iter_next(&iter_dict_entry))
902		goto error;
903	type = dbus_message_iter_get_arg_type(&iter_dict_entry);
904	if (type != DBUS_TYPE_VARIANT)
905		goto error;
906
907	dbus_message_iter_recurse(&iter_dict_entry, &iter_dict_val);
908	entry->type = dbus_message_iter_get_arg_type(&iter_dict_val);
909	if (!_wpa_dbus_dict_fill_value_from_variant(entry, &iter_dict_val))
910		goto error;
911
912	dbus_message_iter_next(iter_dict);
913	return TRUE;
914
915error:
916	if (entry) {
917		wpa_dbus_dict_entry_clear(entry);
918		entry->type = DBUS_TYPE_INVALID;
919		entry->array_type = DBUS_TYPE_INVALID;
920	}
921
922	return FALSE;
923}
924
925
926/**
927 * Return whether or not there are additional dictionary entries.
928 *
929 * @param iter_dict A valid DBusMessageIter returned from
930 *    wpa_dbus_dict_open_read()
931 * @return TRUE if more dict entries exists, FALSE if no more dict entries
932 * exist
933 */
934dbus_bool_t wpa_dbus_dict_has_dict_entry(DBusMessageIter *iter_dict)
935{
936	if (!iter_dict) {
937		perror("wpa_dbus_dict_has_dict_entry[dbus]: out of memory");
938		return FALSE;
939	}
940	return dbus_message_iter_get_arg_type(iter_dict) ==
941		DBUS_TYPE_DICT_ENTRY;
942}
943
944
945/**
946 * Free any memory used by the entry object.
947 *
948 * @param entry The entry object
949 */
950void wpa_dbus_dict_entry_clear(struct wpa_dbus_dict_entry *entry)
951{
952	unsigned int i;
953
954	if (!entry)
955		return;
956	switch (entry->type) {
957	case DBUS_TYPE_OBJECT_PATH:
958	case DBUS_TYPE_STRING:
959		free(entry->str_value);
960		break;
961	case DBUS_TYPE_ARRAY:
962		switch (entry->array_type) {
963		case DBUS_TYPE_BYTE:
964			free(entry->bytearray_value);
965			break;
966		case DBUS_TYPE_STRING:
967			for (i = 0; i < entry->array_len; i++)
968				free(entry->strarray_value[i]);
969			free(entry->strarray_value);
970			break;
971		}
972		break;
973	}
974
975	memset(entry, 0, sizeof(struct wpa_dbus_dict_entry));
976}
977