• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /* -*- mode: C; c-file-style: "gnu" -*- */
2 /* dbus-address.c  Server address parser.
3  *
4  * Copyright (C) 2003  CodeFactory AB
5  * Copyright (C) 2004,2005  Red Hat, Inc.
6  *
7  * Licensed under the Academic Free License version 2.1
8  *
9  * This program is free software; you can redistribute it and/or modify
10  * it under the terms of the GNU General Public License as published by
11  * the Free Software Foundation; either version 2 of the License, or
12  * (at your option) any later version.
13  *
14  * This program is distributed in the hope that it will be useful,
15  * but WITHOUT ANY WARRANTY; without even the implied warranty of
16  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17  * GNU General Public License for more details.
18  *
19  * You should have received a copy of the GNU General Public License
20  * along with this program; if not, write to the Free Software
21  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
22  *
23  */
24 
25 #include <config.h>
26 #include "dbus-address.h"
27 #include "dbus-internals.h"
28 #include "dbus-list.h"
29 #include "dbus-string.h"
30 #include "dbus-protocol.h"
31 
32 /**
33  * @defgroup DBusAddressInternals Address parsing
34  * @ingroup  DBusInternals
35  * @brief Implementation of parsing addresses of D-Bus servers.
36  *
37  * @{
38  */
39 
40 /**
41  * Internals of DBusAddressEntry
42  */
43 struct DBusAddressEntry
44 {
45   DBusString method; /**< The address type (unix, tcp, etc.) */
46 
47   DBusList *keys;    /**< List of keys */
48   DBusList *values;  /**< List of values */
49 };
50 
51 
52 /**
53  *
54  * Sets #DBUS_ERROR_BAD_ADDRESS.
55  * If address_problem_type and address_problem_field are not #NULL,
56  * sets an error message about how the field is no good. Otherwise, sets
57  * address_problem_other as the error message.
58  *
59  * @param error the error to set
60  * @param address_problem_type the address type of the bad address or #NULL
61  * @param address_problem_field the missing field of the bad address or #NULL
62  * @param address_problem_other any other error message or #NULL
63  */
64 void
_dbus_set_bad_address(DBusError * error,const char * address_problem_type,const char * address_problem_field,const char * address_problem_other)65 _dbus_set_bad_address (DBusError  *error,
66                        const char *address_problem_type,
67                        const char *address_problem_field,
68                        const char *address_problem_other)
69 {
70   if (address_problem_type != NULL)
71     dbus_set_error (error, DBUS_ERROR_BAD_ADDRESS,
72                     "Server address of type %s was missing argument %s",
73                     address_problem_type, address_problem_field);
74   else
75     dbus_set_error (error, DBUS_ERROR_BAD_ADDRESS,
76                     "Could not parse server address: %s",
77                     address_problem_other);
78 }
79 
80 /**
81  * #TRUE if the byte need not be escaped when found in a dbus address.
82  * All other bytes are required to be escaped in a valid address.
83  */
84 #define _DBUS_ADDRESS_OPTIONALLY_ESCAPED_BYTE(b)        \
85          (((b) >= 'a' && (b) <= 'z') ||                 \
86           ((b) >= 'A' && (b) <= 'Z') ||                 \
87           ((b) >= '0' && (b) <= '9') ||                 \
88           (b) == '-' ||                                 \
89           (b) == '_' ||                                 \
90           (b) == '/' ||                                 \
91           (b) == '\\' ||                                \
92           (b) == '.')
93 
94 /**
95  * Appends an escaped version of one string to another string,
96  * using the D-Bus address escaping mechanism
97  *
98  * @param escaped the string to append to
99  * @param unescaped the string to escape
100  * @returns #FALSE if no memory
101  */
102 dbus_bool_t
_dbus_address_append_escaped(DBusString * escaped,const DBusString * unescaped)103 _dbus_address_append_escaped (DBusString       *escaped,
104                               const DBusString *unescaped)
105 {
106   const char *p;
107   const char *end;
108   dbus_bool_t ret;
109   int orig_len;
110 
111   ret = FALSE;
112 
113   orig_len = _dbus_string_get_length (escaped);
114   p = _dbus_string_get_const_data (unescaped);
115   end = p + _dbus_string_get_length (unescaped);
116   while (p != end)
117     {
118       if (_DBUS_ADDRESS_OPTIONALLY_ESCAPED_BYTE (*p))
119         {
120           if (!_dbus_string_append_byte (escaped, *p))
121             goto out;
122         }
123       else
124         {
125           if (!_dbus_string_append_byte (escaped, '%'))
126             goto out;
127           if (!_dbus_string_append_byte_as_hex (escaped, *p))
128             goto out;
129         }
130 
131       ++p;
132     }
133 
134   ret = TRUE;
135 
136  out:
137   if (!ret)
138     _dbus_string_set_length (escaped, orig_len);
139   return ret;
140 }
141 
142 /** @} */ /* End of internals */
143 
144 static void
dbus_address_entry_free(DBusAddressEntry * entry)145 dbus_address_entry_free (DBusAddressEntry *entry)
146 {
147   DBusList *link;
148 
149   _dbus_string_free (&entry->method);
150 
151   link = _dbus_list_get_first_link (&entry->keys);
152   while (link != NULL)
153     {
154       _dbus_string_free (link->data);
155       dbus_free (link->data);
156 
157       link = _dbus_list_get_next_link (&entry->keys, link);
158     }
159   _dbus_list_clear (&entry->keys);
160 
161   link = _dbus_list_get_first_link (&entry->values);
162   while (link != NULL)
163     {
164       _dbus_string_free (link->data);
165       dbus_free (link->data);
166 
167       link = _dbus_list_get_next_link (&entry->values, link);
168     }
169   _dbus_list_clear (&entry->values);
170 
171   dbus_free (entry);
172 }
173 
174 /**
175  * @defgroup DBusAddress Address parsing
176  * @ingroup  DBus
177  * @brief Parsing addresses of D-Bus servers.
178  *
179  * @{
180  */
181 
182 /**
183  * Frees a #NULL-terminated array of address entries.
184  *
185  * @param entries the array.
186  */
187 void
dbus_address_entries_free(DBusAddressEntry ** entries)188 dbus_address_entries_free (DBusAddressEntry **entries)
189 {
190   int i;
191 
192   for (i = 0; entries[i] != NULL; i++)
193     dbus_address_entry_free (entries[i]);
194   dbus_free (entries);
195 }
196 
197 static DBusAddressEntry *
create_entry(void)198 create_entry (void)
199 {
200   DBusAddressEntry *entry;
201 
202   entry = dbus_new0 (DBusAddressEntry, 1);
203 
204   if (entry == NULL)
205     return NULL;
206 
207   if (!_dbus_string_init (&entry->method))
208     {
209       dbus_free (entry);
210       return NULL;
211     }
212 
213   return entry;
214 }
215 
216 /**
217  * Returns the method string of an address entry.  For example, given
218  * the address entry "tcp:host=example.com" it would return the string
219  * "tcp"
220  *
221  * @param entry the entry.
222  * @returns a string describing the method. This string
223  * must not be freed.
224  */
225 const char *
dbus_address_entry_get_method(DBusAddressEntry * entry)226 dbus_address_entry_get_method (DBusAddressEntry *entry)
227 {
228   return _dbus_string_get_const_data (&entry->method);
229 }
230 
231 /**
232  * Returns a value from a key of an entry. For example,
233  * given the address "tcp:host=example.com,port=8073" if you asked
234  * for the key "host" you would get the value "example.com"
235  *
236  * The returned value is already unescaped.
237  *
238  * @param entry the entry.
239  * @param key the key.
240  * @returns the key value. This string must not be freed.
241  */
242 const char *
dbus_address_entry_get_value(DBusAddressEntry * entry,const char * key)243 dbus_address_entry_get_value (DBusAddressEntry *entry,
244 			      const char       *key)
245 {
246   DBusList *values, *keys;
247 
248   keys = _dbus_list_get_first_link (&entry->keys);
249   values = _dbus_list_get_first_link (&entry->values);
250 
251   while (keys != NULL)
252     {
253       _dbus_assert (values != NULL);
254 
255       if (_dbus_string_equal_c_str (keys->data, key))
256         return _dbus_string_get_const_data (values->data);
257 
258       keys = _dbus_list_get_next_link (&entry->keys, keys);
259       values = _dbus_list_get_next_link (&entry->values, values);
260     }
261 
262   return NULL;
263 }
264 
265 static dbus_bool_t
append_unescaped_value(DBusString * unescaped,const DBusString * escaped,int escaped_start,int escaped_len,DBusError * error)266 append_unescaped_value (DBusString       *unescaped,
267                         const DBusString *escaped,
268                         int               escaped_start,
269                         int               escaped_len,
270                         DBusError        *error)
271 {
272   const char *p;
273   const char *end;
274   dbus_bool_t ret;
275 
276   ret = FALSE;
277 
278   p = _dbus_string_get_const_data (escaped) + escaped_start;
279   end = p + escaped_len;
280   while (p != end)
281     {
282       if (_DBUS_ADDRESS_OPTIONALLY_ESCAPED_BYTE (*p))
283         {
284           if (!_dbus_string_append_byte (unescaped, *p))
285             goto out;
286         }
287       else if (*p == '%')
288         {
289           /* Efficiency is king */
290           char buf[3];
291           DBusString hex;
292           int hex_end;
293 
294           ++p;
295 
296           if ((p + 2) > end)
297             {
298               dbus_set_error (error, DBUS_ERROR_BAD_ADDRESS,
299                               "In D-Bus address, percent character was not followed by two hex digits");
300               goto out;
301             }
302 
303           buf[0] = *p;
304           ++p;
305           buf[1] = *p;
306           buf[2] = '\0';
307 
308           _dbus_string_init_const (&hex, buf);
309 
310           if (!_dbus_string_hex_decode (&hex, 0, &hex_end,
311                                         unescaped,
312                                         _dbus_string_get_length (unescaped)))
313             goto out;
314 
315           if (hex_end != 2)
316             {
317               dbus_set_error (error, DBUS_ERROR_BAD_ADDRESS,
318                               "In D-Bus address, percent character was followed by characters other than hex digits");
319               goto out;
320             }
321         }
322       else
323         {
324           /* Error, should have been escaped */
325           dbus_set_error (error, DBUS_ERROR_BAD_ADDRESS,
326                           "In D-Bus address, character '%c' should have been escaped\n",
327                           *p);
328           goto out;
329         }
330 
331       ++p;
332     }
333 
334   ret = TRUE;
335 
336  out:
337   if (!ret && error && !dbus_error_is_set (error))
338     _DBUS_SET_OOM (error);
339 
340   _dbus_assert (ret || error == NULL || dbus_error_is_set (error));
341 
342   return ret;
343 }
344 
345 /**
346  * Parses an address string of the form:
347  *
348  * method:key=value,key=value;method:key=value
349  *
350  * See the D-Bus specification for complete docs on the format.
351  *
352  * When connecting to an address, the first address entries
353  * in the semicolon-separated list should be tried first.
354  *
355  * @param address the address.
356  * @param entry return location to an array of entries.
357  * @param array_len return location for array length.
358  * @param error address where an error can be returned.
359  * @returns #TRUE on success, #FALSE otherwise.
360  */
361 dbus_bool_t
dbus_parse_address(const char * address,DBusAddressEntry *** entry,int * array_len,DBusError * error)362 dbus_parse_address (const char         *address,
363 		    DBusAddressEntry ***entry,
364 		    int                *array_len,
365                     DBusError          *error)
366 {
367   DBusString str;
368   int pos, end_pos, len, i;
369   DBusList *entries, *link;
370   DBusAddressEntry **entry_array;
371 
372   _DBUS_ASSERT_ERROR_IS_CLEAR (error);
373 
374   _dbus_string_init_const (&str, address);
375 
376   entries = NULL;
377   pos = 0;
378   len = _dbus_string_get_length (&str);
379 
380   while (pos < len)
381     {
382       DBusAddressEntry *entry;
383 
384       int found_pos;
385 
386       entry = create_entry ();
387       if (!entry)
388 	{
389 	  dbus_set_error (error, DBUS_ERROR_NO_MEMORY, NULL);
390 
391 	  goto error;
392 	}
393 
394       /* Append the entry */
395       if (!_dbus_list_append (&entries, entry))
396 	{
397 	  dbus_set_error (error, DBUS_ERROR_NO_MEMORY, NULL);
398 	  dbus_address_entry_free (entry);
399 	  goto error;
400 	}
401 
402       /* Look for a semi-colon */
403       if (!_dbus_string_find (&str, pos, ";", &end_pos))
404 	end_pos = len;
405 
406       /* Look for the colon : */
407       if (!_dbus_string_find_to (&str, pos, end_pos, ":", &found_pos))
408 	{
409 	  dbus_set_error (error, DBUS_ERROR_BAD_ADDRESS, "Address does not contain a colon");
410 	  goto error;
411 	}
412 
413       if (!_dbus_string_copy_len (&str, pos, found_pos - pos, &entry->method, 0))
414 	{
415 	  dbus_set_error (error, DBUS_ERROR_NO_MEMORY, NULL);
416 	  goto error;
417 	}
418 
419       pos = found_pos + 1;
420 
421       while (pos < end_pos)
422 	{
423 	  int comma_pos, equals_pos;
424 
425 	  if (!_dbus_string_find_to (&str, pos, end_pos, ",", &comma_pos))
426 	    comma_pos = end_pos;
427 
428 	  if (!_dbus_string_find_to (&str, pos, comma_pos, "=", &equals_pos) ||
429 	      equals_pos == pos || equals_pos + 1 == comma_pos)
430 	    {
431 	      dbus_set_error (error, DBUS_ERROR_BAD_ADDRESS,
432                               "'=' character not found or has no value following it");
433               goto error;
434 	    }
435 	  else
436 	    {
437 	      DBusString *key;
438 	      DBusString *value;
439 
440 	      key = dbus_new0 (DBusString, 1);
441 
442 	      if (!key)
443 		{
444 		  dbus_set_error (error, DBUS_ERROR_NO_MEMORY, NULL);
445 		  goto error;
446 		}
447 
448 	      value = dbus_new0 (DBusString, 1);
449 	      if (!value)
450 		{
451 		  dbus_set_error (error, DBUS_ERROR_NO_MEMORY, NULL);
452 		  dbus_free (key);
453 		  goto error;
454 		}
455 
456 	      if (!_dbus_string_init (key))
457 		{
458 		  dbus_set_error (error, DBUS_ERROR_NO_MEMORY, NULL);
459 		  dbus_free (key);
460 		  dbus_free (value);
461 
462 		  goto error;
463 		}
464 
465 	      if (!_dbus_string_init (value))
466 		{
467 		  dbus_set_error (error, DBUS_ERROR_NO_MEMORY, NULL);
468 		  _dbus_string_free (key);
469 
470 		  dbus_free (key);
471 		  dbus_free (value);
472 		  goto error;
473 		}
474 
475 	      if (!_dbus_string_copy_len (&str, pos, equals_pos - pos, key, 0))
476 		{
477 		  dbus_set_error (error, DBUS_ERROR_NO_MEMORY, NULL);
478 		  _dbus_string_free (key);
479 		  _dbus_string_free (value);
480 
481 		  dbus_free (key);
482 		  dbus_free (value);
483 		  goto error;
484 		}
485 
486 	      if (!append_unescaped_value (value, &str, equals_pos + 1,
487                                            comma_pos - equals_pos - 1, error))
488 		{
489                   _dbus_assert (error == NULL || dbus_error_is_set (error));
490 		  _dbus_string_free (key);
491 		  _dbus_string_free (value);
492 
493 		  dbus_free (key);
494 		  dbus_free (value);
495 		  goto error;
496 		}
497 
498 	      if (!_dbus_list_append (&entry->keys, key))
499 		{
500 		  dbus_set_error (error, DBUS_ERROR_NO_MEMORY, NULL);
501 		  _dbus_string_free (key);
502 		  _dbus_string_free (value);
503 
504 		  dbus_free (key);
505 		  dbus_free (value);
506 		  goto error;
507 		}
508 
509 	      if (!_dbus_list_append (&entry->values, value))
510 		{
511 		  dbus_set_error (error, DBUS_ERROR_NO_MEMORY, NULL);
512 		  _dbus_string_free (value);
513 
514 		  dbus_free (value);
515 		  goto error;
516 		}
517 	    }
518 
519 	  pos = comma_pos + 1;
520 	}
521 
522       pos = end_pos + 1;
523     }
524 
525   *array_len = _dbus_list_get_length (&entries);
526 
527   entry_array = dbus_new (DBusAddressEntry *, *array_len + 1);
528 
529   if (!entry_array)
530     {
531       dbus_set_error (error, DBUS_ERROR_NO_MEMORY, NULL);
532 
533       goto error;
534     }
535 
536   entry_array [*array_len] = NULL;
537 
538   link = _dbus_list_get_first_link (&entries);
539   i = 0;
540   while (link != NULL)
541     {
542       entry_array[i] = link->data;
543       i++;
544       link = _dbus_list_get_next_link (&entries, link);
545     }
546 
547   _dbus_list_clear (&entries);
548   *entry = entry_array;
549 
550   return TRUE;
551 
552  error:
553 
554   link = _dbus_list_get_first_link (&entries);
555   while (link != NULL)
556     {
557       dbus_address_entry_free (link->data);
558       link = _dbus_list_get_next_link (&entries, link);
559     }
560 
561   _dbus_list_clear (&entries);
562 
563   return FALSE;
564 
565 }
566 
567 /**
568  * Escapes the given string as a value in a key=value pair
569  * for a D-Bus address.
570  *
571  * @param value the unescaped value
572  * @returns newly-allocated escaped value or #NULL if no memory
573  */
574 char*
dbus_address_escape_value(const char * value)575 dbus_address_escape_value (const char *value)
576 {
577   DBusString escaped;
578   DBusString unescaped;
579   char *ret;
580 
581   ret = NULL;
582 
583   _dbus_string_init_const (&unescaped, value);
584 
585   if (!_dbus_string_init (&escaped))
586     return NULL;
587 
588   if (!_dbus_address_append_escaped (&escaped, &unescaped))
589     goto out;
590 
591   if (!_dbus_string_steal_data (&escaped, &ret))
592     goto out;
593 
594  out:
595   _dbus_string_free (&escaped);
596   return ret;
597 }
598 
599 /**
600  * Unescapes the given string as a value in a key=value pair
601  * for a D-Bus address. Note that dbus_address_entry_get_value()
602  * returns an already-unescaped value.
603  *
604  * @param value the escaped value
605  * @param error error to set if the unescaping fails
606  * @returns newly-allocated unescaped value or #NULL if no memory
607  */
608 char*
dbus_address_unescape_value(const char * value,DBusError * error)609 dbus_address_unescape_value (const char *value,
610                              DBusError  *error)
611 {
612   DBusString unescaped;
613   DBusString escaped;
614   char *ret;
615 
616   ret = NULL;
617 
618   _dbus_string_init_const (&escaped, value);
619 
620   if (!_dbus_string_init (&unescaped))
621     return NULL;
622 
623   if (!append_unescaped_value (&unescaped, &escaped,
624                                0, _dbus_string_get_length (&escaped),
625                                error))
626     goto out;
627 
628   if (!_dbus_string_steal_data (&unescaped, &ret))
629     goto out;
630 
631  out:
632   if (ret == NULL && error && !dbus_error_is_set (error))
633     _DBUS_SET_OOM (error);
634 
635   _dbus_assert (ret != NULL || error == NULL || dbus_error_is_set (error));
636 
637   _dbus_string_free (&unescaped);
638   return ret;
639 }
640 
641 /** @} */ /* End of public API */
642 
643 #ifdef DBUS_BUILD_TESTS
644 
645 #ifndef DOXYGEN_SHOULD_SKIP_THIS
646 
647 #include "dbus-test.h"
648 #include <stdlib.h>
649 
650 typedef struct
651 {
652   const char *escaped;
653   const char *unescaped;
654 } EscapeTest;
655 
656 static const EscapeTest escape_tests[] = {
657   { "abcde", "abcde" },
658   { "", "" },
659   { "%20%20", "  " },
660   { "%24", "$" },
661   { "%25", "%" },
662   { "abc%24", "abc$" },
663   { "%24abc", "$abc" },
664   { "abc%24abc", "abc$abc" },
665   { "/", "/" },
666   { "-", "-" },
667   { "_", "_" },
668   { "A", "A" },
669   { "I", "I" },
670   { "Z", "Z" },
671   { "a", "a" },
672   { "i", "i" },
673   { "z", "z" }
674 };
675 
676 static const char* invalid_escaped_values[] = {
677   "%a",
678   "%q",
679   "%az",
680   "%%",
681   "%$$",
682   "abc%a",
683   "%axyz",
684   "%",
685   "$",
686   " ",
687   "*"
688 };
689 
690 dbus_bool_t
_dbus_address_test(void)691 _dbus_address_test (void)
692 {
693   DBusAddressEntry **entries;
694   int len;
695   DBusError error;
696   int i;
697 
698   dbus_error_init (&error);
699 
700   i = 0;
701   while (i < _DBUS_N_ELEMENTS (escape_tests))
702     {
703       const EscapeTest *test = &escape_tests[i];
704       char *escaped;
705       char *unescaped;
706 
707       escaped = dbus_address_escape_value (test->unescaped);
708       if (escaped == NULL)
709         _dbus_assert_not_reached ("oom");
710 
711       if (strcmp (escaped, test->escaped) != 0)
712         {
713           _dbus_warn ("Escaped '%s' as '%s' should have been '%s'\n",
714                       test->unescaped, escaped, test->escaped);
715           exit (1);
716         }
717       dbus_free (escaped);
718 
719       unescaped = dbus_address_unescape_value (test->escaped, &error);
720       if (unescaped == NULL)
721         {
722           _dbus_warn ("Failed to unescape '%s': %s\n",
723                       test->escaped, error.message);
724           dbus_error_free (&error);
725           exit (1);
726         }
727 
728       if (strcmp (unescaped, test->unescaped) != 0)
729         {
730           _dbus_warn ("Unescaped '%s' as '%s' should have been '%s'\n",
731                       test->escaped, unescaped, test->unescaped);
732           exit (1);
733         }
734       dbus_free (unescaped);
735 
736       ++i;
737     }
738 
739   i = 0;
740   while (i < _DBUS_N_ELEMENTS (invalid_escaped_values))
741     {
742       char *unescaped;
743 
744       unescaped = dbus_address_unescape_value (invalid_escaped_values[i],
745                                                &error);
746       if (unescaped != NULL)
747         {
748           _dbus_warn ("Should not have successfully unescaped '%s' to '%s'\n",
749                       invalid_escaped_values[i], unescaped);
750           dbus_free (unescaped);
751           exit (1);
752         }
753 
754       _dbus_assert (dbus_error_is_set (&error));
755       dbus_error_free (&error);
756 
757       ++i;
758     }
759 
760   if (!dbus_parse_address ("unix:path=/tmp/foo;debug:name=test,sliff=sloff;",
761 			   &entries, &len, &error))
762     _dbus_assert_not_reached ("could not parse address");
763   _dbus_assert (len == 2);
764   _dbus_assert (strcmp (dbus_address_entry_get_value (entries[0], "path"), "/tmp/foo") == 0);
765   _dbus_assert (strcmp (dbus_address_entry_get_value (entries[1], "name"), "test") == 0);
766   _dbus_assert (strcmp (dbus_address_entry_get_value (entries[1], "sliff"), "sloff") == 0);
767 
768   dbus_address_entries_free (entries);
769 
770   /* Different possible errors */
771   if (dbus_parse_address ("foo", &entries, &len, &error))
772     _dbus_assert_not_reached ("Parsed incorrect address.");
773   else
774     dbus_error_free (&error);
775 
776   if (dbus_parse_address ("foo:bar", &entries, &len, &error))
777     _dbus_assert_not_reached ("Parsed incorrect address.");
778   else
779     dbus_error_free (&error);
780 
781   if (dbus_parse_address ("foo:bar,baz", &entries, &len, &error))
782     _dbus_assert_not_reached ("Parsed incorrect address.");
783   else
784     dbus_error_free (&error);
785 
786   if (dbus_parse_address ("foo:bar=foo,baz", &entries, &len, &error))
787     _dbus_assert_not_reached ("Parsed incorrect address.");
788   else
789     dbus_error_free (&error);
790 
791   if (dbus_parse_address ("foo:bar=foo;baz", &entries, &len, &error))
792     _dbus_assert_not_reached ("Parsed incorrect address.");
793   else
794     dbus_error_free (&error);
795 
796   if (dbus_parse_address ("foo:=foo", &entries, &len, &error))
797     _dbus_assert_not_reached ("Parsed incorrect address.");
798   else
799     dbus_error_free (&error);
800 
801   if (dbus_parse_address ("foo:foo=", &entries, &len, &error))
802     _dbus_assert_not_reached ("Parsed incorrect address.");
803   else
804     dbus_error_free (&error);
805 
806   if (dbus_parse_address ("foo:foo,bar=baz", &entries, &len, &error))
807     _dbus_assert_not_reached ("Parsed incorrect address.");
808   else
809     dbus_error_free (&error);
810 
811   return TRUE;
812 }
813 
814 #endif /* !DOXYGEN_SHOULD_SKIP_THIS */
815 
816 #endif
817