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
00052
00053 static void
00054 dbus_address_entry_free (DBusAddressEntry *entry)
00055 {
00056 DBusList *link;
00057
00058 _dbus_string_free (&entry->method);
00059
00060 link = _dbus_list_get_first_link (&entry->keys);
00061 while (link != NULL)
00062 {
00063 _dbus_string_free (link->data);
00064 dbus_free (link->data);
00065
00066 link = _dbus_list_get_next_link (&entry->keys, link);
00067 }
00068 _dbus_list_clear (&entry->keys);
00069
00070 link = _dbus_list_get_first_link (&entry->values);
00071 while (link != NULL)
00072 {
00073 _dbus_string_free (link->data);
00074 dbus_free (link->data);
00075
00076 link = _dbus_list_get_next_link (&entry->values, link);
00077 }
00078 _dbus_list_clear (&entry->values);
00079
00080 dbus_free (entry);
00081 }
00082
00096 void
00097 dbus_address_entries_free (DBusAddressEntry **entries)
00098 {
00099 int i;
00100
00101 for (i = 0; entries[i] != NULL; i++)
00102 dbus_address_entry_free (entries[i]);
00103 dbus_free (entries);
00104 }
00105
00106 static DBusAddressEntry *
00107 create_entry (void)
00108 {
00109 DBusAddressEntry *entry;
00110
00111 entry = dbus_new0 (DBusAddressEntry, 1);
00112
00113 if (entry == NULL)
00114 return NULL;
00115
00116 if (!_dbus_string_init (&entry->method))
00117 {
00118 dbus_free (entry);
00119 return NULL;
00120 }
00121
00122 return entry;
00123 }
00124
00132 const char *
00133 dbus_address_entry_get_method (DBusAddressEntry *entry)
00134 {
00135 return _dbus_string_get_const_data (&entry->method);
00136 }
00137
00145 const char *
00146 dbus_address_entry_get_value (DBusAddressEntry *entry,
00147 const char *key)
00148 {
00149 DBusList *values, *keys;
00150
00151 keys = _dbus_list_get_first_link (&entry->keys);
00152 values = _dbus_list_get_first_link (&entry->values);
00153
00154 while (keys != NULL)
00155 {
00156 _dbus_assert (values != NULL);
00157
00158 if (_dbus_string_equal_c_str (keys->data, key))
00159 return _dbus_string_get_const_data (values->data);
00160
00161 keys = _dbus_list_get_next_link (&entry->keys, keys);
00162 values = _dbus_list_get_next_link (&entry->values, values);
00163 }
00164
00165 return NULL;
00166 }
00167
00168 #define _DBUS_ADDRESS_OPTIONALLY_ESCAPED_BYTE(b) \
00169 (((b) >= 'a' && (b) <= 'z') || \
00170 ((b) >= 'A' && (b) <= 'Z') || \
00171 ((b) >= '0' && (b) <= '9') || \
00172 (b) == '-' || \
00173 (b) == '_' || \
00174 (b) == '/' || \
00175 (b) == '\\' || \
00176 (b) == '.')
00177
00186 dbus_bool_t
00187 _dbus_address_append_escaped (DBusString *escaped,
00188 const DBusString *unescaped)
00189 {
00190 const char *p;
00191 const char *end;
00192 dbus_bool_t ret;
00193 int orig_len;
00194
00195 ret = FALSE;
00196
00197 orig_len = _dbus_string_get_length (escaped);
00198 p = _dbus_string_get_const_data (unescaped);
00199 end = p + _dbus_string_get_length (unescaped);
00200 while (p != end)
00201 {
00202 if (_DBUS_ADDRESS_OPTIONALLY_ESCAPED_BYTE (*p))
00203 {
00204 if (!_dbus_string_append_byte (escaped, *p))
00205 goto out;
00206 }
00207 else
00208 {
00209 if (!_dbus_string_append_byte (escaped, '%'))
00210 goto out;
00211 if (!_dbus_string_append_byte_as_hex (escaped, *p))
00212 goto out;
00213 }
00214
00215 ++p;
00216 }
00217
00218 ret = TRUE;
00219
00220 out:
00221 if (!ret)
00222 _dbus_string_set_length (escaped, orig_len);
00223 return ret;
00224 }
00225
00226 static dbus_bool_t
00227 append_unescaped_value (DBusString *unescaped,
00228 const DBusString *escaped,
00229 int escaped_start,
00230 int escaped_len,
00231 DBusError *error)
00232 {
00233 const char *p;
00234 const char *end;
00235 dbus_bool_t ret;
00236
00237 ret = FALSE;
00238
00239 p = _dbus_string_get_const_data (escaped) + escaped_start;
00240 end = p + escaped_len;
00241 while (p != end)
00242 {
00243 if (_DBUS_ADDRESS_OPTIONALLY_ESCAPED_BYTE (*p))
00244 {
00245 if (!_dbus_string_append_byte (unescaped, *p))
00246 goto out;
00247 }
00248 else if (*p == '%')
00249 {
00250
00251 char buf[3];
00252 DBusString hex;
00253 int hex_end;
00254
00255 ++p;
00256
00257 if ((p + 2) > end)
00258 {
00259 dbus_set_error (error, DBUS_ERROR_BAD_ADDRESS,
00260 "In D-Bus address, percent character was not followed by two hex digits");
00261 goto out;
00262 }
00263
00264 buf[0] = *p;
00265 ++p;
00266 buf[1] = *p;
00267 buf[2] = '\0';
00268
00269 _dbus_string_init_const (&hex, buf);
00270
00271 if (!_dbus_string_hex_decode (&hex, 0, &hex_end,
00272 unescaped,
00273 _dbus_string_get_length (unescaped)))
00274 goto out;
00275
00276 if (hex_end != 2)
00277 {
00278 dbus_set_error (error, DBUS_ERROR_BAD_ADDRESS,
00279 "In D-Bus address, percent character was followed by characters other than hex digits");
00280 goto out;
00281 }
00282 }
00283 else
00284 {
00285
00286 dbus_set_error (error, DBUS_ERROR_BAD_ADDRESS,
00287 "In D-Bus address, character '%c' should have been escaped\n",
00288 *p);
00289 goto out;
00290 }
00291
00292 ++p;
00293 }
00294
00295 ret = TRUE;
00296
00297 out:
00298 if (!ret && error && !dbus_error_is_set (error))
00299 _DBUS_SET_OOM (error);
00300
00301 _dbus_assert (ret || error == NULL || dbus_error_is_set (error));
00302
00303 return ret;
00304 }
00305
00319 dbus_bool_t
00320 dbus_parse_address (const char *address,
00321 DBusAddressEntry ***entry,
00322 int *array_len,
00323 DBusError *error)
00324 {
00325 DBusString str;
00326 int pos, end_pos, len, i;
00327 DBusList *entries, *link;
00328 DBusAddressEntry **entry_array;
00329
00330 _DBUS_ASSERT_ERROR_IS_CLEAR (error);
00331
00332 _dbus_string_init_const (&str, address);
00333
00334 entries = NULL;
00335 pos = 0;
00336 len = _dbus_string_get_length (&str);
00337
00338 while (pos < len)
00339 {
00340 DBusAddressEntry *entry;
00341
00342 int found_pos;
00343
00344 entry = create_entry ();
00345 if (!entry)
00346 {
00347 dbus_set_error (error, DBUS_ERROR_NO_MEMORY, NULL);
00348
00349 goto error;
00350 }
00351
00352
00353 if (!_dbus_list_append (&entries, entry))
00354 {
00355 dbus_set_error (error, DBUS_ERROR_NO_MEMORY, NULL);
00356 dbus_address_entry_free (entry);
00357 goto error;
00358 }
00359
00360
00361 if (!_dbus_string_find (&str, pos, ";", &end_pos))
00362 end_pos = len;
00363
00364
00365 if (!_dbus_string_find_to (&str, pos, end_pos, ":", &found_pos))
00366 {
00367 dbus_set_error (error, DBUS_ERROR_BAD_ADDRESS, "Address does not contain a colon");
00368 goto error;
00369 }
00370
00371 if (!_dbus_string_copy_len (&str, pos, found_pos - pos, &entry->method, 0))
00372 {
00373 dbus_set_error (error, DBUS_ERROR_NO_MEMORY, NULL);
00374 goto error;
00375 }
00376
00377 pos = found_pos + 1;
00378
00379 while (pos < end_pos)
00380 {
00381 int comma_pos, equals_pos;
00382
00383 if (!_dbus_string_find_to (&str, pos, end_pos, ",", &comma_pos))
00384 comma_pos = end_pos;
00385
00386 if (!_dbus_string_find_to (&str, pos, comma_pos, "=", &equals_pos) ||
00387 equals_pos == pos || equals_pos + 1 == comma_pos)
00388 {
00389 dbus_set_error (error, DBUS_ERROR_BAD_ADDRESS,
00390 "'=' character not found or has no value following it");
00391 goto error;
00392 }
00393 else
00394 {
00395 DBusString *key;
00396 DBusString *value;
00397
00398 key = dbus_new0 (DBusString, 1);
00399
00400 if (!key)
00401 {
00402 dbus_set_error (error, DBUS_ERROR_NO_MEMORY, NULL);
00403 goto error;
00404 }
00405
00406 value = dbus_new0 (DBusString, 1);
00407 if (!value)
00408 {
00409 dbus_set_error (error, DBUS_ERROR_NO_MEMORY, NULL);
00410 dbus_free (key);
00411 goto error;
00412 }
00413
00414 if (!_dbus_string_init (key))
00415 {
00416 dbus_set_error (error, DBUS_ERROR_NO_MEMORY, NULL);
00417 dbus_free (key);
00418 dbus_free (value);
00419
00420 goto error;
00421 }
00422
00423 if (!_dbus_string_init (value))
00424 {
00425 dbus_set_error (error, DBUS_ERROR_NO_MEMORY, NULL);
00426 _dbus_string_free (key);
00427
00428 dbus_free (key);
00429 dbus_free (value);
00430 goto error;
00431 }
00432
00433 if (!_dbus_string_copy_len (&str, pos, equals_pos - pos, key, 0))
00434 {
00435 dbus_set_error (error, DBUS_ERROR_NO_MEMORY, NULL);
00436 _dbus_string_free (key);
00437 _dbus_string_free (value);
00438
00439 dbus_free (key);
00440 dbus_free (value);
00441 goto error;
00442 }
00443
00444 if (!append_unescaped_value (value, &str, equals_pos + 1,
00445 comma_pos - equals_pos - 1, error))
00446 {
00447 _dbus_assert (error == NULL || dbus_error_is_set (error));
00448 _dbus_string_free (key);
00449 _dbus_string_free (value);
00450
00451 dbus_free (key);
00452 dbus_free (value);
00453 goto error;
00454 }
00455
00456 if (!_dbus_list_append (&entry->keys, key))
00457 {
00458 dbus_set_error (error, DBUS_ERROR_NO_MEMORY, NULL);
00459 _dbus_string_free (key);
00460 _dbus_string_free (value);
00461
00462 dbus_free (key);
00463 dbus_free (value);
00464 goto error;
00465 }
00466
00467 if (!_dbus_list_append (&entry->values, value))
00468 {
00469 dbus_set_error (error, DBUS_ERROR_NO_MEMORY, NULL);
00470 _dbus_string_free (value);
00471
00472 dbus_free (value);
00473 goto error;
00474 }
00475 }
00476
00477 pos = comma_pos + 1;
00478 }
00479
00480 pos = end_pos + 1;
00481 }
00482
00483 *array_len = _dbus_list_get_length (&entries);
00484
00485 entry_array = dbus_new (DBusAddressEntry *, *array_len + 1);
00486
00487 if (!entry_array)
00488 {
00489 dbus_set_error (error, DBUS_ERROR_NO_MEMORY, NULL);
00490
00491 goto error;
00492 }
00493
00494 entry_array [*array_len] = NULL;
00495
00496 link = _dbus_list_get_first_link (&entries);
00497 i = 0;
00498 while (link != NULL)
00499 {
00500 entry_array[i] = link->data;
00501 i++;
00502 link = _dbus_list_get_next_link (&entries, link);
00503 }
00504
00505 _dbus_list_clear (&entries);
00506 *entry = entry_array;
00507
00508 return TRUE;
00509
00510 error:
00511
00512 link = _dbus_list_get_first_link (&entries);
00513 while (link != NULL)
00514 {
00515 dbus_address_entry_free (link->data);
00516 link = _dbus_list_get_next_link (&entries, link);
00517 }
00518
00519 _dbus_list_clear (&entries);
00520
00521 return FALSE;
00522
00523 }
00524
00532 char*
00533 dbus_address_escape_value (const char *value)
00534 {
00535 DBusString escaped;
00536 DBusString unescaped;
00537 char *ret;
00538
00539 ret = NULL;
00540
00541 _dbus_string_init_const (&unescaped, value);
00542
00543 if (!_dbus_string_init (&escaped))
00544 return NULL;
00545
00546 if (!_dbus_address_append_escaped (&escaped, &unescaped))
00547 goto out;
00548
00549 if (!_dbus_string_steal_data (&escaped, &ret))
00550 goto out;
00551
00552 out:
00553 _dbus_string_free (&escaped);
00554 return ret;
00555 }
00556
00565 char*
00566 dbus_address_unescape_value (const char *value,
00567 DBusError *error)
00568 {
00569 DBusString unescaped;
00570 DBusString escaped;
00571 char *ret;
00572
00573 ret = NULL;
00574
00575 _dbus_string_init_const (&escaped, value);
00576
00577 if (!_dbus_string_init (&unescaped))
00578 return NULL;
00579
00580 if (!append_unescaped_value (&unescaped, &escaped,
00581 0, _dbus_string_get_length (&escaped),
00582 error))
00583 goto out;
00584
00585 if (!_dbus_string_steal_data (&unescaped, &ret))
00586 goto out;
00587
00588 out:
00589 if (ret == NULL && error && !dbus_error_is_set (error))
00590 _DBUS_SET_OOM (error);
00591
00592 _dbus_assert (ret != NULL || error == NULL || dbus_error_is_set (error));
00593
00594 _dbus_string_free (&unescaped);
00595 return ret;
00596 }
00597
00599
00600 #ifdef DBUS_BUILD_TESTS
00601 #include "dbus-test.h"
00602 #include <stdlib.h>
00603
00604 typedef struct
00605 {
00606 const char *escaped;
00607 const char *unescaped;
00608 } EscapeTest;
00609
00610 static const EscapeTest escape_tests[] = {
00611 { "abcde", "abcde" },
00612 { "", "" },
00613 { "%20%20", " " },
00614 { "%24", "$" },
00615 { "%25", "%" },
00616 { "abc%24", "abc$" },
00617 { "%24abc", "$abc" },
00618 { "abc%24abc", "abc$abc" },
00619 { "/", "/" },
00620 { "-", "-" },
00621 { "_", "_" },
00622 { "A", "A" },
00623 { "I", "I" },
00624 { "Z", "Z" },
00625 { "a", "a" },
00626 { "i", "i" },
00627 { "z", "z" }
00628 };
00629
00630 static const char* invalid_escaped_values[] = {
00631 "%a",
00632 "%q",
00633 "%az",
00634 "%%",
00635 "%$$",
00636 "abc%a",
00637 "%axyz",
00638 "%",
00639 "$",
00640 " ",
00641 "*"
00642 };
00643
00644 dbus_bool_t
00645 _dbus_address_test (void)
00646 {
00647 DBusAddressEntry **entries;
00648 int len;
00649 DBusError error;
00650 int i;
00651
00652 dbus_error_init (&error);
00653
00654 i = 0;
00655 while (i < _DBUS_N_ELEMENTS (escape_tests))
00656 {
00657 const EscapeTest *test = &escape_tests[i];
00658 char *escaped;
00659 char *unescaped;
00660
00661 escaped = dbus_address_escape_value (test->unescaped);
00662 if (escaped == NULL)
00663 _dbus_assert_not_reached ("oom");
00664
00665 if (strcmp (escaped, test->escaped) != 0)
00666 {
00667 _dbus_warn ("Escaped '%s' as '%s' should have been '%s'\n",
00668 test->unescaped, escaped, test->escaped);
00669 exit (1);
00670 }
00671 dbus_free (escaped);
00672
00673 unescaped = dbus_address_unescape_value (test->escaped, &error);
00674 if (unescaped == NULL)
00675 {
00676 _dbus_warn ("Failed to unescape '%s': %s\n",
00677 test->escaped, error.message);
00678 dbus_error_free (&error);
00679 exit (1);
00680 }
00681
00682 if (strcmp (unescaped, test->unescaped) != 0)
00683 {
00684 _dbus_warn ("Unescaped '%s' as '%s' should have been '%s'\n",
00685 test->escaped, unescaped, test->unescaped);
00686 exit (1);
00687 }
00688 dbus_free (unescaped);
00689
00690 ++i;
00691 }
00692
00693 i = 0;
00694 while (i < _DBUS_N_ELEMENTS (invalid_escaped_values))
00695 {
00696 char *unescaped;
00697
00698 unescaped = dbus_address_unescape_value (invalid_escaped_values[i],
00699 &error);
00700 if (unescaped != NULL)
00701 {
00702 _dbus_warn ("Should not have successfully unescaped '%s' to '%s'\n",
00703 invalid_escaped_values[i], unescaped);
00704 dbus_free (unescaped);
00705 exit (1);
00706 }
00707
00708 _dbus_assert (dbus_error_is_set (&error));
00709 dbus_error_free (&error);
00710
00711 ++i;
00712 }
00713
00714 if (!dbus_parse_address ("unix:path=/tmp/foo;debug:name=test,sliff=sloff;",
00715 &entries, &len, &error))
00716 _dbus_assert_not_reached ("could not parse address");
00717 _dbus_assert (len == 2);
00718 _dbus_assert (strcmp (dbus_address_entry_get_value (entries[0], "path"), "/tmp/foo") == 0);
00719 _dbus_assert (strcmp (dbus_address_entry_get_value (entries[1], "name"), "test") == 0);
00720 _dbus_assert (strcmp (dbus_address_entry_get_value (entries[1], "sliff"), "sloff") == 0);
00721
00722 dbus_address_entries_free (entries);
00723
00724
00725 if (dbus_parse_address ("foo", &entries, &len, &error))
00726 _dbus_assert_not_reached ("Parsed incorrect address.");
00727 else
00728 dbus_error_free (&error);
00729
00730 if (dbus_parse_address ("foo:bar", &entries, &len, &error))
00731 _dbus_assert_not_reached ("Parsed incorrect address.");
00732 else
00733 dbus_error_free (&error);
00734
00735 if (dbus_parse_address ("foo:bar,baz", &entries, &len, &error))
00736 _dbus_assert_not_reached ("Parsed incorrect address.");
00737 else
00738 dbus_error_free (&error);
00739
00740 if (dbus_parse_address ("foo:bar=foo,baz", &entries, &len, &error))
00741 _dbus_assert_not_reached ("Parsed incorrect address.");
00742 else
00743 dbus_error_free (&error);
00744
00745 if (dbus_parse_address ("foo:bar=foo;baz", &entries, &len, &error))
00746 _dbus_assert_not_reached ("Parsed incorrect address.");
00747 else
00748 dbus_error_free (&error);
00749
00750 if (dbus_parse_address ("foo:=foo", &entries, &len, &error))
00751 _dbus_assert_not_reached ("Parsed incorrect address.");
00752 else
00753 dbus_error_free (&error);
00754
00755 if (dbus_parse_address ("foo:foo=", &entries, &len, &error))
00756 _dbus_assert_not_reached ("Parsed incorrect address.");
00757 else
00758 dbus_error_free (&error);
00759
00760 if (dbus_parse_address ("foo:foo,bar=baz", &entries, &len, &error))
00761 _dbus_assert_not_reached ("Parsed incorrect address.");
00762 else
00763 dbus_error_free (&error);
00764
00765 return TRUE;
00766 }
00767
00768 #endif