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