• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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  */
wpa_dbus_dict_open_write(DBusMessageIter * iter,DBusMessageIter * iter_dict)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  */
wpa_dbus_dict_close_write(DBusMessageIter * iter,DBusMessageIter * iter_dict)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 
_wpa_get_type_as_string_from_type(const int type)72 static 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 
_wpa_dbus_add_dict_entry_start(DBusMessageIter * iter_dict,DBusMessageIter * iter_dict_entry,const char * key,const int value_type)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 
_wpa_dbus_add_dict_entry_end(DBusMessageIter * iter_dict,DBusMessageIter * iter_dict_entry,DBusMessageIter * iter_dict_val)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 
_wpa_dbus_add_dict_entry_basic(DBusMessageIter * iter_dict,const char * key,const int value_type,const void * value)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 	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 
_wpa_dbus_add_dict_entry_byte_array(DBusMessageIter * iter_dict,const char * key,const char * value,const dbus_uint32_t value_len)167 static 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  */
wpa_dbus_dict_append_string(DBusMessageIter * iter_dict,const char * key,const char * value)218 dbus_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  */
wpa_dbus_dict_append_byte(DBusMessageIter * iter_dict,const char * key,const char value)238 dbus_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  */
wpa_dbus_dict_append_bool(DBusMessageIter * iter_dict,const char * key,const dbus_bool_t value)258 dbus_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  */
wpa_dbus_dict_append_int16(DBusMessageIter * iter_dict,const char * key,const dbus_int16_t value)278 dbus_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  */
wpa_dbus_dict_append_uint16(DBusMessageIter * iter_dict,const char * key,const dbus_uint16_t value)299 dbus_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  */
wpa_dbus_dict_append_int32(DBusMessageIter * iter_dict,const char * key,const dbus_int32_t value)320 dbus_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  */
wpa_dbus_dict_append_uint32(DBusMessageIter * iter_dict,const char * key,const dbus_uint32_t value)341 dbus_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  */
wpa_dbus_dict_append_int64(DBusMessageIter * iter_dict,const char * key,const dbus_int64_t value)362 dbus_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  */
wpa_dbus_dict_append_uint64(DBusMessageIter * iter_dict,const char * key,const dbus_uint64_t value)383 dbus_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  */
wpa_dbus_dict_append_double(DBusMessageIter * iter_dict,const char * key,const double value)404 dbus_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  */
wpa_dbus_dict_append_object_path(DBusMessageIter * iter_dict,const char * key,const char * value)425 dbus_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  */
wpa_dbus_dict_append_byte_array(DBusMessageIter * iter_dict,const char * key,const char * value,const dbus_uint32_t value_len)447 dbus_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  */
wpa_dbus_dict_begin_string_array(DBusMessageIter * iter_dict,const char * key,DBusMessageIter * iter_dict_entry,DBusMessageIter * iter_dict_val,DBusMessageIter * iter_array)476 dbus_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  */
wpa_dbus_dict_string_array_add_element(DBusMessageIter * iter_array,const char * elem)515 dbus_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  */
wpa_dbus_dict_end_string_array(DBusMessageIter * iter_dict,DBusMessageIter * iter_dict_entry,DBusMessageIter * iter_dict_val,DBusMessageIter * iter_array)540 dbus_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  */
wpa_dbus_dict_append_string_array(DBusMessageIter * iter_dict,const char * key,const char ** items,const dbus_uint32_t num_items)570 dbus_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  */
wpa_dbus_dict_open_read(DBusMessageIter * iter,DBusMessageIter * iter_dict)615 dbus_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 
_wpa_dbus_dict_entry_get_byte_array(DBusMessageIter * iter,int array_type,struct wpa_dbus_dict_entry * entry)633 static 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 
682 done:
683 	return success;
684 }
685 
686 
687 #define STR_ARRAY_CHUNK_SIZE 8
688 #define STR_ARRAY_ITEM_SIZE (sizeof(char *))
689 
_wpa_dbus_dict_entry_get_string_array(DBusMessageIter * iter,int array_type,struct wpa_dbus_dict_entry * entry)690 static 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 
747 done:
748 	return success;
749 }
750 
751 
_wpa_dbus_dict_entry_get_array(DBusMessageIter * iter_dict_val,struct wpa_dbus_dict_entry * entry)752 static 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 
_wpa_dbus_dict_fill_value_from_variant(struct wpa_dbus_dict_entry * entry,DBusMessageIter * iter_dict_val)783 static 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  */
wpa_dbus_dict_get_entry(DBusMessageIter * iter_dict,struct wpa_dbus_dict_entry * entry)884 dbus_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 
915 error:
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  */
wpa_dbus_dict_has_dict_entry(DBusMessageIter * iter_dict)934 dbus_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  */
wpa_dbus_dict_entry_clear(struct wpa_dbus_dict_entry * entry)950 void 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