summaryrefslogtreecommitdiff
path: root/gdbus/gdbusaddress.c
diff options
context:
space:
mode:
Diffstat (limited to 'gdbus/gdbusaddress.c')
-rw-r--r--gdbus/gdbusaddress.c532
1 files changed, 465 insertions, 67 deletions
diff --git a/gdbus/gdbusaddress.c b/gdbus/gdbusaddress.c
index 0d0c2dc..3534562 100644
--- a/gdbus/gdbusaddress.c
+++ b/gdbus/gdbusaddress.c
@@ -26,9 +26,11 @@
#include <glib/gi18n.h>
+#include "gdbusutils.h"
#include "gdbusaddress.h"
#include "gdbuserror.h"
#include "gdbusenumtypes.h"
+#include "gdbusprivate.h"
#ifdef G_OS_UNIX
#include <gio/gunixsocketaddress.h>
@@ -45,6 +47,430 @@
/* ---------------------------------------------------------------------------------------------------- */
+/**
+ * g_dbus_is_address:
+ * @string: A string.
+ *
+ * Checks if @string is a D-Bus address.
+ *
+ * This doesn't check if @string is actually supported by #GDBusServer
+ * or #GDBusConnection - use g_dbus_is_supported_address() to do more
+ * checks.
+ *
+ * Returns: %TRUE if @string is a valid D-Bus address, %FALSE otherwise.
+ */
+gboolean
+g_dbus_is_address (const gchar *string)
+{
+ guint n;
+ gchar **a;
+ gboolean ret;
+
+ ret = FALSE;
+
+ g_return_val_if_fail (string != NULL, FALSE);
+
+ a = g_strsplit (string, ";", 0);
+ for (n = 0; a[n] != NULL; n++)
+ {
+ if (!_g_dbus_address_parse_entry (a[n],
+ NULL,
+ NULL,
+ NULL))
+ goto out;
+ }
+
+ ret = TRUE;
+
+ out:
+ g_strfreev (a);
+ return ret;
+}
+
+static gboolean
+is_valid_unix (const gchar *address_entry,
+ GHashTable *key_value_pairs,
+ GError **error)
+{
+ gboolean ret;
+ GList *keys;
+ GList *l;
+ const gchar *path;
+ const gchar *tmpdir;
+ const gchar *abstract;
+
+ ret = FALSE;
+ keys = NULL;
+ path = NULL;
+ tmpdir = NULL;
+ abstract = NULL;
+
+ keys = g_hash_table_get_keys (key_value_pairs);
+ for (l = keys; l != NULL; l = l->next)
+ {
+ const gchar *key = l->data;
+ if (g_strcmp0 (key, "path") == 0)
+ path = g_hash_table_lookup (key_value_pairs, key);
+ else if (g_strcmp0 (key, "tmpdir") == 0)
+ tmpdir = g_hash_table_lookup (key_value_pairs, key);
+ else if (g_strcmp0 (key, "abstract") == 0)
+ abstract = g_hash_table_lookup (key_value_pairs, key);
+ else
+ {
+ g_set_error (error,
+ G_IO_ERROR,
+ G_IO_ERROR_INVALID_ARGUMENT,
+ _("Unsupported key `%s' in address entry `%s'"),
+ key,
+ address_entry);
+ goto out;
+ }
+ }
+
+ if (path != NULL)
+ {
+ if (tmpdir != NULL || abstract != NULL)
+ goto meaningless;
+ /* TODO: validate path */
+ }
+ else if (tmpdir != NULL)
+ {
+ if (path != NULL || abstract != NULL)
+ goto meaningless;
+ /* TODO: validate tmpdir */
+ }
+ else if (abstract != NULL)
+ {
+ if (path != NULL || tmpdir != NULL)
+ goto meaningless;
+ /* TODO: validate abstract */
+ }
+ else
+ {
+ g_set_error (error,
+ G_IO_ERROR,
+ G_IO_ERROR_INVALID_ARGUMENT,
+ _("Address `%s' is invalid (need exactly one of path, tmpdir or abstract keys"),
+ address_entry);
+ goto out;
+ }
+
+
+ ret= TRUE;
+ goto out;
+
+ meaningless:
+ g_set_error (error,
+ G_IO_ERROR,
+ G_IO_ERROR_INVALID_ARGUMENT,
+ _("Meaningless key/value pair combination in address entry `%s'"),
+ address_entry);
+
+ out:
+ g_list_free (keys);
+
+ return ret;
+}
+
+static gboolean
+is_valid_nonce_tcp (const gchar *address_entry,
+ GHashTable *key_value_pairs,
+ GError **error)
+{
+ gboolean ret;
+ GList *keys;
+ GList *l;
+ const gchar *host;
+ const gchar *port;
+ const gchar *family;
+ const gchar *nonce_file;
+ gint port_num;
+ gchar *endp;
+
+ ret = FALSE;
+ keys = NULL;
+ host = NULL;
+ port = NULL;
+ family = NULL;
+ nonce_file = NULL;
+
+ keys = g_hash_table_get_keys (key_value_pairs);
+ for (l = keys; l != NULL; l = l->next)
+ {
+ const gchar *key = l->data;
+ if (g_strcmp0 (key, "host") == 0)
+ host = g_hash_table_lookup (key_value_pairs, key);
+ else if (g_strcmp0 (key, "port") == 0)
+ port = g_hash_table_lookup (key_value_pairs, key);
+ else if (g_strcmp0 (key, "family") == 0)
+ family = g_hash_table_lookup (key_value_pairs, key);
+ else if (g_strcmp0 (key, "noncefile") == 0)
+ nonce_file = g_hash_table_lookup (key_value_pairs, key);
+ else
+ {
+ g_set_error (error,
+ G_IO_ERROR,
+ G_IO_ERROR_INVALID_ARGUMENT,
+ _("Unsupported key `%s' in address entry `%s'"),
+ key,
+ address_entry);
+ goto out;
+ }
+ }
+
+ if (port != NULL)
+ {
+ port_num = strtol (port, &endp, 10);
+ if ((*port == '\0' || *endp != '\0') || port_num < 0 || port_num >= 65536)
+ {
+ g_set_error (error,
+ G_IO_ERROR,
+ G_IO_ERROR_INVALID_ARGUMENT,
+ _("Error in address `%s' - the port attribute is malformed"),
+ address_entry);
+ goto out;
+ }
+ }
+
+ if (family != NULL && !(g_strcmp0 (family, "ipv4") == 0 || g_strcmp0 (family, "ipv6") == 0))
+ {
+ g_set_error (error,
+ G_IO_ERROR,
+ G_IO_ERROR_INVALID_ARGUMENT,
+ _("Error in address `%s' - the family attribute is malformed"),
+ address_entry);
+ goto out;
+ }
+
+ ret= TRUE;
+
+ out:
+ g_list_free (keys);
+
+ return ret;
+}
+
+static gboolean
+is_valid_tcp (const gchar *address_entry,
+ GHashTable *key_value_pairs,
+ GError **error)
+{
+ gboolean ret;
+ GList *keys;
+ GList *l;
+ const gchar *host;
+ const gchar *port;
+ const gchar *family;
+ gint port_num;
+ gchar *endp;
+
+ ret = FALSE;
+ keys = NULL;
+ host = NULL;
+ port = NULL;
+ family = NULL;
+
+ keys = g_hash_table_get_keys (key_value_pairs);
+ for (l = keys; l != NULL; l = l->next)
+ {
+ const gchar *key = l->data;
+ if (g_strcmp0 (key, "host") == 0)
+ host = g_hash_table_lookup (key_value_pairs, key);
+ else if (g_strcmp0 (key, "port") == 0)
+ port = g_hash_table_lookup (key_value_pairs, key);
+ else if (g_strcmp0 (key, "family") == 0)
+ family = g_hash_table_lookup (key_value_pairs, key);
+ else
+ {
+ g_set_error (error,
+ G_IO_ERROR,
+ G_IO_ERROR_INVALID_ARGUMENT,
+ _("Unsupported key `%s' in address entry `%s'"),
+ key,
+ address_entry);
+ goto out;
+ }
+ }
+
+ if (port != NULL)
+ {
+ port_num = strtol (port, &endp, 10);
+ if ((*port == '\0' || *endp != '\0') || port_num < 0 || port_num >= 65536)
+ {
+ g_set_error (error,
+ G_IO_ERROR,
+ G_IO_ERROR_INVALID_ARGUMENT,
+ _("Error in address `%s' - the port attribute is malformed"),
+ address_entry);
+ goto out;
+ }
+ }
+
+ if (family != NULL && !(g_strcmp0 (family, "ipv4") == 0 || g_strcmp0 (family, "ipv6") == 0))
+ {
+ g_set_error (error,
+ G_IO_ERROR,
+ G_IO_ERROR_INVALID_ARGUMENT,
+ _("Error in address `%s' - the family attribute is malformed"),
+ address_entry);
+ goto out;
+ }
+
+ ret= TRUE;
+
+ out:
+ g_list_free (keys);
+
+ return ret;
+}
+
+/**
+ * g_dbus_is_supported_address:
+ * @string: A string.
+ * @error: Return location for error or %NULL.
+ *
+ * Like g_dbus_is_address() but also checks if the library suppors the
+ * transports in @string and that key/value pairs for each transport
+ * are valid.
+ *
+ * Returns: %TRUE if @string is a valid D-Bus address that is
+ * supported by this library, %FALSE if @error is set.
+ */
+gboolean
+g_dbus_is_supported_address (const gchar *string,
+ GError **error)
+{
+ guint n;
+ gchar **a;
+ gboolean ret;
+
+ ret = FALSE;
+
+ g_return_val_if_fail (string != NULL, FALSE);
+ g_return_val_if_fail (error == NULL || *error == NULL, FALSE);
+
+ a = g_strsplit (string, ";", 0);
+ for (n = 0; a[n] != NULL; n++)
+ {
+ gchar *transport_name;
+ GHashTable *key_value_pairs;
+ gboolean supported;
+
+ if (!_g_dbus_address_parse_entry (a[n],
+ &transport_name,
+ &key_value_pairs,
+ error))
+ goto out;
+
+ supported = FALSE;
+ if (g_strcmp0 (transport_name, "unix") == 0)
+ supported = is_valid_unix (a[n], key_value_pairs, error);
+ else if (g_strcmp0 (transport_name, "tcp") == 0)
+ supported = is_valid_tcp (a[n], key_value_pairs, error);
+ else if (g_strcmp0 (transport_name, "nonce-tcp") == 0)
+ supported = is_valid_nonce_tcp (a[n], key_value_pairs, error);
+
+ g_free (transport_name);
+ g_hash_table_unref (key_value_pairs);
+
+ if (!supported)
+ goto out;
+ }
+
+ ret = TRUE;
+
+ out:
+ g_strfreev (a);
+
+ g_assert (ret || (!ret && (error == NULL || *error != NULL)));
+
+ return ret;
+}
+
+gboolean
+_g_dbus_address_parse_entry (const gchar *address_entry,
+ gchar **out_transport_name,
+ GHashTable **out_key_value_pairs,
+ GError **error)
+{
+ gboolean ret;
+ GHashTable *key_value_pairs;
+ gchar *transport_name;
+ gchar **kv_pairs;
+ const gchar *s;
+ guint n;
+
+ ret = FALSE;
+ kv_pairs = NULL;
+ transport_name = NULL;
+ key_value_pairs = NULL;
+
+ s = strchr (address_entry, ':');
+ if (s == NULL)
+ {
+ g_set_error (error,
+ G_IO_ERROR,
+ G_IO_ERROR_INVALID_ARGUMENT,
+ _("Address element `%s', does not contain a colon (:)"),
+ address_entry);
+ goto out;
+ }
+
+ transport_name = g_strndup (address_entry, s - address_entry);
+ key_value_pairs = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, g_free);
+
+ kv_pairs = g_strsplit (s + 1, ",", 0);
+ for (n = 0; kv_pairs != NULL && kv_pairs[n] != NULL; n++)
+ {
+ const gchar *kv_pair = kv_pairs[n];
+ gchar *key;
+ gchar *value;
+
+ s = strchr (kv_pair, '=');
+ if (s == NULL)
+ {
+ g_set_error (error,
+ G_IO_ERROR,
+ G_IO_ERROR_INVALID_ARGUMENT,
+ _("Key/Value pair %d, `%s', in address element `%s', does not contain an equal sign"),
+ n,
+ kv_pair,
+ address_entry);
+ goto out;
+ }
+
+ /* TODO: actually validate that no illegal characters are present before and after then '=' sign */
+ key = g_uri_unescape_segment (kv_pair, s, NULL);
+ value = g_uri_unescape_segment (s + 1, kv_pair + strlen (kv_pair), NULL);
+ g_hash_table_insert (key_value_pairs, key, value);
+ }
+
+ ret = TRUE;
+
+out:
+ g_strfreev (kv_pairs);
+ if (ret)
+ {
+ if (out_transport_name != NULL)
+ *out_transport_name = transport_name;
+ else
+ g_free (transport_name);
+ if (out_key_value_pairs != NULL)
+ *out_key_value_pairs = key_value_pairs;
+ else if (key_value_pairs != NULL)
+ g_hash_table_unref (key_value_pairs);
+ }
+ else
+ {
+ g_free (transport_name);
+ if (key_value_pairs != NULL)
+ g_hash_table_unref (key_value_pairs);
+ }
+ return ret;
+}
+
+/* ---------------------------------------------------------------------------------------------------- */
+
/* TODO: Declare an extension point called GDBusTransport (or similar)
* and move code below to extensions implementing said extension
* point. That way we can implement a D-Bus transport over X11 without
@@ -100,12 +526,15 @@ g_dbus_address_connect (const gchar *address_entry,
}
}
#endif
- else if (g_strcmp0 (transport_name, "nonce-tcp") == 0)
+ else if (g_strcmp0 (transport_name, "tcp") == 0 || g_strcmp0 (transport_name, "nonce-tcp") == 0)
{
const gchar *s;
const gchar *host;
guint port;
gchar *endp;
+ gboolean is_nonce;
+
+ is_nonce = (g_strcmp0 (transport_name, "nonce-tcp") == 0);
host = g_hash_table_lookup (key_value_pairs, "host");
if (host == NULL)
@@ -122,7 +551,7 @@ g_dbus_address_connect (const gchar *address_entry,
if (s == NULL)
s = "0";
port = strtol (s, &endp, 10);
- if ((*s == '\0' || *endp != '\0') || port == 0 || port >= 65536)
+ if ((*s == '\0' || *endp != '\0') || port < 0 || port >= 65536)
{
g_set_error (error,
G_IO_ERROR,
@@ -132,18 +561,22 @@ g_dbus_address_connect (const gchar *address_entry,
goto out;
}
- nonce_file = g_hash_table_lookup (key_value_pairs, "noncefile");
- if (nonce_file == NULL)
+
+ if (is_nonce)
{
- g_set_error (error,
- G_IO_ERROR,
- G_IO_ERROR_INVALID_ARGUMENT,
- _("Error in address `%s' - the noncefile attribute is missing or malformed"),
- address_entry);
- goto out;
+ nonce_file = g_hash_table_lookup (key_value_pairs, "noncefile");
+ if (nonce_file == NULL)
+ {
+ g_set_error (error,
+ G_IO_ERROR,
+ G_IO_ERROR_INVALID_ARGUMENT,
+ _("Error in address `%s' - the noncefile attribute is missing or malformed"),
+ address_entry);
+ goto out;
+ }
}
- /* TODO: deal with family? */
+ /* TODO: deal with family */
connectable = g_network_address_new (host, port);
}
else
@@ -167,12 +600,12 @@ g_dbus_address_connect (const gchar *address_entry,
connectable,
cancellable,
error);
- if (connection != NULL)
- {
- ret = G_IO_STREAM (connection);
- }
g_object_unref (connectable);
g_object_unref (client);
+ if (connection == NULL)
+ goto out;
+
+ ret = G_IO_STREAM (connection);
if (nonce_file != NULL)
{
@@ -236,70 +669,35 @@ g_dbus_address_try_connect_one (const gchar *address_entry,
GIOStream *ret;
GHashTable *key_value_pairs;
gchar *transport_name;
- gchar **kv_pairs;
- const gchar *s;
- guint n;
+ const gchar *guid;
ret = NULL;
+ transport_name = NULL;
+ key_value_pairs = NULL;
- s = strchr (address_entry, ':');
- if (s == NULL)
- {
- g_set_error (error,
- G_IO_ERROR,
- G_IO_ERROR_INVALID_ARGUMENT,
- _("Address element `%s', does not contain a colon (:)"),
- address_entry);
- goto out;
- }
-
- transport_name = g_strndup (address_entry, s - address_entry);
- key_value_pairs = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, g_free);
-
- kv_pairs = g_strsplit (s + 1, ",", 0);
- for (n = 0; kv_pairs != NULL && kv_pairs[n] != NULL; n++)
- {
- const gchar *kv_pair = kv_pairs[n];
- gchar *key;
- gchar *value;
-
- s = strchr (kv_pair, '=');
- if (s == NULL)
- {
- g_set_error (error,
- G_IO_ERROR,
- G_IO_ERROR_INVALID_ARGUMENT,
- _("Key/Value pair %d, `%s', in address element `%s', does not contain an equal sign"),
- n,
- kv_pair,
- address_entry);
- goto out;
- }
-
- /* TODO: actually validate that no illegal characters are present before and after then '=' sign */
- key = g_uri_unescape_segment (kv_pair, s, NULL);
- value = g_uri_unescape_segment (s + 1, kv_pair + strlen (kv_pair), NULL);
- g_hash_table_insert (key_value_pairs, key, value);
- }
+ if (!_g_dbus_address_parse_entry (address_entry,
+ &transport_name,
+ &key_value_pairs,
+ error))
+ goto out;
ret = g_dbus_address_connect (address_entry,
transport_name,
key_value_pairs,
cancellable,
error);
- if (ret != NULL)
- {
- const gchar *guid;
- /* TODO: validate that guid is of correct format */
- guid = g_hash_table_lookup (key_value_pairs, "guid");
- if (guid != NULL && out_guid != NULL)
- *out_guid = g_strdup (guid);
- }
+ if (ret == NULL)
+ goto out;
+
+ /* TODO: validate that guid is of correct format */
+ guid = g_hash_table_lookup (key_value_pairs, "guid");
+ if (guid != NULL && out_guid != NULL)
+ *out_guid = g_strdup (guid);
out:
- g_strfreev (kv_pairs);
g_free (transport_name);
- g_hash_table_unref (key_value_pairs);
+ if (key_value_pairs != NULL)
+ g_hash_table_unref (key_value_pairs);
return ret;
}