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