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