D-Bus: dbus-address.c Source File

D-Bus 1.14.10

dbus-address.c
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-2007 Red Hat, Inc.
6 * Copyright (C) 2007 Ralf Habacker
7 * Copyright (C) 2013 Chengwei Yang / Intel
8 *
9 * Licensed under the Academic Free License version 2.1
10 *
11 * This program is free software; you can redistribute it and/or modify
12 * it under the terms of the GNU General Public License as published by
13 * the Free Software Foundation; either version 2 of the License, or
14 * (at your option) any later version.
15 *
16 * This program is distributed in the hope that it will be useful,
17 * but WITHOUT ANY WARRANTY; without even the implied warranty of
18 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19 * GNU General Public License for more details.
20 *
21 * You should have received a copy of the GNU General Public License
22 * along with this program; if not, write to the Free Software
23 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
24 *
25 */
26
27#include <config.h>
28#include "dbus-address.h"
29#include "dbus-internals.h"
30#include "dbus-list.h"
31#include "dbus-string.h"
32#include "dbus-protocol.h"
33#include <dbus/dbus-test-tap.h>
34
46 struct DBusAddressEntry
47{
48 DBusString method;
50 DBusList *keys;
51 DBusList *values;
52};
53
54
67void
68_dbus_set_bad_address (DBusError *error,
69 const char *address_problem_type,
70 const char *address_problem_field,
71 const char *address_problem_other)
72{
73 if (address_problem_type != NULL)
74 dbus_set_error (error, DBUS_ERROR_BAD_ADDRESS,
75 "Server address of type %s was missing argument %s",
76 address_problem_type, address_problem_field);
77 else
78 dbus_set_error (error, DBUS_ERROR_BAD_ADDRESS,
79 "Could not parse server address: %s",
80 address_problem_other);
81}
82
87#define _DBUS_ADDRESS_OPTIONALLY_ESCAPED_BYTE(b) \
88 (((b) >= 'a' && (b) <= 'z') || \
89 ((b) >= 'A' && (b) <= 'Z') || \
90 ((b) >= '0' && (b) <= '9') || \
91 (b) == '-' || \
92 (b) == '_' || \
93 (b) == '/' || \
94 (b) == '\\' || \
95 (b) == '*' || \
96 (b) == '.')
97
106dbus_bool_t
107_dbus_address_append_escaped (DBusString *escaped,
108 const DBusString *unescaped)
109{
110 const unsigned char *p;
111 const unsigned char *end;
112 dbus_bool_t ret;
113 int orig_len;
114
115 ret = FALSE;
116
117 orig_len = _dbus_string_get_length (escaped);
118 p = _dbus_string_get_const_udata (unescaped);
119 end = p + _dbus_string_get_length (unescaped);
120 while (p != end)
121 {
122 if (_DBUS_ADDRESS_OPTIONALLY_ESCAPED_BYTE (*p))
123 {
124 if (!_dbus_string_append_byte (escaped, *p))
125 goto out;
126 }
127 else
128 {
129 if (!_dbus_string_append_byte (escaped, '%'))
130 goto out;
131 if (!_dbus_string_append_byte_as_hex (escaped, *p))
132 goto out;
133 }
134
135 ++p;
136 }
137
138 ret = TRUE;
139
140 out:
141 if (!ret)
142 _dbus_string_set_length (escaped, orig_len);
143 return ret;
144}
145 /* End of internals */
147
148static void
149dbus_address_entry_free (DBusAddressEntry *entry)
150{
151 DBusList *link;
152
153 _dbus_string_free (&entry->method);
154
155 link = _dbus_list_get_first_link (&entry->keys);
156 while (link != NULL)
157 {
158 _dbus_string_free (link->data);
159 dbus_free (link->data);
160
161 link = _dbus_list_get_next_link (&entry->keys, link);
162 }
163 _dbus_list_clear (&entry->keys);
164
165 link = _dbus_list_get_first_link (&entry->values);
166 while (link != NULL)
167 {
168 _dbus_string_free (link->data);
169 dbus_free (link->data);
170
171 link = _dbus_list_get_next_link (&entry->values, link);
172 }
173 _dbus_list_clear (&entry->values);
174
175 dbus_free (entry);
176}
177
191void
192dbus_address_entries_free (DBusAddressEntry **entries)
193{
194 int i;
195
196 for (i = 0; entries[i] != NULL; i++)
197 dbus_address_entry_free (entries[i]);
198 dbus_free (entries);
199}
200
201static DBusAddressEntry *
202create_entry (void)
203{
204 DBusAddressEntry *entry;
205
206 entry = dbus_new0 (DBusAddressEntry, 1);
207
208 if (entry == NULL)
209 return NULL;
210
211 if (!_dbus_string_init (&entry->method))
212 {
213 dbus_free (entry);
214 return NULL;
215 }
216
217 return entry;
218}
219
229const char *
230dbus_address_entry_get_method (DBusAddressEntry *entry)
231{
232 return _dbus_string_get_const_data (&entry->method);
233}
234
246const char *
247dbus_address_entry_get_value (DBusAddressEntry *entry,
248 const char *key)
249{
250 DBusList *values, *keys;
251
252 keys = _dbus_list_get_first_link (&entry->keys);
253 values = _dbus_list_get_first_link (&entry->values);
254
255 while (keys != NULL)
256 {
257 _dbus_assert (values != NULL);
258
259 if (_dbus_string_equal_c_str (keys->data, key))
260 return _dbus_string_get_const_data (values->data);
261
262 keys = _dbus_list_get_next_link (&entry->keys, keys);
263 values = _dbus_list_get_next_link (&entry->values, values);
264 }
265
266 return NULL;
267}
268
269static dbus_bool_t
270append_unescaped_value (DBusString *unescaped,
271 const DBusString *escaped,
272 int escaped_start,
273 int escaped_len,
274 DBusError *error)
275{
276 const char *p;
277 const char *end;
278 dbus_bool_t ret;
279
280 ret = FALSE;
281
282 p = _dbus_string_get_const_data (escaped) + escaped_start;
283 end = p + escaped_len;
284 while (p != end)
285 {
286 if (_DBUS_ADDRESS_OPTIONALLY_ESCAPED_BYTE (*p))
287 {
288 if (!_dbus_string_append_byte (unescaped, *p))
289 goto out;
290 }
291 else if (*p == '%')
292 {
293 /* Efficiency is king */
294 char buf[3];
295 DBusString hex;
296 int hex_end;
297
298 ++p;
299
300 if ((p + 2) > end)
301 {
302 dbus_set_error (error, DBUS_ERROR_BAD_ADDRESS,
303 "In D-Bus address, percent character was not followed by two hex digits");
304 goto out;
305 }
306
307 buf[0] = *p;
308 ++p;
309 buf[1] = *p;
310 buf[2] = '\0';
311
312 _dbus_string_init_const (&hex, buf);
313
314 if (!_dbus_string_hex_decode (&hex, 0, &hex_end,
315 unescaped,
316 _dbus_string_get_length (unescaped)))
317 goto out;
318
319 if (hex_end != 2)
320 {
321 dbus_set_error (error, DBUS_ERROR_BAD_ADDRESS,
322 "In D-Bus address, percent character was followed by characters other than hex digits");
323 goto out;
324 }
325 }
326 else
327 {
328 /* Error, should have been escaped */
329 dbus_set_error (error, DBUS_ERROR_BAD_ADDRESS,
330 "In D-Bus address, character '%c' should have been escaped\n",
331 *p);
332 goto out;
333 }
334
335 ++p;
336 }
337
338 ret = TRUE;
339
340 out:
341 if (!ret && error && !dbus_error_is_set (error))
342 _DBUS_SET_OOM (error);
343
344 _dbus_assert (ret || error == NULL || dbus_error_is_set (error));
345
346 return ret;
347}
348
365dbus_bool_t
366dbus_parse_address (const char *address,
367 DBusAddressEntry ***entry_result,
368 int *array_len,
369 DBusError *error)
370{
371 DBusString str;
372 int pos, end_pos, len, i;
373 DBusList *entries, *link;
374 DBusAddressEntry **entry_array;
375
376 _DBUS_ASSERT_ERROR_IS_CLEAR (error);
377
378 _dbus_string_init_const (&str, address);
379
380 entries = NULL;
381 pos = 0;
382 len = _dbus_string_get_length (&str);
383
384 if (len == 0)
385 {
386 dbus_set_error (error, DBUS_ERROR_BAD_ADDRESS,
387 "Empty address '%s'", address);
388 goto error;
389 }
390
391 while (pos < len)
392 {
393 DBusAddressEntry *entry;
394
395 int found_pos;
396
397 entry = create_entry ();
398 if (!entry)
399 {
400 dbus_set_error (error, DBUS_ERROR_NO_MEMORY, NULL);
401
402 goto error;
403 }
404
405 /* Append the entry */
406 if (!_dbus_list_append (&entries, entry))
407 {
408 dbus_set_error (error, DBUS_ERROR_NO_MEMORY, NULL);
409 dbus_address_entry_free (entry);
410 goto error;
411 }
412
413 /* Look for a semi-colon */
414 if (!_dbus_string_find (&str, pos, ";", &end_pos))
415 end_pos = len;
416
417 /* Look for the colon : */
418 if (!_dbus_string_find_to (&str, pos, end_pos, ":", &found_pos))
419 {
420 dbus_set_error (error, DBUS_ERROR_BAD_ADDRESS, "Address does not contain a colon");
421 goto error;
422 }
423
424 if (!_dbus_string_copy_len (&str, pos, found_pos - pos, &entry->method, 0))
425 {
426 dbus_set_error (error, DBUS_ERROR_NO_MEMORY, NULL);
427 goto error;
428 }
429
430 pos = found_pos + 1;
431
432 while (pos < end_pos)
433 {
434 int comma_pos, equals_pos;
435
436 if (!_dbus_string_find_to (&str, pos, end_pos, ",", &comma_pos))
437 comma_pos = end_pos;
438
439 if (!_dbus_string_find_to (&str, pos, comma_pos, "=", &equals_pos) ||
440 equals_pos == pos || equals_pos + 1 == comma_pos)
441 {
442 dbus_set_error (error, DBUS_ERROR_BAD_ADDRESS,
443 "'=' character not found or has no value following it");
444 goto error;
445 }
446 else
447 {
448 DBusString *key;
449 DBusString *value;
450
451 key = dbus_new0 (DBusString, 1);
452
453 if (!key)
454 {
455 dbus_set_error (error, DBUS_ERROR_NO_MEMORY, NULL);
456 goto error;
457 }
458
459 value = dbus_new0 (DBusString, 1);
460 if (!value)
461 {
462 dbus_set_error (error, DBUS_ERROR_NO_MEMORY, NULL);
463 dbus_free (key);
464 goto error;
465 }
466
467 if (!_dbus_string_init (key))
468 {
469 dbus_set_error (error, DBUS_ERROR_NO_MEMORY, NULL);
470 dbus_free (key);
471 dbus_free (value);
472
473 goto error;
474 }
475
476 if (!_dbus_string_init (value))
477 {
478 dbus_set_error (error, DBUS_ERROR_NO_MEMORY, NULL);
479 _dbus_string_free (key);
480
481 dbus_free (key);
482 dbus_free (value);
483 goto error;
484 }
485
486 if (!_dbus_string_copy_len (&str, pos, equals_pos - pos, key, 0))
487 {
488 dbus_set_error (error, DBUS_ERROR_NO_MEMORY, NULL);
489 _dbus_string_free (key);
490 _dbus_string_free (value);
491
492 dbus_free (key);
493 dbus_free (value);
494 goto error;
495 }
496
497 if (!append_unescaped_value (value, &str, equals_pos + 1,
498 comma_pos - equals_pos - 1, error))
499 {
500 _dbus_assert (error == NULL || dbus_error_is_set (error));
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->keys, key))
510 {
511 dbus_set_error (error, DBUS_ERROR_NO_MEMORY, NULL);
512 _dbus_string_free (key);
513 _dbus_string_free (value);
514
515 dbus_free (key);
516 dbus_free (value);
517 goto error;
518 }
519
520 if (!_dbus_list_append (&entry->values, value))
521 {
522 dbus_set_error (error, DBUS_ERROR_NO_MEMORY, NULL);
523 _dbus_string_free (value);
524
525 dbus_free (value);
526 goto error;
527 }
528 }
529
530 pos = comma_pos + 1;
531 }
532
533 pos = end_pos + 1;
534 }
535
536 *array_len = _dbus_list_get_length (&entries);
537
538 entry_array = dbus_new (DBusAddressEntry *, *array_len + 1);
539
540 if (!entry_array)
541 {
542 dbus_set_error (error, DBUS_ERROR_NO_MEMORY, NULL);
543
544 goto error;
545 }
546
547 entry_array [*array_len] = NULL;
548
549 link = _dbus_list_get_first_link (&entries);
550 i = 0;
551 while (link != NULL)
552 {
553 entry_array[i] = link->data;
554 i++;
555 link = _dbus_list_get_next_link (&entries, link);
556 }
557
558 _dbus_list_clear (&entries);
559 *entry_result = entry_array;
560
561 return TRUE;
562
563 error:
564
565 link = _dbus_list_get_first_link (&entries);
566 while (link != NULL)
567 {
568 dbus_address_entry_free (link->data);
569 link = _dbus_list_get_next_link (&entries, link);
570 }
571
572 _dbus_list_clear (&entries);
573
574 return FALSE;
575
576}
577
585char*
586dbus_address_escape_value (const char *value)
587{
588 DBusString escaped;
589 DBusString unescaped;
590 char *ret;
591
592 ret = NULL;
593
594 _dbus_string_init_const (&unescaped, value);
595
596 if (!_dbus_string_init (&escaped))
597 return NULL;
598
599 if (!_dbus_address_append_escaped (&escaped, &unescaped))
600 goto out;
601
602 if (!_dbus_string_steal_data (&escaped, &ret))
603 goto out;
604
605 out:
606 _dbus_string_free (&escaped);
607 return ret;
608}
609
619char*
620dbus_address_unescape_value (const char *value,
621 DBusError *error)
622{
623 DBusString unescaped;
624 DBusString escaped;
625 char *ret;
626
627 ret = NULL;
628
629 _dbus_string_init_const (&escaped, value);
630
631 if (!_dbus_string_init (&unescaped))
632 return NULL;
633
634 if (!append_unescaped_value (&unescaped, &escaped,
635 0, _dbus_string_get_length (&escaped),
636 error))
637 goto out;
638
639 if (!_dbus_string_steal_data (&unescaped, &ret))
640 goto out;
641
642 out:
643 if (ret == NULL && error && !dbus_error_is_set (error))
644 _DBUS_SET_OOM (error);
645
646 _dbus_assert (ret != NULL || error == NULL || dbus_error_is_set (error));
647
648 _dbus_string_free (&unescaped);
649 return ret;
650}
651 /* End of public API */
_DBUS_ADDRESS_OPTIONALLY_ESCAPED_BYTE
#define _DBUS_ADDRESS_OPTIONALLY_ESCAPED_BYTE(b)
TRUE if the byte need not be escaped when found in a dbus address.
Definition dbus-address.c:87
_dbus_address_append_escaped
dbus_bool_t _dbus_address_append_escaped(DBusString *escaped, const DBusString *unescaped)
Appends an escaped version of one string to another string, using the D-Bus address escaping mechanis...
Definition dbus-address.c:107
_dbus_set_bad_address
void _dbus_set_bad_address(DBusError *error, const char *address_problem_type, const char *address_problem_field, const char *address_problem_other)
Sets DBUS_ERROR_BAD_ADDRESS.
Definition dbus-address.c:68
dbus_address_entries_free
void dbus_address_entries_free(DBusAddressEntry **entries)
Frees a NULL-terminated array of address entries.
Definition dbus-address.c:192
dbus_parse_address
dbus_bool_t dbus_parse_address(const char *address, DBusAddressEntry ***entry_result, int *array_len, DBusError *error)
Parses an address string of the form:
Definition dbus-address.c:366
dbus_address_entry_get_method
const char * dbus_address_entry_get_method(DBusAddressEntry *entry)
Returns the method string of an address entry.
Definition dbus-address.c:230
dbus_address_unescape_value
char * dbus_address_unescape_value(const char *value, DBusError *error)
Unescapes the given string as a value in a key=value pair for a D-Bus address.
Definition dbus-address.c:620
dbus_address_escape_value
char * dbus_address_escape_value(const char *value)
Escapes the given string as a value in a key=value pair for a D-Bus address.
Definition dbus-address.c:586
dbus_address_entry_get_value
const char * dbus_address_entry_get_value(DBusAddressEntry *entry, const char *key)
Returns a value from a key of an entry.
Definition dbus-address.c:247
dbus_set_error
void dbus_set_error(DBusError *error, const char *name, const char *format,...)
Assigns an error name and message to a DBusError.
Definition dbus-errors.c:354
dbus_error_is_set
dbus_bool_t dbus_error_is_set(const DBusError *error)
Checks whether an error occurred (the error is set).
Definition dbus-errors.c:329
_dbus_assert
#define _dbus_assert(condition)
Aborts with an error message if the condition is false.
Definition dbus-internals.h:153
_dbus_list_get_first_link
DBusList * _dbus_list_get_first_link(DBusList **list)
Gets the first link in the list.
Definition dbus-list.c:595
_dbus_list_get_length
int _dbus_list_get_length(DBusList **list)
Gets the length of a list.
Definition dbus-list.c:758
_dbus_list_clear
void _dbus_list_clear(DBusList **list)
Frees all links in the list and sets the list head to NULL.
Definition dbus-list.c:543
_dbus_list_append
dbus_bool_t _dbus_list_append(DBusList **list, void *data)
Appends a value to the list.
Definition dbus-list.c:271
_dbus_list_get_next_link
#define _dbus_list_get_next_link(list, link)
Gets the next link in the list, or NULL if there are no more links.
Definition dbus-list.h:119
NULL
#define NULL
A null pointer, defined appropriately for C or C++.
Definition dbus-macros.h:49
TRUE
#define TRUE
Expands to "1".
Definition dbus-macros.h:39
FALSE
#define FALSE
Expands to "0".
Definition dbus-macros.h:42
dbus_free
void dbus_free(void *memory)
Frees a block of memory previously allocated by dbus_malloc() or dbus_malloc0().
Definition dbus-memory.c:692
dbus_new
#define dbus_new(type, count)
Safe macro for using dbus_malloc().
Definition dbus-memory.h:57
dbus_new0
#define dbus_new0(type, count)
Safe macro for using dbus_malloc0().
Definition dbus-memory.h:58
DBUS_ERROR_BAD_ADDRESS
#define DBUS_ERROR_BAD_ADDRESS
A D-Bus bus address was malformed.
Definition dbus-protocol.h:371
DBUS_ERROR_NO_MEMORY
#define DBUS_ERROR_NO_MEMORY
There was not enough memory to complete an operation.
Definition dbus-protocol.h:361
_dbus_string_set_length
dbus_bool_t _dbus_string_set_length(DBusString *str, int length)
Sets the length of a string.
Definition dbus-string.c:833
_dbus_string_hex_decode
dbus_bool_t _dbus_string_hex_decode(const DBusString *source, int start, int *end_return, DBusString *dest, int insert_at)
Decodes a string from hex encoding.
Definition dbus-string.c:2395
_dbus_string_init
dbus_bool_t _dbus_string_init(DBusString *str)
Initializes a string.
Definition dbus-string.c:182
_dbus_string_init_const
void _dbus_string_init_const(DBusString *str, const char *value)
Initializes a constant string.
Definition dbus-string.c:197
_dbus_string_steal_data
dbus_bool_t _dbus_string_steal_data(DBusString *str, char **data_return)
Like _dbus_string_get_data(), but removes the gotten data from the original string.
Definition dbus-string.c:672
_dbus_string_find
dbus_bool_t _dbus_string_find(const DBusString *str, int start, const char *substr, int *found)
Finds the given substring in the string, returning TRUE and filling in the byte index where the subst...
Definition dbus-string.c:1664
_dbus_string_free
void _dbus_string_free(DBusString *str)
Frees a string created by _dbus_string_init(), and fills it with the same contents as _DBUS_STRING_IN...
Definition dbus-string.c:278
_dbus_string_equal_c_str
dbus_bool_t _dbus_string_equal_c_str(const DBusString *a, const char *c_str)
Checks whether a string is equal to a C string.
Definition dbus-string.c:2212
_dbus_string_append_byte
dbus_bool_t _dbus_string_append_byte(DBusString *str, unsigned char byte)
Appends a single byte to the string, returning FALSE if not enough memory.
Definition dbus-string.c:1188
_dbus_string_append_byte_as_hex
dbus_bool_t _dbus_string_append_byte_as_hex(DBusString *str, unsigned char byte)
Appends a two-character hex digit to a string, where the hex digit has the value of the given byte.
Definition dbus-string.c:2311
_dbus_string_find_to
dbus_bool_t _dbus_string_find_to(const DBusString *str, int start, int end, const char *substr, int *found)
Finds the given substring in the string, up to a certain position, returning TRUE and filling in the ...
Definition dbus-string.c:1757
_dbus_string_copy_len
dbus_bool_t _dbus_string_copy_len(const DBusString *source, int start, int len, DBusString *dest, int insert_at)
Like _dbus_string_copy(), but can copy a segment from the middle of the source string.
Definition dbus-string.c:1435
DBusAddressEntry
Internals of DBusAddressEntry.
Definition dbus-address.c:47
DBusAddressEntry::method
DBusString method
The address type (unix, tcp, etc.)
Definition dbus-address.c:48
DBusAddressEntry::values
DBusList * values
List of values.
Definition dbus-address.c:51
DBusAddressEntry::keys
DBusList * keys
List of keys.
Definition dbus-address.c:50
DBusError
Object representing an exception.
Definition dbus-errors.h:49
DBusList
A node in a linked list.
Definition dbus-list.h:35
DBusList::data
void * data
Data stored at this element.
Definition dbus-list.h:38
DBusString
Definition dbus-string.h:43