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