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