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 while (pos < len)
00381 {
00382 DBusAddressEntry *entry;
00383
00384 int found_pos;
00385
00386 entry = create_entry ();
00387 if (!entry)
00388 {
00389 dbus_set_error (error, DBUS_ERROR_NO_MEMORY, NULL);
00390
00391 goto error;
00392 }
00393
00394
00395 if (!_dbus_list_append (&entries, entry))
00396 {
00397 dbus_set_error (error, DBUS_ERROR_NO_MEMORY, NULL);
00398 dbus_address_entry_free (entry);
00399 goto error;
00400 }
00401
00402
00403 if (!_dbus_string_find (&str, pos, ";", &end_pos))
00404 end_pos = len;
00405
00406
00407 if (!_dbus_string_find_to (&str, pos, end_pos, ":", &found_pos))
00408 {
00409 dbus_set_error (error, DBUS_ERROR_BAD_ADDRESS, "Address does not contain a colon");
00410 goto error;
00411 }
00412
00413 if (!_dbus_string_copy_len (&str, pos, found_pos - pos, &entry->method, 0))
00414 {
00415 dbus_set_error (error, DBUS_ERROR_NO_MEMORY, NULL);
00416 goto error;
00417 }
00418
00419 pos = found_pos + 1;
00420
00421 while (pos < end_pos)
00422 {
00423 int comma_pos, equals_pos;
00424
00425 if (!_dbus_string_find_to (&str, pos, end_pos, ",", &comma_pos))
00426 comma_pos = end_pos;
00427
00428 if (!_dbus_string_find_to (&str, pos, comma_pos, "=", &equals_pos) ||
00429 equals_pos == pos || equals_pos + 1 == comma_pos)
00430 {
00431 dbus_set_error (error, DBUS_ERROR_BAD_ADDRESS,
00432 "'=' character not found or has no value following it");
00433 goto error;
00434 }
00435 else
00436 {
00437 DBusString *key;
00438 DBusString *value;
00439
00440 key = dbus_new0 (DBusString, 1);
00441
00442 if (!key)
00443 {
00444 dbus_set_error (error, DBUS_ERROR_NO_MEMORY, NULL);
00445 goto error;
00446 }
00447
00448 value = dbus_new0 (DBusString, 1);
00449 if (!value)
00450 {
00451 dbus_set_error (error, DBUS_ERROR_NO_MEMORY, NULL);
00452 dbus_free (key);
00453 goto error;
00454 }
00455
00456 if (!_dbus_string_init (key))
00457 {
00458 dbus_set_error (error, DBUS_ERROR_NO_MEMORY, NULL);
00459 dbus_free (key);
00460 dbus_free (value);
00461
00462 goto error;
00463 }
00464
00465 if (!_dbus_string_init (value))
00466 {
00467 dbus_set_error (error, DBUS_ERROR_NO_MEMORY, NULL);
00468 _dbus_string_free (key);
00469
00470 dbus_free (key);
00471 dbus_free (value);
00472 goto error;
00473 }
00474
00475 if (!_dbus_string_copy_len (&str, pos, equals_pos - pos, key, 0))
00476 {
00477 dbus_set_error (error, DBUS_ERROR_NO_MEMORY, NULL);
00478 _dbus_string_free (key);
00479 _dbus_string_free (value);
00480
00481 dbus_free (key);
00482 dbus_free (value);
00483 goto error;
00484 }
00485
00486 if (!append_unescaped_value (value, &str, equals_pos + 1,
00487 comma_pos - equals_pos - 1, error))
00488 {
00489 _dbus_assert (error == NULL || dbus_error_is_set (error));
00490 _dbus_string_free (key);
00491 _dbus_string_free (value);
00492
00493 dbus_free (key);
00494 dbus_free (value);
00495 goto error;
00496 }
00497
00498 if (!_dbus_list_append (&entry->keys, key))
00499 {
00500 dbus_set_error (error, DBUS_ERROR_NO_MEMORY, NULL);
00501 _dbus_string_free (key);
00502 _dbus_string_free (value);
00503
00504 dbus_free (key);
00505 dbus_free (value);
00506 goto error;
00507 }
00508
00509 if (!_dbus_list_append (&entry->values, value))
00510 {
00511 dbus_set_error (error, DBUS_ERROR_NO_MEMORY, NULL);
00512 _dbus_string_free (value);
00513
00514 dbus_free (value);
00515 goto error;
00516 }
00517 }
00518
00519 pos = comma_pos + 1;
00520 }
00521
00522 pos = end_pos + 1;
00523 }
00524
00525 *array_len = _dbus_list_get_length (&entries);
00526
00527 entry_array = dbus_new (DBusAddressEntry *, *array_len + 1);
00528
00529 if (!entry_array)
00530 {
00531 dbus_set_error (error, DBUS_ERROR_NO_MEMORY, NULL);
00532
00533 goto error;
00534 }
00535
00536 entry_array [*array_len] = NULL;
00537
00538 link = _dbus_list_get_first_link (&entries);
00539 i = 0;
00540 while (link != NULL)
00541 {
00542 entry_array[i] = link->data;
00543 i++;
00544 link = _dbus_list_get_next_link (&entries, link);
00545 }
00546
00547 _dbus_list_clear (&entries);
00548 *entry = entry_array;
00549
00550 return TRUE;
00551
00552 error:
00553
00554 link = _dbus_list_get_first_link (&entries);
00555 while (link != NULL)
00556 {
00557 dbus_address_entry_free (link->data);
00558 link = _dbus_list_get_next_link (&entries, link);
00559 }
00560
00561 _dbus_list_clear (&entries);
00562
00563 return FALSE;
00564
00565 }
00566
00574 char*
00575 dbus_address_escape_value (const char *value)
00576 {
00577 DBusString escaped;
00578 DBusString unescaped;
00579 char *ret;
00580
00581 ret = NULL;
00582
00583 _dbus_string_init_const (&unescaped, value);
00584
00585 if (!_dbus_string_init (&escaped))
00586 return NULL;
00587
00588 if (!_dbus_address_append_escaped (&escaped, &unescaped))
00589 goto out;
00590
00591 if (!_dbus_string_steal_data (&escaped, &ret))
00592 goto out;
00593
00594 out:
00595 _dbus_string_free (&escaped);
00596 return ret;
00597 }
00598
00608 char*
00609 dbus_address_unescape_value (const char *value,
00610 DBusError *error)
00611 {
00612 DBusString unescaped;
00613 DBusString escaped;
00614 char *ret;
00615
00616 ret = NULL;
00617
00618 _dbus_string_init_const (&escaped, value);
00619
00620 if (!_dbus_string_init (&unescaped))
00621 return NULL;
00622
00623 if (!append_unescaped_value (&unescaped, &escaped,
00624 0, _dbus_string_get_length (&escaped),
00625 error))
00626 goto out;
00627
00628 if (!_dbus_string_steal_data (&unescaped, &ret))
00629 goto out;
00630
00631 out:
00632 if (ret == NULL && error && !dbus_error_is_set (error))
00633 _DBUS_SET_OOM (error);
00634
00635 _dbus_assert (ret != NULL || error == NULL || dbus_error_is_set (error));
00636
00637 _dbus_string_free (&unescaped);
00638 return ret;
00639 }
00640
00642
00643 #ifdef DBUS_BUILD_TESTS
00644
00645 #ifndef DOXYGEN_SHOULD_SKIP_THIS
00646
00647 #include "dbus-test.h"
00648 #include <stdlib.h>
00649
00650 typedef struct
00651 {
00652 const char *escaped;
00653 const char *unescaped;
00654 } EscapeTest;
00655
00656 static const EscapeTest escape_tests[] = {
00657 { "abcde", "abcde" },
00658 { "", "" },
00659 { "%20%20", " " },
00660 { "%24", "$" },
00661 { "%25", "%" },
00662 { "abc%24", "abc$" },
00663 { "%24abc", "$abc" },
00664 { "abc%24abc", "abc$abc" },
00665 { "/", "/" },
00666 { "-", "-" },
00667 { "_", "_" },
00668 { "A", "A" },
00669 { "I", "I" },
00670 { "Z", "Z" },
00671 { "a", "a" },
00672 { "i", "i" },
00673 { "z", "z" }
00674 };
00675
00676 static const char* invalid_escaped_values[] = {
00677 "%a",
00678 "%q",
00679 "%az",
00680 "%%",
00681 "%$$",
00682 "abc%a",
00683 "%axyz",
00684 "%",
00685 "$",
00686 " ",
00687 "*"
00688 };
00689
00690 dbus_bool_t
00691 _dbus_address_test (void)
00692 {
00693 DBusAddressEntry **entries;
00694 int len;
00695 DBusError error;
00696 int i;
00697
00698 dbus_error_init (&error);
00699
00700 i = 0;
00701 while (i < _DBUS_N_ELEMENTS (escape_tests))
00702 {
00703 const EscapeTest *test = &escape_tests[i];
00704 char *escaped;
00705 char *unescaped;
00706
00707 escaped = dbus_address_escape_value (test->unescaped);
00708 if (escaped == NULL)
00709 _dbus_assert_not_reached ("oom");
00710
00711 if (strcmp (escaped, test->escaped) != 0)
00712 {
00713 _dbus_warn ("Escaped '%s' as '%s' should have been '%s'\n",
00714 test->unescaped, escaped, test->escaped);
00715 exit (1);
00716 }
00717 dbus_free (escaped);
00718
00719 unescaped = dbus_address_unescape_value (test->escaped, &error);
00720 if (unescaped == NULL)
00721 {
00722 _dbus_warn ("Failed to unescape '%s': %s\n",
00723 test->escaped, error.message);
00724 dbus_error_free (&error);
00725 exit (1);
00726 }
00727
00728 if (strcmp (unescaped, test->unescaped) != 0)
00729 {
00730 _dbus_warn ("Unescaped '%s' as '%s' should have been '%s'\n",
00731 test->escaped, unescaped, test->unescaped);
00732 exit (1);
00733 }
00734 dbus_free (unescaped);
00735
00736 ++i;
00737 }
00738
00739 i = 0;
00740 while (i < _DBUS_N_ELEMENTS (invalid_escaped_values))
00741 {
00742 char *unescaped;
00743
00744 unescaped = dbus_address_unescape_value (invalid_escaped_values[i],
00745 &error);
00746 if (unescaped != NULL)
00747 {
00748 _dbus_warn ("Should not have successfully unescaped '%s' to '%s'\n",
00749 invalid_escaped_values[i], unescaped);
00750 dbus_free (unescaped);
00751 exit (1);
00752 }
00753
00754 _dbus_assert (dbus_error_is_set (&error));
00755 dbus_error_free (&error);
00756
00757 ++i;
00758 }
00759
00760 if (!dbus_parse_address ("unix:path=/tmp/foo;debug:name=test,sliff=sloff;",
00761 &entries, &len, &error))
00762 _dbus_assert_not_reached ("could not parse address");
00763 _dbus_assert (len == 2);
00764 _dbus_assert (strcmp (dbus_address_entry_get_value (entries[0], "path"), "/tmp/foo") == 0);
00765 _dbus_assert (strcmp (dbus_address_entry_get_value (entries[1], "name"), "test") == 0);
00766 _dbus_assert (strcmp (dbus_address_entry_get_value (entries[1], "sliff"), "sloff") == 0);
00767
00768 dbus_address_entries_free (entries);
00769
00770
00771 if (dbus_parse_address ("foo", &entries, &len, &error))
00772 _dbus_assert_not_reached ("Parsed incorrect address.");
00773 else
00774 dbus_error_free (&error);
00775
00776 if (dbus_parse_address ("foo:bar", &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:bar,baz", &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=foo,baz", &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=foo;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:=foo", &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:foo=", &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,bar=baz", &entries, &len, &error))
00807 _dbus_assert_not_reached ("Parsed incorrect address.");
00808 else
00809 dbus_error_free (&error);
00810
00811 return TRUE;
00812 }
00813
00814 #endif
00815
00816 #endif