1 /* 2 * WPA Supplicant / dbus-based control interface 3 * Copyright (c) 2006, Dan Williams <dcbw (at) 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 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 */ 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 */ 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 */ 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 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 */ 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 */ 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 */ 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 */ 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 */ 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 */ 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 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 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 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 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 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 */ 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 */ 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 */ 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