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 */ 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 */ 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 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 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 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 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 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 */ 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 */ 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 */ 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 */ 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 */ 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 */ 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 64-bit unsigned integer 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 64-bit unsigned integer value 308 * @return TRUE on success, FALSE on failure 309 * 310 */ 311 dbus_bool_t wpa_dbus_dict_append_uint64(DBusMessageIter *iter_dict, 312 const char *key, 313 const dbus_uint64_t value) 314 { 315 return _wpa_dbus_add_dict_entry_basic(iter_dict, key, DBUS_TYPE_UINT64, 316 &value); 317 } 318 319 320 /** 321 * Add a DBus object path entry to the dict. 322 * 323 * @param iter_dict A valid DBusMessageIter returned from 324 * wpa_dbus_dict_open_write() 325 * @param key The key of the dict item 326 * @param value The DBus object path value 327 * @return TRUE on success, FALSE on failure 328 * 329 */ 330 dbus_bool_t wpa_dbus_dict_append_object_path(DBusMessageIter *iter_dict, 331 const char *key, 332 const char *value) 333 { 334 if (!value) 335 return FALSE; 336 return _wpa_dbus_add_dict_entry_basic(iter_dict, key, 337 DBUS_TYPE_OBJECT_PATH, &value); 338 } 339 340 341 /** 342 * Add a byte array entry to the dict. 343 * 344 * @param iter_dict A valid DBusMessageIter returned from 345 * wpa_dbus_dict_open_write() 346 * @param key The key of the dict item 347 * @param value The byte array 348 * @param value_len The length of the byte array, in bytes 349 * @return TRUE on success, FALSE on failure 350 * 351 */ 352 dbus_bool_t wpa_dbus_dict_append_byte_array(DBusMessageIter *iter_dict, 353 const char *key, 354 const char *value, 355 const dbus_uint32_t value_len) 356 { 357 if (!key || (!value && value_len != 0)) 358 return FALSE; 359 return _wpa_dbus_add_dict_entry_byte_array(iter_dict, key, value, 360 value_len); 361 } 362 363 364 /** 365 * Add a double entry to the dict. 366 * 367 * @param iter_dict A valid DBusMessageIter returned from 368 * wpa_dbus_dict_open_write() 369 * @param key The key of the dict item 370 * @param value The double value 371 * @return TRUE on success, FALSE on failure 372 * 373 */ 374 dbus_bool_t wpa_dbus_dict_append_double(DBusMessageIter *iter_dict, 375 const char *key, 376 const double value) 377 { 378 if (!key) 379 return FALSE; 380 return _wpa_dbus_add_dict_entry_basic(iter_dict, key, DBUS_TYPE_DOUBLE, 381 &value); 382 } 383 384 385 /** 386 * Begin an array entry in the dict 387 * 388 * @param iter_dict A valid DBusMessageIter returned from 389 * wpa_dbus_dict_open_write() 390 * @param key The key of the dict item 391 * @param type The type of the contained data 392 * @param iter_dict_entry A private DBusMessageIter provided by the caller to 393 * be passed to wpa_dbus_dict_end_string_array() 394 * @param iter_dict_val A private DBusMessageIter provided by the caller to 395 * be passed to wpa_dbus_dict_end_string_array() 396 * @param iter_array On return, the DBusMessageIter to be passed to 397 * wpa_dbus_dict_string_array_add_element() 398 * @return TRUE on success, FALSE on failure 399 * 400 */ 401 dbus_bool_t wpa_dbus_dict_begin_array(DBusMessageIter *iter_dict, 402 const char *key, const char *type, 403 DBusMessageIter *iter_dict_entry, 404 DBusMessageIter *iter_dict_val, 405 DBusMessageIter *iter_array) 406 { 407 char array_type[10]; 408 int err; 409 410 err = os_snprintf(array_type, sizeof(array_type), 411 DBUS_TYPE_ARRAY_AS_STRING "%s", 412 type); 413 if (os_snprintf_error(sizeof(array_type), err)) 414 return FALSE; 415 416 if (!iter_dict || !iter_dict_entry || !iter_dict_val || !iter_array || 417 !_wpa_dbus_add_dict_entry_start(iter_dict, iter_dict_entry, 418 key, DBUS_TYPE_ARRAY) || 419 !dbus_message_iter_open_container(iter_dict_entry, 420 DBUS_TYPE_VARIANT, 421 array_type, 422 iter_dict_val)) 423 return FALSE; 424 425 return dbus_message_iter_open_container(iter_dict_val, DBUS_TYPE_ARRAY, 426 type, iter_array); 427 } 428 429 430 dbus_bool_t wpa_dbus_dict_begin_string_array(DBusMessageIter *iter_dict, 431 const char *key, 432 DBusMessageIter *iter_dict_entry, 433 DBusMessageIter *iter_dict_val, 434 DBusMessageIter *iter_array) 435 { 436 return wpa_dbus_dict_begin_array( 437 iter_dict, key, 438 DBUS_TYPE_STRING_AS_STRING, 439 iter_dict_entry, iter_dict_val, iter_array); 440 } 441 442 443 /** 444 * Add a single string element to a string array dict entry 445 * 446 * @param iter_array A valid DBusMessageIter returned from 447 * wpa_dbus_dict_begin_string_array()'s 448 * iter_array parameter 449 * @param elem The string element to be added to the dict entry's string array 450 * @return TRUE on success, FALSE on failure 451 * 452 */ 453 dbus_bool_t wpa_dbus_dict_string_array_add_element(DBusMessageIter *iter_array, 454 const char *elem) 455 { 456 if (!iter_array || !elem) 457 return FALSE; 458 459 return dbus_message_iter_append_basic(iter_array, DBUS_TYPE_STRING, 460 &elem); 461 } 462 463 464 /** 465 * Add a single byte array element to a string array dict entry 466 * 467 * @param iter_array A valid DBusMessageIter returned from 468 * wpa_dbus_dict_begin_array()'s iter_array 469 * parameter -- note that wpa_dbus_dict_begin_array() 470 * must have been called with "ay" as the type 471 * @param value The data to be added to the dict entry's array 472 * @param value_len The length of the data 473 * @return TRUE on success, FALSE on failure 474 * 475 */ 476 dbus_bool_t wpa_dbus_dict_bin_array_add_element(DBusMessageIter *iter_array, 477 const u8 *value, 478 size_t value_len) 479 { 480 DBusMessageIter iter_bytes; 481 size_t i; 482 483 if (!iter_array || !value || 484 !dbus_message_iter_open_container(iter_array, DBUS_TYPE_ARRAY, 485 DBUS_TYPE_BYTE_AS_STRING, 486 &iter_bytes)) 487 return FALSE; 488 489 for (i = 0; i < value_len; i++) { 490 if (!dbus_message_iter_append_basic(&iter_bytes, 491 DBUS_TYPE_BYTE, 492 &(value[i]))) 493 return FALSE; 494 } 495 496 return dbus_message_iter_close_container(iter_array, &iter_bytes); 497 } 498 499 500 /** 501 * End an array dict entry 502 * 503 * @param iter_dict A valid DBusMessageIter returned from 504 * wpa_dbus_dict_open_write() 505 * @param iter_dict_entry A private DBusMessageIter returned from 506 * wpa_dbus_dict_begin_string_array() or 507 * wpa_dbus_dict_begin_array() 508 * @param iter_dict_val A private DBusMessageIter returned from 509 * wpa_dbus_dict_begin_string_array() or 510 * wpa_dbus_dict_begin_array() 511 * @param iter_array A DBusMessageIter returned from 512 * wpa_dbus_dict_begin_string_array() or 513 * wpa_dbus_dict_begin_array() 514 * @return TRUE on success, FALSE on failure 515 * 516 */ 517 dbus_bool_t wpa_dbus_dict_end_array(DBusMessageIter *iter_dict, 518 DBusMessageIter *iter_dict_entry, 519 DBusMessageIter *iter_dict_val, 520 DBusMessageIter *iter_array) 521 { 522 if (!iter_dict || !iter_dict_entry || !iter_dict_val || !iter_array || 523 !dbus_message_iter_close_container(iter_dict_val, iter_array)) 524 return FALSE; 525 526 return _wpa_dbus_add_dict_entry_end(iter_dict, iter_dict_entry, 527 iter_dict_val); 528 } 529 530 531 /** 532 * Convenience function to add an entire string array to the dict. 533 * 534 * @param iter_dict A valid DBusMessageIter returned from 535 * wpa_dbus_dict_open_write() 536 * @param key The key of the dict item 537 * @param items The array of strings 538 * @param num_items The number of strings in the array 539 * @return TRUE on success, FALSE on failure 540 * 541 */ 542 dbus_bool_t wpa_dbus_dict_append_string_array(DBusMessageIter *iter_dict, 543 const char *key, 544 const char **items, 545 const dbus_uint32_t num_items) 546 { 547 DBusMessageIter iter_dict_entry, iter_dict_val, iter_array; 548 dbus_uint32_t i; 549 550 if (!key || (!items && num_items != 0) || 551 !wpa_dbus_dict_begin_string_array(iter_dict, key, 552 &iter_dict_entry, &iter_dict_val, 553 &iter_array)) 554 return FALSE; 555 556 for (i = 0; i < num_items; i++) { 557 if (!wpa_dbus_dict_string_array_add_element(&iter_array, 558 items[i])) 559 return FALSE; 560 } 561 562 return wpa_dbus_dict_end_string_array(iter_dict, &iter_dict_entry, 563 &iter_dict_val, &iter_array); 564 } 565 566 567 /** 568 * Convenience function to add an wpabuf binary array to the dict. 569 * 570 * @param iter_dict A valid DBusMessageIter returned from 571 * wpa_dbus_dict_open_write() 572 * @param key The key of the dict item 573 * @param items The array of wpabuf structures 574 * @param num_items The number of strings in the array 575 * @return TRUE on success, FALSE on failure 576 * 577 */ 578 dbus_bool_t wpa_dbus_dict_append_wpabuf_array(DBusMessageIter *iter_dict, 579 const char *key, 580 const struct wpabuf **items, 581 const dbus_uint32_t num_items) 582 { 583 DBusMessageIter iter_dict_entry, iter_dict_val, iter_array; 584 dbus_uint32_t i; 585 586 if (!key || 587 (!items && num_items != 0) || 588 !wpa_dbus_dict_begin_array(iter_dict, key, 589 DBUS_TYPE_ARRAY_AS_STRING 590 DBUS_TYPE_BYTE_AS_STRING, 591 &iter_dict_entry, &iter_dict_val, 592 &iter_array)) 593 return FALSE; 594 595 for (i = 0; i < num_items; i++) { 596 if (!wpa_dbus_dict_bin_array_add_element(&iter_array, 597 wpabuf_head(items[i]), 598 wpabuf_len(items[i]))) 599 return FALSE; 600 } 601 602 return wpa_dbus_dict_end_array(iter_dict, &iter_dict_entry, 603 &iter_dict_val, &iter_array); 604 } 605 606 607 /*****************************************************/ 608 /* Stuff for reading dicts */ 609 /*****************************************************/ 610 611 /** 612 * Start reading from a dbus dict. 613 * 614 * @param iter A valid DBusMessageIter pointing to the start of the dict 615 * @param iter_dict (out) A DBusMessageIter to be passed to 616 * wpa_dbus_dict_read_next_entry() 617 * @error on failure a descriptive error 618 * @return TRUE on success, FALSE on failure 619 * 620 */ 621 dbus_bool_t wpa_dbus_dict_open_read(DBusMessageIter *iter, 622 DBusMessageIter *iter_dict, 623 DBusError *error) 624 { 625 int type; 626 627 wpa_printf(MSG_MSGDUMP, "%s: start reading a dict entry", __func__); 628 if (!iter || !iter_dict) { 629 dbus_set_error_const(error, DBUS_ERROR_FAILED, 630 "[internal] missing message iterators"); 631 return FALSE; 632 } 633 634 type = dbus_message_iter_get_arg_type(iter); 635 if (type != DBUS_TYPE_ARRAY || 636 dbus_message_iter_get_element_type(iter) != DBUS_TYPE_DICT_ENTRY) { 637 wpa_printf(MSG_DEBUG, 638 "%s: unexpected message argument types (arg=%c element=%c)", 639 __func__, type, 640 type != DBUS_TYPE_ARRAY ? '?' : 641 dbus_message_iter_get_element_type(iter)); 642 dbus_set_error_const(error, DBUS_ERROR_INVALID_ARGS, 643 "unexpected message argument types"); 644 return FALSE; 645 } 646 647 dbus_message_iter_recurse(iter, iter_dict); 648 return TRUE; 649 } 650 651 652 #define BYTE_ARRAY_CHUNK_SIZE 34 653 #define BYTE_ARRAY_ITEM_SIZE (sizeof(char)) 654 655 static dbus_bool_t _wpa_dbus_dict_entry_get_byte_array( 656 DBusMessageIter *iter, struct wpa_dbus_dict_entry *entry) 657 { 658 dbus_uint32_t count = 0; 659 dbus_bool_t success = FALSE; 660 char *buffer, *nbuffer; 661 662 entry->bytearray_value = NULL; 663 entry->array_type = DBUS_TYPE_BYTE; 664 665 buffer = os_calloc(BYTE_ARRAY_CHUNK_SIZE, BYTE_ARRAY_ITEM_SIZE); 666 if (!buffer) 667 return FALSE; 668 669 entry->array_len = 0; 670 while (dbus_message_iter_get_arg_type(iter) == DBUS_TYPE_BYTE) { 671 char byte; 672 673 if ((count % BYTE_ARRAY_CHUNK_SIZE) == 0 && count != 0) { 674 nbuffer = os_realloc_array( 675 buffer, count + BYTE_ARRAY_CHUNK_SIZE, 676 BYTE_ARRAY_ITEM_SIZE); 677 if (nbuffer == NULL) { 678 os_free(buffer); 679 wpa_printf(MSG_ERROR, 680 "dbus: %s out of memory trying to retrieve the string array", 681 __func__); 682 goto done; 683 } 684 buffer = nbuffer; 685 } 686 687 dbus_message_iter_get_basic(iter, &byte); 688 buffer[count] = byte; 689 entry->array_len = ++count; 690 dbus_message_iter_next(iter); 691 } 692 entry->bytearray_value = buffer; 693 wpa_hexdump_key(MSG_MSGDUMP, "dbus: byte array contents", 694 entry->bytearray_value, entry->array_len); 695 696 /* Zero-length arrays are valid. */ 697 if (entry->array_len == 0) { 698 os_free(entry->bytearray_value); 699 entry->bytearray_value = NULL; 700 } 701 702 success = TRUE; 703 704 done: 705 return success; 706 } 707 708 709 #define UINT16_ARRAY_CHUNK_SIZE 18 710 #define UINT16_ARRAY_ITEM_SIZE (sizeof(dbus_uint16_t)) 711 712 static dbus_bool_t _wpa_dbus_dict_entry_get_uint16_array( 713 DBusMessageIter *iter, struct wpa_dbus_dict_entry *entry) 714 { 715 dbus_uint32_t count = 0; 716 dbus_uint16_t *buffer, *nbuffer; 717 718 entry->uint16array_value = NULL; 719 entry->array_type = DBUS_TYPE_UINT16; 720 721 buffer = os_calloc(UINT16_ARRAY_CHUNK_SIZE, UINT16_ARRAY_ITEM_SIZE); 722 if (!buffer) 723 return FALSE; 724 725 entry->array_len = 0; 726 while (dbus_message_iter_get_arg_type(iter) == DBUS_TYPE_UINT16) { 727 dbus_uint16_t value; 728 729 if ((count % UINT16_ARRAY_CHUNK_SIZE) == 0 && count != 0) { 730 nbuffer = os_realloc_array( 731 buffer, count + UINT16_ARRAY_CHUNK_SIZE, 732 UINT16_ARRAY_ITEM_SIZE); 733 if (!nbuffer) { 734 os_free(buffer); 735 wpa_printf(MSG_ERROR, 736 "dbus: %s out of memory trying to retrieve the uint16 array", 737 __func__); 738 return FALSE; 739 } 740 buffer = nbuffer; 741 } 742 743 dbus_message_iter_get_basic(iter, &value); 744 buffer[count] = value; 745 entry->array_len = ++count; 746 dbus_message_iter_next(iter); 747 } 748 entry->uint16array_value = buffer; 749 wpa_hexdump_key(MSG_MSGDUMP, "dbus: uint16 array contents", 750 entry->bytearray_value, entry->array_len); 751 752 /* Zero-length arrays are valid. */ 753 if (entry->array_len == 0) { 754 os_free(entry->uint16array_value); 755 entry->uint16array_value = NULL; 756 } 757 758 return TRUE; 759 } 760 761 762 #define STR_ARRAY_CHUNK_SIZE 8 763 #define STR_ARRAY_ITEM_SIZE (sizeof(char *)) 764 765 static dbus_bool_t _wpa_dbus_dict_entry_get_string_array( 766 DBusMessageIter *iter, int array_type, 767 struct wpa_dbus_dict_entry *entry) 768 { 769 dbus_uint32_t count = 0; 770 char **buffer, **nbuffer; 771 772 entry->strarray_value = NULL; 773 entry->array_len = 0; 774 entry->array_type = DBUS_TYPE_STRING; 775 776 buffer = os_calloc(STR_ARRAY_CHUNK_SIZE, STR_ARRAY_ITEM_SIZE); 777 if (buffer == NULL) 778 return FALSE; 779 780 while (dbus_message_iter_get_arg_type(iter) == DBUS_TYPE_STRING) { 781 const char *value; 782 char *str; 783 784 if ((count % STR_ARRAY_CHUNK_SIZE) == 0 && count != 0) { 785 nbuffer = os_realloc_array( 786 buffer, count + STR_ARRAY_CHUNK_SIZE, 787 STR_ARRAY_ITEM_SIZE); 788 if (nbuffer == NULL) { 789 wpa_printf(MSG_ERROR, 790 "dbus: %s out of memory trying to retrieve the string array", 791 __func__); 792 goto fail; 793 } 794 buffer = nbuffer; 795 } 796 797 dbus_message_iter_get_basic(iter, &value); 798 wpa_printf(MSG_MSGDUMP, "%s: string_array value: %s", 799 __func__, wpa_debug_show_keys ? value : "[omitted]"); 800 str = os_strdup(value); 801 if (str == NULL) { 802 wpa_printf(MSG_ERROR, 803 "dbus: %s out of memory trying to duplicate the string array", 804 __func__); 805 goto fail; 806 } 807 buffer[count++] = str; 808 dbus_message_iter_next(iter); 809 } 810 entry->strarray_value = buffer; 811 entry->array_len = count; 812 wpa_printf(MSG_MSGDUMP, "%s: string_array length %u", 813 __func__, entry->array_len); 814 815 /* Zero-length arrays are valid. */ 816 if (entry->array_len == 0) { 817 os_free(entry->strarray_value); 818 entry->strarray_value = NULL; 819 } 820 821 return TRUE; 822 823 fail: 824 while (count > 0) { 825 count--; 826 os_free(buffer[count]); 827 } 828 os_free(buffer); 829 return FALSE; 830 } 831 832 833 #define BIN_ARRAY_CHUNK_SIZE 10 834 #define BIN_ARRAY_ITEM_SIZE (sizeof(struct wpabuf *)) 835 836 static dbus_bool_t _wpa_dbus_dict_entry_get_binarray( 837 DBusMessageIter *iter, struct wpa_dbus_dict_entry *entry) 838 { 839 struct wpa_dbus_dict_entry tmpentry; 840 size_t buflen = 0; 841 int i, type; 842 843 entry->array_type = WPAS_DBUS_TYPE_BINARRAY; 844 entry->array_len = 0; 845 entry->binarray_value = NULL; 846 847 type = dbus_message_iter_get_arg_type(iter); 848 wpa_printf(MSG_MSGDUMP, "%s: parsing binarray type %c", __func__, type); 849 if (type == DBUS_TYPE_INVALID) { 850 /* Likely an empty array of arrays */ 851 return TRUE; 852 } 853 if (type != DBUS_TYPE_ARRAY) { 854 wpa_printf(MSG_DEBUG, "%s: not an array type: %c", 855 __func__, type); 856 return FALSE; 857 } 858 859 type = dbus_message_iter_get_element_type(iter); 860 if (type != DBUS_TYPE_BYTE) { 861 wpa_printf(MSG_DEBUG, "%s: unexpected element type %c", 862 __func__, type); 863 return FALSE; 864 } 865 866 while (dbus_message_iter_get_arg_type(iter) == DBUS_TYPE_ARRAY) { 867 DBusMessageIter iter_array; 868 869 if (entry->array_len == buflen) { 870 struct wpabuf **newbuf; 871 872 buflen += BIN_ARRAY_CHUNK_SIZE; 873 874 newbuf = os_realloc_array(entry->binarray_value, 875 buflen, BIN_ARRAY_ITEM_SIZE); 876 if (!newbuf) 877 goto cleanup; 878 entry->binarray_value = newbuf; 879 } 880 881 dbus_message_iter_recurse(iter, &iter_array); 882 os_memset(&tmpentry, 0, sizeof(tmpentry)); 883 tmpentry.type = DBUS_TYPE_ARRAY; 884 if (_wpa_dbus_dict_entry_get_byte_array(&iter_array, &tmpentry) 885 == FALSE) 886 goto cleanup; 887 888 entry->binarray_value[entry->array_len] = 889 wpabuf_alloc_ext_data((u8 *) tmpentry.bytearray_value, 890 tmpentry.array_len); 891 if (entry->binarray_value[entry->array_len] == NULL) { 892 wpa_dbus_dict_entry_clear(&tmpentry); 893 goto cleanup; 894 } 895 entry->array_len++; 896 dbus_message_iter_next(iter); 897 } 898 wpa_printf(MSG_MSGDUMP, "%s: binarray length %u", 899 __func__, entry->array_len); 900 901 return TRUE; 902 903 cleanup: 904 for (i = 0; i < (int) entry->array_len; i++) 905 wpabuf_free(entry->binarray_value[i]); 906 os_free(entry->binarray_value); 907 entry->array_len = 0; 908 entry->binarray_value = NULL; 909 return FALSE; 910 } 911 912 913 static dbus_bool_t _wpa_dbus_dict_entry_get_array( 914 DBusMessageIter *iter_dict_val, struct wpa_dbus_dict_entry *entry) 915 { 916 int array_type = dbus_message_iter_get_element_type(iter_dict_val); 917 dbus_bool_t success = FALSE; 918 DBusMessageIter iter_array; 919 920 wpa_printf(MSG_MSGDUMP, "%s: array_type %c", __func__, array_type); 921 922 dbus_message_iter_recurse(iter_dict_val, &iter_array); 923 924 switch (array_type) { 925 case DBUS_TYPE_BYTE: 926 success = _wpa_dbus_dict_entry_get_byte_array(&iter_array, 927 entry); 928 break; 929 case DBUS_TYPE_UINT16: 930 success = _wpa_dbus_dict_entry_get_uint16_array(&iter_array, 931 entry); 932 break; 933 case DBUS_TYPE_STRING: 934 success = _wpa_dbus_dict_entry_get_string_array(&iter_array, 935 array_type, 936 entry); 937 break; 938 case DBUS_TYPE_ARRAY: 939 success = _wpa_dbus_dict_entry_get_binarray(&iter_array, entry); 940 break; 941 default: 942 wpa_printf(MSG_MSGDUMP, "%s: unsupported array type %c", 943 __func__, array_type); 944 break; 945 } 946 947 return success; 948 } 949 950 951 static dbus_bool_t _wpa_dbus_dict_fill_value_from_variant( 952 struct wpa_dbus_dict_entry *entry, DBusMessageIter *iter) 953 { 954 const char *v; 955 956 switch (entry->type) { 957 case DBUS_TYPE_OBJECT_PATH: 958 dbus_message_iter_get_basic(iter, &v); 959 wpa_printf(MSG_MSGDUMP, "%s: object path value: %s", 960 __func__, v); 961 entry->str_value = os_strdup(v); 962 if (entry->str_value == NULL) 963 return FALSE; 964 break; 965 case DBUS_TYPE_STRING: 966 dbus_message_iter_get_basic(iter, &v); 967 wpa_printf(MSG_MSGDUMP, "%s: string value: %s", 968 __func__, wpa_debug_show_keys ? v : "[omitted]"); 969 entry->str_value = os_strdup(v); 970 if (entry->str_value == NULL) 971 return FALSE; 972 break; 973 case DBUS_TYPE_BOOLEAN: 974 dbus_message_iter_get_basic(iter, &entry->bool_value); 975 wpa_printf(MSG_MSGDUMP, "%s: boolean value: %d", 976 __func__, entry->bool_value); 977 break; 978 case DBUS_TYPE_BYTE: 979 dbus_message_iter_get_basic(iter, &entry->byte_value); 980 wpa_printf(MSG_MSGDUMP, "%s: byte value: %d", 981 __func__, entry->byte_value); 982 break; 983 case DBUS_TYPE_INT16: 984 dbus_message_iter_get_basic(iter, &entry->int16_value); 985 wpa_printf(MSG_MSGDUMP, "%s: int16 value: %d", 986 __func__, entry->int16_value); 987 break; 988 case DBUS_TYPE_UINT16: 989 dbus_message_iter_get_basic(iter, &entry->uint16_value); 990 wpa_printf(MSG_MSGDUMP, "%s: uint16 value: %d", 991 __func__, entry->uint16_value); 992 break; 993 case DBUS_TYPE_INT32: 994 dbus_message_iter_get_basic(iter, &entry->int32_value); 995 wpa_printf(MSG_MSGDUMP, "%s: int32 value: %d", 996 __func__, entry->int32_value); 997 break; 998 case DBUS_TYPE_UINT32: 999 dbus_message_iter_get_basic(iter, &entry->uint32_value); 1000 wpa_printf(MSG_MSGDUMP, "%s: uint32 value: %d", 1001 __func__, entry->uint32_value); 1002 break; 1003 case DBUS_TYPE_INT64: 1004 dbus_message_iter_get_basic(iter, &entry->int64_value); 1005 wpa_printf(MSG_MSGDUMP, "%s: int64 value: %lld", 1006 __func__, (long long int) entry->int64_value); 1007 break; 1008 case DBUS_TYPE_UINT64: 1009 dbus_message_iter_get_basic(iter, &entry->uint64_value); 1010 wpa_printf(MSG_MSGDUMP, "%s: uint64 value: %llu", 1011 __func__, 1012 (unsigned long long int) entry->uint64_value); 1013 break; 1014 case DBUS_TYPE_DOUBLE: 1015 dbus_message_iter_get_basic(iter, &entry->double_value); 1016 wpa_printf(MSG_MSGDUMP, "%s: double value: %f", 1017 __func__, entry->double_value); 1018 break; 1019 case DBUS_TYPE_ARRAY: 1020 return _wpa_dbus_dict_entry_get_array(iter, entry); 1021 default: 1022 wpa_printf(MSG_MSGDUMP, "%s: unsupported type %c", 1023 __func__, entry->type); 1024 return FALSE; 1025 } 1026 1027 return TRUE; 1028 } 1029 1030 1031 /** 1032 * Read the current key/value entry from the dict. Entries are dynamically 1033 * allocated when needed and must be freed after use with the 1034 * wpa_dbus_dict_entry_clear() function. 1035 * 1036 * The returned entry object will be filled with the type and value of the next 1037 * entry in the dict, or the type will be DBUS_TYPE_INVALID if an error 1038 * occurred. 1039 * 1040 * @param iter_dict A valid DBusMessageIter returned from 1041 * wpa_dbus_dict_open_read() 1042 * @param entry A valid dict entry object into which the dict key and value 1043 * will be placed 1044 * @return TRUE on success, FALSE on failure 1045 * 1046 */ 1047 dbus_bool_t wpa_dbus_dict_get_entry(DBusMessageIter *iter_dict, 1048 struct wpa_dbus_dict_entry * entry) 1049 { 1050 DBusMessageIter iter_dict_entry, iter_dict_val; 1051 int type; 1052 const char *key; 1053 1054 if (!iter_dict || !entry || 1055 dbus_message_iter_get_arg_type(iter_dict) != DBUS_TYPE_DICT_ENTRY) { 1056 wpa_printf(MSG_DEBUG, "%s: not a dict entry", __func__); 1057 goto error; 1058 } 1059 1060 dbus_message_iter_recurse(iter_dict, &iter_dict_entry); 1061 dbus_message_iter_get_basic(&iter_dict_entry, &key); 1062 wpa_printf(MSG_MSGDUMP, "%s: dict entry key: %s", __func__, key); 1063 entry->key = key; 1064 1065 if (!dbus_message_iter_next(&iter_dict_entry)) { 1066 wpa_printf(MSG_DEBUG, "%s: no variant in dict entry", __func__); 1067 goto error; 1068 } 1069 type = dbus_message_iter_get_arg_type(&iter_dict_entry); 1070 if (type != DBUS_TYPE_VARIANT) { 1071 wpa_printf(MSG_DEBUG, 1072 "%s: unexpected dict entry variant type: %c", 1073 __func__, type); 1074 goto error; 1075 } 1076 1077 dbus_message_iter_recurse(&iter_dict_entry, &iter_dict_val); 1078 entry->type = dbus_message_iter_get_arg_type(&iter_dict_val); 1079 wpa_printf(MSG_MSGDUMP, "%s: dict entry variant content type: %c", 1080 __func__, entry->type); 1081 entry->array_type = DBUS_TYPE_INVALID; 1082 if (!_wpa_dbus_dict_fill_value_from_variant(entry, &iter_dict_val)) { 1083 wpa_printf(MSG_DEBUG, 1084 "%s: failed to fetch dict values from variant", 1085 __func__); 1086 goto error; 1087 } 1088 1089 dbus_message_iter_next(iter_dict); 1090 return TRUE; 1091 1092 error: 1093 if (entry) { 1094 wpa_dbus_dict_entry_clear(entry); 1095 entry->type = DBUS_TYPE_INVALID; 1096 entry->array_type = DBUS_TYPE_INVALID; 1097 } 1098 1099 return FALSE; 1100 } 1101 1102 1103 /** 1104 * Return whether or not there are additional dictionary entries. 1105 * 1106 * @param iter_dict A valid DBusMessageIter returned from 1107 * wpa_dbus_dict_open_read() 1108 * @return TRUE if more dict entries exists, FALSE if no more dict entries 1109 * exist 1110 */ 1111 dbus_bool_t wpa_dbus_dict_has_dict_entry(DBusMessageIter *iter_dict) 1112 { 1113 if (!iter_dict) 1114 return FALSE; 1115 return dbus_message_iter_get_arg_type(iter_dict) == 1116 DBUS_TYPE_DICT_ENTRY; 1117 } 1118 1119 1120 /** 1121 * Free any memory used by the entry object. 1122 * 1123 * @param entry The entry object 1124 */ 1125 void wpa_dbus_dict_entry_clear(struct wpa_dbus_dict_entry *entry) 1126 { 1127 unsigned int i; 1128 1129 if (!entry) 1130 return; 1131 switch (entry->type) { 1132 case DBUS_TYPE_OBJECT_PATH: 1133 case DBUS_TYPE_STRING: 1134 os_free(entry->str_value); 1135 break; 1136 case DBUS_TYPE_ARRAY: 1137 switch (entry->array_type) { 1138 case DBUS_TYPE_BYTE: 1139 os_free(entry->bytearray_value); 1140 break; 1141 case DBUS_TYPE_UINT16: 1142 os_free(entry->uint16array_value); 1143 break; 1144 case DBUS_TYPE_STRING: 1145 if (!entry->strarray_value) 1146 break; 1147 for (i = 0; i < entry->array_len; i++) 1148 os_free(entry->strarray_value[i]); 1149 os_free(entry->strarray_value); 1150 break; 1151 case WPAS_DBUS_TYPE_BINARRAY: 1152 for (i = 0; i < entry->array_len; i++) 1153 wpabuf_free(entry->binarray_value[i]); 1154 os_free(entry->binarray_value); 1155 break; 1156 } 1157 break; 1158 } 1159 1160 os_memset(entry, 0, sizeof(struct wpa_dbus_dict_entry)); 1161 } 1162