00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025 #include <config.h>
00026 #include "dbus-address.h"
00027 #include "dbus-internals.h"
00028 #include "dbus-list.h"
00029 #include "dbus-string.h"
00030 #include "dbus-protocol.h"
00031
00043 struct DBusAddressEntry
00044 {
00045 DBusString method;
00047 DBusList *keys;
00048 DBusList *values;
00049 };
00050
00051
00064 void
00065 _dbus_set_bad_address (DBusError *error,
00066 const char *address_problem_type,
00067 const char *address_problem_field,
00068 const char *address_problem_other)
00069 {
00070 if (address_problem_type != NULL)
00071 dbus_set_error (error, DBUS_ERROR_BAD_ADDRESS,
00072 "Server address of type %s was missing argument %s",
00073 address_problem_type, address_problem_field);
00074 else
00075 dbus_set_error (error, DBUS_ERROR_BAD_ADDRESS,
00076 "Could not parse server address: %s",
00077 address_problem_other);
00078 }
00079
00084 #define _DBUS_ADDRESS_OPTIONALLY_ESCAPED_BYTE(b) \
00085 (((b) >= 'a' && (b) <= 'z') || \
00086 ((b) >= 'A' && (b) <= 'Z') || \
00087 ((b) >= '0' && (b) <= '9') || \
00088 (b) == '-' || \
00089 (b) == '_' || \
00090 (b) == '/' || \
00091 (b) == '\\' || \
00092 (b) == '*' || \
00093 (b) == '.')
00094
00103 dbus_bool_t
00104 _dbus_address_append_escaped (DBusString *escaped,
00105 const DBusString *unescaped)
00106 {
00107 const char *p;
00108 const char *end;
00109 dbus_bool_t ret;
00110 int orig_len;
00111
00112 ret = FALSE;
00113
00114 orig_len = _dbus_string_get_length (escaped);
00115 p = _dbus_string_get_const_data (unescaped);
00116 end = p + _dbus_string_get_length (unescaped);
00117 while (p != end)
00118 {
00119 if (_DBUS_ADDRESS_OPTIONALLY_ESCAPED_BYTE (*p))
00120 {
00121 if (!_dbus_string_append_byte (escaped, *p))
00122 goto out;
00123 }
00124 else
00125 {
00126 if (!_dbus_string_append_byte (escaped, '%'))
00127 goto out;
00128 if (!_dbus_string_append_byte_as_hex (escaped, *p))
00129 goto out;
00130 }
00131
00132 ++p;
00133 }
00134
00135 ret = TRUE;
00136
00137 out:
00138 if (!ret)
00139 _dbus_string_set_length (escaped, orig_len);
00140 return ret;
00141 }
00142
00144
00145 static void
00146 dbus_address_entry_free (DBusAddressEntry *entry)
00147 {
00148 DBusList *link;
00149
00150 _dbus_string_free (&entry->method);
00151
00152 link = _dbus_list_get_first_link (&entry->keys);
00153 while (link != NULL)
00154 {
00155 _dbus_string_free (link->data);
00156 dbus_free (link->data);
00157
00158 link = _dbus_list_get_next_link (&entry->keys, link);
00159 }
00160 _dbus_list_clear (&entry->keys);
00161
00162 link = _dbus_list_get_first_link (&entry->values);
00163 while (link != NULL)
00164 {
00165 _dbus_string_free (link->data);
00166 dbus_free (link->data);
00167
00168 link = _dbus_list_get_next_link (&entry->values, link);
00169 }
00170 _dbus_list_clear (&entry->values);
00171
00172 dbus_free (entry);
00173 }
00174
00188 void
00189 dbus_address_entries_free (DBusAddressEntry **entries)
00190 {
00191 int i;
00192
00193 for (i = 0; entries[i] != NULL; i++)
00194 dbus_address_entry_free (entries[i]);
00195 dbus_free (entries);
00196 }
00197
00198 static DBusAddressEntry *
00199 create_entry (void)
00200 {
00201 DBusAddressEntry *entry;
00202
00203 entry = dbus_new0 (DBusAddressEntry, 1);
00204
00205 if (entry == NULL)
00206 return NULL;
00207
00208 if (!_dbus_string_init (&entry->method))
00209 {
00210 dbus_free (entry);
00211 return NULL;
00212 }
00213
00214 return entry;
00215 }
00216
00226 const char *
00227 dbus_address_entry_get_method (DBusAddressEntry *entry)
00228 {
00229 return _dbus_string_get_const_data (&entry->method);
00230 }
00231
00243 const char *
00244 dbus_address_entry_get_value (DBusAddressEntry *entry,
00245 const char *key)
00246 {
00247 DBusList *values, *keys;
00248
00249 keys = _dbus_list_get_first_link (&entry->keys);
00250 values = _dbus_list_get_first_link (&entry->values);
00251
00252 while (keys != NULL)
00253 {
00254 _dbus_assert (values != NULL);
00255
00256 if (_dbus_string_equal_c_str (keys->data, key))
00257 return _dbus_string_get_const_data (values->data);
00258
00259 keys = _dbus_list_get_next_link (&entry->keys, keys);
00260 values = _dbus_list_get_next_link (&entry->values, values);
00261 }
00262
00263 return NULL;
00264 }
00265
00266 static dbus_bool_t
00267 append_unescaped_value (DBusString *unescaped,
00268 const DBusString *escaped,
00269 int escaped_start,
00270 int escaped_len,
00271 DBusError *error)
00272 {
00273 const char *p;
00274 const char *end;
00275 dbus_bool_t ret;
00276
00277 ret = FALSE;
00278
00279 p = _dbus_string_get_const_data (escaped) + escaped_start;
00280 end = p + escaped_len;
00281 while (p != end)
00282 {
00283 if (_DBUS_ADDRESS_OPTIONALLY_ESCAPED_BYTE (*p))
00284 {
00285 if (!_dbus_string_append_byte (unescaped, *p))
00286 goto out;
00287 }
00288 else if (*p == '%')
00289 {
00290
00291 char buf[3];
00292 DBusString hex;
00293 int hex_end;
00294
00295 ++p;
00296
00297 if ((p + 2) > end)
00298 {
00299 dbus_set_error (error, DBUS_ERROR_BAD_ADDRESS,
00300 "In D-Bus address, percent character was not followed by two hex digits");
00301 goto out;
00302 }
00303
00304 buf[0] = *p;
00305 ++p;
00306 buf[1] = *p;
00307 buf[2] = '\0';
00308
00309 _dbus_string_init_const (&hex, buf);
00310
00311 if (!_dbus_string_hex_decode (&hex, 0, &hex_end,
00312 unescaped,
00313 _dbus_string_get_length (unescaped)))
00314 goto out;
00315
00316 if (hex_end != 2)
00317 {
00318 dbus_set_error (error, DBUS_ERROR_BAD_ADDRESS,
00319 "In D-Bus address, percent character was followed by characters other than hex digits");
00320 goto out;
00321 }
00322 }
00323 else
00324 {
00325
00326 dbus_set_error (error, DBUS_ERROR_BAD_ADDRESS,
00327 "In D-Bus address, character '%c' should have been escaped\n",
00328 *p);
00329 goto out;
00330 }
00331
00332 ++p;
00333 }
00334
00335 ret = TRUE;
00336
00337 out:
00338 if (!ret && error && !dbus_error_is_set (error))
00339 _DBUS_SET_OOM (error);
00340
00341 _dbus_assert (ret || error == NULL || dbus_error_is_set (error));
00342
00343 return ret;
00344 }
00345
00362 dbus_bool_t
00363 dbus_parse_address (const char *address,
00364 DBusAddressEntry ***entry,
00365 int *array_len,
00366 DBusError *error)
00367 {
00368 DBusString str;
00369 int pos, end_pos, len, i;
00370 DBusList *entries, *link;
00371 DBusAddressEntry **entry_array;
00372
00373 _DBUS_ASSERT_ERROR_IS_CLEAR (error);
00374
00375 _dbus_string_init_const (&str, address);
00376
00377 entries = NULL;
00378 pos = 0;
00379 len = _dbus_string_get_length (&str);
00380
00381 if (len == 0)
00382 {
00383 dbus_set_error (error, DBUS_ERROR_BAD_ADDRESS,
00384 "Empty address '%s'", address);
00385 goto error;
00386 }
00387
00388 while (pos < len)
00389 {
00390 DBusAddressEntry *entry;
00391
00392 int found_pos;
00393
00394 entry = create_entry ();
00395 if (!entry)
00396 {
00397 dbus_set_error (error, DBUS_ERROR_NO_MEMORY, NULL);
00398
00399 goto error;
00400 }
00401
00402
00403 if (!_dbus_list_append (&entries, entry))
00404 {
00405 dbus_set_error (error, DBUS_ERROR_NO_MEMORY, NULL);
00406 dbus_address_entry_free (entry);
00407 goto error;
00408 }
00409
00410
00411 if (!_dbus_string_find (&str, pos, ";", &end_pos))
00412 end_pos = len;
00413
00414
00415 if (!_dbus_string_find_to (&str, pos, end_pos, ":", &found_pos))
00416 {
00417 dbus_set_error (error, DBUS_ERROR_BAD_ADDRESS, "Address does not contain a colon");
00418 goto error;
00419 }
00420
00421 if (!_dbus_string_copy_len (&str, pos, found_pos - pos, &entry->method, 0))
00422 {
00423 dbus_set_error (error, DBUS_ERROR_NO_MEMORY, NULL);
00424 goto error;
00425 }
00426
00427 pos = found_pos + 1;
00428
00429 while (pos < end_pos)
00430 {
00431 int comma_pos, equals_pos;
00432
00433 if (!_dbus_string_find_to (&str, pos, end_pos, ",", &comma_pos))
00434 comma_pos = end_pos;
00435
00436 if (!_dbus_string_find_to (&str, pos, comma_pos, "=", &equals_pos) ||
00437 equals_pos == pos || equals_pos + 1 == comma_pos)
00438 {
00439 dbus_set_error (error, DBUS_ERROR_BAD_ADDRESS,
00440 "'=' character not found or has no value following it");
00441 goto error;
00442 }
00443 else
00444 {
00445 DBusString *key;
00446 DBusString *value;
00447
00448 key = dbus_new0 (DBusString, 1);
00449
00450 if (!key)
00451 {
00452 dbus_set_error (error, DBUS_ERROR_NO_MEMORY, NULL);
00453 goto error;
00454 }
00455
00456 value = dbus_new0 (DBusString, 1);
00457 if (!value)
00458 {
00459 dbus_set_error (error, DBUS_ERROR_NO_MEMORY, NULL);
00460 dbus_free (key);
00461 goto error;
00462 }
00463
00464 if (!_dbus_string_init (key))
00465 {
00466 dbus_set_error (error, DBUS_ERROR_NO_MEMORY, NULL);
00467 dbus_free (key);
00468 dbus_free (value);
00469
00470 goto error;
00471 }
00472
00473 if (!_dbus_string_init (value))
00474 {
00475 dbus_set_error (error, DBUS_ERROR_NO_MEMORY, NULL);
00476 _dbus_string_free (key);
00477
00478 dbus_free (key);
00479 dbus_free (value);
00480 goto error;
00481 }
00482
00483 if (!_dbus_string_copy_len (&str, pos, equals_pos - pos, key, 0))
00484 {
00485 dbus_set_error (error, DBUS_ERROR_NO_MEMORY, NULL);
00486 _dbus_string_free (key);
00487 _dbus_string_free (value);
00488
00489 dbus_free (key);
00490 dbus_free (value);
00491 goto error;
00492 }
00493
00494 if (!append_unescaped_value (value, &str, equals_pos + 1,
00495 comma_pos - equals_pos - 1, error))
00496 {
00497 _dbus_assert (error == NULL || dbus_error_is_set (error));
00498 _dbus_string_free (key);
00499 _dbus_string_free (value);
00500
00501 dbus_free (key);
00502 dbus_free (value);
00503 goto error;
00504 }
00505
00506 if (!_dbus_list_append (&entry->keys, key))
00507 {
00508 dbus_set_error (error, DBUS_ERROR_NO_MEMORY, NULL);
00509 _dbus_string_free (key);
00510 _dbus_string_free (value);
00511
00512 dbus_free (key);
00513 dbus_free (value);
00514 goto error;
00515 }
00516
00517 if (!_dbus_list_append (&entry->values, value))
00518 {
00519 dbus_set_error (error, DBUS_ERROR_NO_MEMORY, NULL);
00520 _dbus_string_free (value);
00521
00522 dbus_free (value);
00523 goto error;
00524 }
00525 }
00526
00527 pos = comma_pos + 1;
00528 }
00529
00530 pos = end_pos + 1;
00531 }
00532
00533 *array_len = _dbus_list_get_length (&entries);
00534
00535 entry_array = dbus_new (DBusAddressEntry *, *array_len + 1);
00536
00537 if (!entry_array)
00538 {
00539 dbus_set_error (error, DBUS_ERROR_NO_MEMORY, NULL);
00540
00541 goto error;
00542 }
00543
00544 entry_array [*array_len] = NULL;
00545
00546 link = _dbus_list_get_first_link (&entries);
00547 i = 0;
00548 while (link != NULL)
00549 {
00550 entry_array[i] = link->data;
00551 i++;
00552 link = _dbus_list_get_next_link (&entries, link);
00553 }
00554
00555 _dbus_list_clear (&entries);
00556 *entry = entry_array;
00557
00558 return TRUE;
00559
00560 error:
00561
00562 link = _dbus_list_get_first_link (&entries);
00563 while (link != NULL)
00564 {
00565 dbus_address_entry_free (link->data);
00566 link = _dbus_list_get_next_link (&entries, link);
00567 }
00568
00569 _dbus_list_clear (&entries);
00570
00571 return FALSE;
00572
00573 }
00574
00582 char*
00583 dbus_address_escape_value (const char *value)
00584 {
00585 DBusString escaped;
00586 DBusString unescaped;
00587 char *ret;
00588
00589 ret = NULL;
00590
00591 _dbus_string_init_const (&unescaped, value);
00592
00593 if (!_dbus_string_init (&escaped))
00594 return NULL;
00595
00596 if (!_dbus_address_append_escaped (&escaped, &unescaped))
00597 goto out;
00598
00599 if (!_dbus_string_steal_data (&escaped, &ret))
00600 goto out;
00601
00602 out:
00603 _dbus_string_free (&escaped);
00604 return ret;
00605 }
00606
00616 char*
00617 dbus_address_unescape_value (const char *value,
00618 DBusError *error)
00619 {
00620 DBusString unescaped;
00621 DBusString escaped;
00622 char *ret;
00623
00624 ret = NULL;
00625
00626 _dbus_string_init_const (&escaped, value);
00627
00628 if (!_dbus_string_init (&unescaped))
00629 return NULL;
00630
00631 if (!append_unescaped_value (&unescaped, &escaped,
00632 0, _dbus_string_get_length (&escaped),
00633 error))
00634 goto out;
00635
00636 if (!_dbus_string_steal_data (&unescaped, &ret))
00637 goto out;
00638
00639 out:
00640 if (ret == NULL && error && !dbus_error_is_set (error))
00641 _DBUS_SET_OOM (error);
00642
00643 _dbus_assert (ret != NULL || error == NULL || dbus_error_is_set (error));
00644
00645 _dbus_string_free (&unescaped);
00646 return ret;
00647 }
00648
00650
00651 #ifdef DBUS_BUILD_TESTS
00652
00653 #ifndef DOXYGEN_SHOULD_SKIP_THIS
00654
00655 #include "dbus-test.h"
00656 #include <stdlib.h>
00657
00658 typedef struct
00659 {
00660 const char *escaped;
00661 const char *unescaped;
00662 } EscapeTest;
00663
00664 static const EscapeTest escape_tests[] = {
00665 { "abcde", "abcde" },
00666 { "", "" },
00667 { "%20%20", " " },
00668 { "%24", "$" },
00669 { "%25", "%" },
00670 { "abc%24", "abc$" },
00671 { "%24abc", "$abc" },
00672 { "abc%24abc", "abc$abc" },
00673 { "/", "/" },
00674 { "-", "-" },
00675 { "_", "_" },
00676 { "A", "A" },
00677 { "I", "I" },
00678 { "Z", "Z" },
00679 { "a", "a" },
00680 { "i", "i" },
00681 { "z", "z" }
00682 };
00683
00684 static const char* invalid_escaped_values[] = {
00685 "%a",
00686 "%q",
00687 "%az",
00688 "%%",
00689 "%$$",
00690 "abc%a",
00691 "%axyz",
00692 "%",
00693 "$",
00694 " ",
00695 };
00696
00697 dbus_bool_t
00698 _dbus_address_test (void)
00699 {
00700 DBusAddressEntry **entries;
00701 int len;
00702 DBusError error = DBUS_ERROR_INIT;
00703 int i;
00704
00705 i = 0;
00706 while (i < _DBUS_N_ELEMENTS (escape_tests))
00707 {
00708 const EscapeTest *test = &escape_tests[i];
00709 char *escaped;
00710 char *unescaped;
00711
00712 escaped = dbus_address_escape_value (test->unescaped);
00713 if (escaped == NULL)
00714 _dbus_assert_not_reached ("oom");
00715
00716 if (strcmp (escaped, test->escaped) != 0)
00717 {
00718 _dbus_warn ("Escaped '%s' as '%s' should have been '%s'\n",
00719 test->unescaped, escaped, test->escaped);
00720 exit (1);
00721 }
00722 dbus_free (escaped);
00723
00724 unescaped = dbus_address_unescape_value (test->escaped, &error);
00725 if (unescaped == NULL)
00726 {
00727 _dbus_warn ("Failed to unescape '%s': %s\n",
00728 test->escaped, error.message);
00729 dbus_error_free (&error);
00730 exit (1);
00731 }
00732
00733 if (strcmp (unescaped, test->unescaped) != 0)
00734 {
00735 _dbus_warn ("Unescaped '%s' as '%s' should have been '%s'\n",
00736 test->escaped, unescaped, test->unescaped);
00737 exit (1);
00738 }
00739 dbus_free (unescaped);
00740
00741 ++i;
00742 }
00743
00744 i = 0;
00745 while (i < _DBUS_N_ELEMENTS (invalid_escaped_values))
00746 {
00747 char *unescaped;
00748
00749 unescaped = dbus_address_unescape_value (invalid_escaped_values[i],
00750 &error);
00751 if (unescaped != NULL)
00752 {
00753 _dbus_warn ("Should not have successfully unescaped '%s' to '%s'\n",
00754 invalid_escaped_values[i], unescaped);
00755 dbus_free (unescaped);
00756 exit (1);
00757 }
00758
00759 _dbus_assert (dbus_error_is_set (&error));
00760 dbus_error_free (&error);
00761
00762 ++i;
00763 }
00764
00765 if (!dbus_parse_address ("unix:path=/tmp/foo;debug:name=test,sliff=sloff;",
00766 &entries, &len, &error))
00767 _dbus_assert_not_reached ("could not parse address");
00768 _dbus_assert (len == 2);
00769 _dbus_assert (strcmp (dbus_address_entry_get_value (entries[0], "path"), "/tmp/foo") == 0);
00770 _dbus_assert (strcmp (dbus_address_entry_get_value (entries[1], "name"), "test") == 0);
00771 _dbus_assert (strcmp (dbus_address_entry_get_value (entries[1], "sliff"), "sloff") == 0);
00772
00773 dbus_address_entries_free (entries);
00774
00775
00776 if (dbus_parse_address ("", &entries, &len, &error))
00777 _dbus_assert_not_reached ("Parsed incorrect address.");
00778 else
00779 dbus_error_free (&error);
00780
00781 if (dbus_parse_address ("foo", &entries, &len, &error))
00782 _dbus_assert_not_reached ("Parsed incorrect address.");
00783 else
00784 dbus_error_free (&error);
00785
00786 if (dbus_parse_address ("foo:bar", &entries, &len, &error))
00787 _dbus_assert_not_reached ("Parsed incorrect address.");
00788 else
00789 dbus_error_free (&error);
00790
00791 if (dbus_parse_address ("foo:bar,baz", &entries, &len, &error))
00792 _dbus_assert_not_reached ("Parsed incorrect address.");
00793 else
00794 dbus_error_free (&error);
00795
00796 if (dbus_parse_address ("foo:bar=foo,baz", &entries, &len, &error))
00797 _dbus_assert_not_reached ("Parsed incorrect address.");
00798 else
00799 dbus_error_free (&error);
00800
00801 if (dbus_parse_address ("foo:bar=foo;baz", &entries, &len, &error))
00802 _dbus_assert_not_reached ("Parsed incorrect address.");
00803 else
00804 dbus_error_free (&error);
00805
00806 if (dbus_parse_address ("foo:=foo", &entries, &len, &error))
00807 _dbus_assert_not_reached ("Parsed incorrect address.");
00808 else
00809 dbus_error_free (&error);
00810
00811 if (dbus_parse_address ("foo:foo=", &entries, &len, &error))
00812 _dbus_assert_not_reached ("Parsed incorrect address.");
00813 else
00814 dbus_error_free (&error);
00815
00816 if (dbus_parse_address ("foo:foo,bar=baz", &entries, &len, &error))
00817 _dbus_assert_not_reached ("Parsed incorrect address.");
00818 else
00819 dbus_error_free (&error);
00820
00821 return TRUE;
00822 }
00823
00824 #endif
00825
00826 #endif