[kdbus] Make SipHash function as a private utility function to kdbus
[platform/upstream/glib.git] / gio / gdbusaddress.c
index f8b2c72..d82a09a 100644 (file)
@@ -13,9 +13,7 @@
  * Lesser General Public License for more details.
  *
  * You should have received a copy of the GNU Lesser General
- * Public License along with this library; if not, write to the
- * Free Software Foundation, Inc., 59 Temple Place, Suite 330,
- * Boston, MA 02111-1307, USA.
+ * Public License along with this library; if not, see <http://www.gnu.org/licenses/>.
  *
  * Author: David Zeuthen <davidz@redhat.com>
  */
@@ -41,6 +39,7 @@
 #include "gdbusprivate.h"
 #include "giomodule-priv.h"
 #include "gdbusdaemon.h"
+#include "gkdbus.h"
 
 #ifdef G_OS_UNIX
 #include <gio/gunixsocketaddress.h>
@@ -62,7 +61,7 @@
  *
  * Routines for working with D-Bus addresses. A D-Bus address is a string
  * like "unix:tmpdir=/tmp/my-app-name". The exact format of addresses
- * is explained in detail in the <link linkend="http://dbus.freedesktop.org/doc/dbus-specification.html&num;addresses">D-Bus specification</link>.
+ * is explained in detail in the [D-Bus specification](http://dbus.freedesktop.org/doc/dbus-specification.html\#addresses).
  */
 
 static gchar *get_session_address_platform_specific (GError **error);
@@ -147,7 +146,7 @@ is_valid_unix (const gchar  *address_entry,
           g_set_error (error,
                        G_IO_ERROR,
                        G_IO_ERROR_INVALID_ARGUMENT,
-                       _("Unsupported key `%s' in address entry `%s'"),
+                       _("Unsupported key '%s' in address entry '%s'"),
                        key,
                        address_entry);
           goto out;
@@ -174,7 +173,7 @@ is_valid_unix (const gchar  *address_entry,
       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 '%s' is invalid (need exactly one of path, tmpdir or abstract keys)"),
                    address_entry);
       goto out;
     }
@@ -187,7 +186,7 @@ is_valid_unix (const gchar  *address_entry,
   g_set_error (error,
                G_IO_ERROR,
                G_IO_ERROR_INVALID_ARGUMENT,
-               _("Meaningless key/value pair combination in address entry `%s'"),
+               _("Meaningless key/value pair combination in address entry '%s'"),
                address_entry);
 
  out:
@@ -235,7 +234,7 @@ is_valid_nonce_tcp (const gchar  *address_entry,
           g_set_error (error,
                        G_IO_ERROR,
                        G_IO_ERROR_INVALID_ARGUMENT,
-                       _("Unsupported key `%s' in address entry `%s'"),
+                       _("Unsupported key '%s' in address entry '%s'"),
                        key,
                        address_entry);
           goto out;
@@ -250,7 +249,7 @@ is_valid_nonce_tcp (const gchar  *address_entry,
           g_set_error (error,
                        G_IO_ERROR,
                        G_IO_ERROR_INVALID_ARGUMENT,
-                       _("Error in address `%s' - the port attribute is malformed"),
+                       _("Error in address '%s' - the port attribute is malformed"),
                        address_entry);
           goto out;
         }
@@ -261,7 +260,7 @@ is_valid_nonce_tcp (const gchar  *address_entry,
       g_set_error (error,
                    G_IO_ERROR,
                    G_IO_ERROR_INVALID_ARGUMENT,
-                   _("Error in address `%s' - the family attribute is malformed"),
+                   _("Error in address '%s' - the family attribute is malformed"),
                    address_entry);
       goto out;
     }
@@ -316,7 +315,7 @@ is_valid_tcp (const gchar  *address_entry,
           g_set_error (error,
                        G_IO_ERROR,
                        G_IO_ERROR_INVALID_ARGUMENT,
-                       _("Unsupported key `%s' in address entry `%s'"),
+                       _("Unsupported key '%s' in address entry '%s'"),
                        key,
                        address_entry);
           goto out;
@@ -331,7 +330,7 @@ is_valid_tcp (const gchar  *address_entry,
           g_set_error (error,
                        G_IO_ERROR,
                        G_IO_ERROR_INVALID_ARGUMENT,
-                       _("Error in address `%s' - the port attribute is malformed"),
+                       _("Error in address '%s' - the port attribute is malformed"),
                        address_entry);
           goto out;
         }
@@ -342,7 +341,7 @@ is_valid_tcp (const gchar  *address_entry,
       g_set_error (error,
                    G_IO_ERROR,
                    G_IO_ERROR_INVALID_ARGUMENT,
-                   _("Error in address `%s' - the family attribute is malformed"),
+                   _("Error in address '%s' - the family attribute is malformed"),
                    address_entry);
       goto out;
     }
@@ -451,7 +450,7 @@ _g_dbus_address_parse_entry (const gchar  *address_entry,
       g_set_error (error,
                    G_IO_ERROR,
                    G_IO_ERROR_INVALID_ARGUMENT,
-                   _("Address element `%s' does not contain a colon (:)"),
+                   _("Address element '%s' does not contain a colon (:)"),
                    address_entry);
       goto out;
     }
@@ -472,7 +471,7 @@ _g_dbus_address_parse_entry (const gchar  *address_entry,
           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"),
+                       _("Key/Value pair %d, '%s', in address element '%s' does not contain an equal sign"),
                        n,
                        kv_pair,
                        address_entry);
@@ -486,7 +485,7 @@ _g_dbus_address_parse_entry (const gchar  *address_entry,
           g_set_error (error,
                        G_IO_ERROR,
                        G_IO_ERROR_INVALID_ARGUMENT,
-                       _("Error unescaping key or value in Key/Value pair %d, `%s', in address element `%s'"),
+                       _("Error unescaping key or value in Key/Value pair %d, '%s', in address element '%s'"),
                        n,
                        kv_pair,
                        address_entry);
@@ -523,8 +522,9 @@ out:
 
 /* ---------------------------------------------------------------------------------------------------- */
 
-static GIOStream *
+static GObject *
 g_dbus_address_try_connect_one (const gchar   *address_entry,
+                                gboolean       kdbus_okay,
                                 gchar        **out_guid,
                                 GCancellable  *cancellable,
                                 GError       **error);
@@ -534,14 +534,15 @@ g_dbus_address_try_connect_one (const gchar   *address_entry,
  * point. That way we can implement a D-Bus transport over X11 without
  * making libgio link to libX11...
  */
-static GIOStream *
+static GObject *
 g_dbus_address_connect (const gchar   *address_entry,
                         const gchar   *transport_name,
+                        gboolean       kdbus_okay,
                         GHashTable    *key_value_pairs,
                         GCancellable  *cancellable,
                         GError       **error)
 {
-  GIOStream *ret;
+  GObject *ret;
   GSocketConnectable *connectable;
   const gchar *nonce_file;
 
@@ -553,6 +554,29 @@ g_dbus_address_connect (const gchar   *address_entry,
     {
     }
 #ifdef G_OS_UNIX
+  else if (kdbus_okay && g_str_equal (transport_name, "kernel"))
+    {
+      GKDBusWorker *worker;
+      const gchar *path;
+
+      path = g_hash_table_lookup (key_value_pairs, "path");
+
+      if (path == NULL)
+        {
+          g_set_error (error, G_IO_ERROR, G_IO_ERROR_INVALID_ARGUMENT,
+                       _("Error in address '%s' - the kernel transport requires a path"),
+                       address_entry);
+        }
+      else
+        {
+          worker = g_kdbus_worker_new (path, error);
+
+          if (worker == NULL)
+            return NULL;
+
+          return G_OBJECT (worker);
+        }
+    }
   else if (g_strcmp0 (transport_name, "unix") == 0)
     {
       const gchar *path;
@@ -564,8 +588,8 @@ g_dbus_address_connect (const gchar   *address_entry,
           g_set_error (error,
                        G_IO_ERROR,
                        G_IO_ERROR_INVALID_ARGUMENT,
-                       _("Error in address `%s' - the unix transport requires exactly one of the "
-                         "keys `path' or `abstract' to be set"),
+                       _("Error in address '%s' - the unix transport requires exactly one of the "
+                         "keys 'path' or 'abstract' to be set"),
                        address_entry);
         }
       else if (path != NULL)
@@ -600,7 +624,7 @@ g_dbus_address_connect (const gchar   *address_entry,
           g_set_error (error,
                        G_IO_ERROR,
                        G_IO_ERROR_INVALID_ARGUMENT,
-                       _("Error in address `%s' - the host attribute is missing or malformed"),
+                       _("Error in address '%s' - the host attribute is missing or malformed"),
                        address_entry);
           goto out;
         }
@@ -614,7 +638,7 @@ g_dbus_address_connect (const gchar   *address_entry,
           g_set_error (error,
                        G_IO_ERROR,
                        G_IO_ERROR_INVALID_ARGUMENT,
-                       _("Error in address `%s' - the port attribute is missing or malformed"),
+                       _("Error in address '%s' - the port attribute is missing or malformed"),
                        address_entry);
           goto out;
         }
@@ -628,7 +652,7 @@ g_dbus_address_connect (const gchar   *address_entry,
               g_set_error (error,
                            G_IO_ERROR,
                            G_IO_ERROR_INVALID_ARGUMENT,
-                           _("Error in address `%s' - the noncefile attribute is missing or malformed"),
+                           _("Error in address '%s' - the noncefile attribute is missing or malformed"),
                            address_entry);
               goto out;
             }
@@ -643,7 +667,7 @@ g_dbus_address_connect (const gchar   *address_entry,
       autolaunch_address = get_session_address_platform_specific (error);
       if (autolaunch_address != NULL)
         {
-          ret = g_dbus_address_try_connect_one (autolaunch_address, NULL, cancellable, error);
+          ret = g_dbus_address_try_connect_one (autolaunch_address, kdbus_okay, NULL, cancellable, error);
           g_free (autolaunch_address);
           goto out;
         }
@@ -657,7 +681,7 @@ g_dbus_address_connect (const gchar   *address_entry,
       g_set_error (error,
                    G_IO_ERROR,
                    G_IO_ERROR_INVALID_ARGUMENT,
-                   _("Unknown or unsupported transport `%s' for address `%s'"),
+                   _("Unknown or unsupported transport '%s' for address '%s'"),
                    transport_name,
                    address_entry);
     }
@@ -678,7 +702,7 @@ g_dbus_address_connect (const gchar   *address_entry,
       if (connection == NULL)
         goto out;
 
-      ret = G_IO_STREAM (connection);
+      ret = G_OBJECT (connection);
 
       if (nonce_file != NULL)
         {
@@ -693,7 +717,7 @@ g_dbus_address_connect (const gchar   *address_entry,
               g_set_error (error,
                            G_IO_ERROR,
                            G_IO_ERROR_INVALID_ARGUMENT,
-                           _("Error opening nonce file `%s': %s"),
+                           _("Error opening nonce file '%s': %s"),
                            nonce_file,
                            g_strerror (errno));
               g_object_unref (ret);
@@ -711,7 +735,7 @@ g_dbus_address_connect (const gchar   *address_entry,
                   g_set_error (error,
                                G_IO_ERROR,
                                G_IO_ERROR_INVALID_ARGUMENT,
-                               _("Error reading from nonce file `%s': %s"),
+                               _("Error reading from nonce file '%s': %s"),
                                nonce_file,
                                g_strerror (errno));
                 }
@@ -720,7 +744,7 @@ g_dbus_address_connect (const gchar   *address_entry,
                   g_set_error (error,
                                G_IO_ERROR,
                                G_IO_ERROR_INVALID_ARGUMENT,
-                               _("Error reading from nonce file `%s', expected 16 bytes, got %d"),
+                               _("Error reading from nonce file '%s', expected 16 bytes, got %d"),
                                nonce_file,
                                (gint) num_bytes_read);
                 }
@@ -731,14 +755,14 @@ g_dbus_address_connect (const gchar   *address_entry,
             }
           fclose (f);
 
-          if (!g_output_stream_write_all (g_io_stream_get_output_stream (ret),
+          if (!g_output_stream_write_all (g_io_stream_get_output_stream (G_IO_STREAM (connection)),
                                           nonce_contents,
                                           16,
                                           NULL,
                                           cancellable,
                                           error))
             {
-              g_prefix_error (error, _("Error writing contents of nonce file `%s' to stream:"), nonce_file);
+              g_prefix_error (error, _("Error writing contents of nonce file '%s' to stream:"), nonce_file);
               g_object_unref (ret);
               ret = NULL;
               goto out;
@@ -751,13 +775,14 @@ g_dbus_address_connect (const gchar   *address_entry,
   return ret;
 }
 
-static GIOStream *
+static GObject *
 g_dbus_address_try_connect_one (const gchar   *address_entry,
+                                gboolean       kdbus_okay,
                                 gchar        **out_guid,
                                 GCancellable  *cancellable,
                                 GError       **error)
 {
-  GIOStream *ret;
+  GObject *ret;
   GHashTable *key_value_pairs;
   gchar *transport_name;
   const gchar *guid;
@@ -774,6 +799,7 @@ g_dbus_address_try_connect_one (const gchar   *address_entry,
 
   ret = g_dbus_address_connect (address_entry,
                                 transport_name,
+                                kdbus_okay,
                                 key_value_pairs,
                                 cancellable,
                                 error);
@@ -941,7 +967,25 @@ g_dbus_address_get_stream_sync (const gchar   *address,
                                 GCancellable  *cancellable,
                                 GError       **error)
 {
-  GIOStream *ret;
+  GObject *result;
+
+  result = g_dbus_address_get_stream_internal (address, FALSE, out_guid, cancellable, error);
+  g_assert (result == NULL || G_IS_IO_STREAM (result));
+
+  if (result)
+    return G_IO_STREAM (result);
+
+  return NULL;
+}
+
+GObject *
+g_dbus_address_get_stream_internal (const gchar   *address,
+                                    gboolean       kdbus_okay,
+                                    gchar        **out_guid,
+                                    GCancellable  *cancellable,
+                                    GError       **error)
+{
+  GObject *ret;
   gchar **addr_array;
   guint n;
   GError *last_error;
@@ -968,6 +1012,7 @@ g_dbus_address_get_stream_sync (const gchar   *address,
 
       this_error = NULL;
       ret = g_dbus_address_try_connect_one (addr,
+                                            kdbus_okay,
                                             out_guid,
                                             cancellable,
                                             &this_error);
@@ -1058,7 +1103,7 @@ get_session_address_dbus_launch (GError **error)
   if (G_UNLIKELY (_g_dbus_debug_address ()))
     {
       _g_dbus_debug_print_lock ();
-      g_print ("GDBus-debug:Address: Running `%s' to get bus address (possibly autolaunching)\n", command_line);
+      g_print ("GDBus-debug:Address: Running '%s' to get bus address (possibly autolaunching)\n", command_line);
       old_dbus_verbose = g_strdup (g_getenv ("DBUS_VERBOSE"));
       restore_dbus_verbose = TRUE;
       g_setenv ("DBUS_VERBOSE", "1", TRUE);
@@ -1076,7 +1121,7 @@ get_session_address_dbus_launch (GError **error)
 
   if (!g_spawn_check_exit_status (exit_status, error))
     {
-      g_prefix_error (error, _("Error spawning command line `%s': "), command_line);
+      g_prefix_error (error, _("Error spawning command line '%s': "), command_line);
       goto out;
     }
 
@@ -1272,7 +1317,7 @@ publish_session_bus (const char *address)
 }
 
 static void
-unpublish_session_bus ()
+unpublish_session_bus (void)
 {
   HANDLE init_mutex;
 
@@ -1322,6 +1367,8 @@ idle_timeout_cb (GDBusDaemon *daemon, gpointer user_data)
   g_main_loop_quit (loop);
 }
 
+__declspec(dllexport) void CALLBACK g_win32_run_session_bus (HWND hwnd, HINSTANCE hinst, char *cmdline, int nCmdShow);
+
 __declspec(dllexport) void CALLBACK
 g_win32_run_session_bus (HWND hwnd, HINSTANCE hinst, char *cmdline, int nCmdShow)
 {
@@ -1398,7 +1445,13 @@ get_session_address_dbus_launch (GError **error)
          wcscat (args, rundll_path);
          wcscat (args, L"\" ");
          wcscat (args, gio_path_short);
+#if defined(_WIN64) || defined(_M_X64) || defined(_M_AMD64)
+         wcscat (args, L",g_win32_run_session_bus");
+#elif defined (_MSC_VER)
+         wcscat (args, L",_g_win32_run_session_bus@16");
+#else
          wcscat (args, L",g_win32_run_session_bus@16");
+#endif
 
          res = CreateProcessW (rundll_path, args,
                                0, 0, FALSE,
@@ -1429,7 +1482,7 @@ get_session_address_platform_specific (GError **error)
 {
   gchar *ret;
 #if defined (G_OS_UNIX) || defined(G_OS_WIN32)
-  /* need to handle OS X in a different way since `dbus-launch --autolaunch' probably won't work there */
+  /* need to handle OS X in a different way since 'dbus-launch --autolaunch' probably won't work there */
   ret = get_session_address_dbus_launch (error);
 #else
   /* TODO: implement for OS X */
@@ -1446,15 +1499,16 @@ get_session_address_platform_specific (GError **error)
 
 /**
  * g_dbus_address_get_for_bus_sync:
- * @bus_type: A #GBusType.
- * @cancellable: (allow-none): A #GCancellable or %NULL.
- * @error: Return location for error or %NULL.
+ * @bus_type: a #GBusType
+ * @cancellable: (allow-none): a #GCancellable or %NULL
+ * @error: return location for error or %NULL
  *
  * Synchronously looks up the D-Bus address for the well-known message
  * bus instance specified by @bus_type. This may involve using various
  * platform specific mechanisms.
  *
- * Returns: A valid D-Bus address string for @bus_type or %NULL if @error is set.
+ * Returns: a valid D-Bus address string for @bus_type or %NULL if
+ *     @error is set
  *
  * Since: 2.26
  */
@@ -1464,6 +1518,8 @@ g_dbus_address_get_for_bus_sync (GBusType       bus_type,
                                  GError       **error)
 {
   gchar *ret;
+  const gchar *system_bus;
+  const gchar *session_bus;
   const gchar *starter_bus;
   GError *local_error;
 
@@ -1476,7 +1532,7 @@ g_dbus_address_get_for_bus_sync (GBusType       bus_type,
     {
       guint n;
       _g_dbus_debug_print_lock ();
-      g_print ("GDBus-debug:Address: In g_dbus_address_get_for_bus_sync() for bus type `%s'\n",
+      g_print ("GDBus-debug:Address: In g_dbus_address_get_for_bus_sync() for bus type '%s'\n",
                _g_dbus_enum_to_string (G_TYPE_BUS_TYPE, bus_type));
       for (n = 0; n < 3; n++)
         {
@@ -1492,7 +1548,7 @@ g_dbus_address_get_for_bus_sync (GBusType       bus_type,
           v = g_getenv (k);
           g_print ("GDBus-debug:Address: env var %s", k);
           if (v != NULL)
-            g_print ("=`%s'\n", v);
+            g_print ("='%s'\n", v);
           else
             g_print (" is not set\n");
         }
@@ -1517,6 +1573,23 @@ g_dbus_address_get_for_bus_sync (GBusType       bus_type,
         }
       break;
 
+    case G_BUS_TYPE_MACHINE:
+      system_bus = g_getenv ("DBUS_SYSTEM_BUS_ADDRESS");
+      if (system_bus == NULL)
+        ret = g_strdup ("kernel:path=/sys/fs/kdbus/0-system/bus;unix:path=/var/run/dbus/system_bus_socket");
+      else
+        ret = g_strdup_printf ("kernel:path=/sys/fs/kdbus/0-system/bus;%s", system_bus);
+      break;
+
+    case G_BUS_TYPE_USER:
+      session_bus = g_getenv ("DBUS_SESSION_BUS_ADDRESS");
+      if (session_bus == NULL)
+        ret = g_strdup_printf ("kernel:path=%s/kdbus;%s", g_get_user_runtime_dir (),
+                                   get_session_address_platform_specific (&local_error));
+      else
+        ret = g_strdup_printf ("kernel:path=%s/kdbus;%s", g_get_user_runtime_dir (), session_bus);
+      break;
+
     case G_BUS_TYPE_STARTER:
       starter_bus = g_getenv ("DBUS_STARTER_BUS_TYPE");
       if (g_strcmp0 (starter_bus, "session") == 0)
@@ -1537,7 +1610,7 @@ g_dbus_address_get_for_bus_sync (GBusType       bus_type,
                            G_IO_ERROR,
                            G_IO_ERROR_FAILED,
                            _("Cannot determine bus address from DBUS_STARTER_BUS_TYPE environment variable"
-                             " - unknown value `%s'"),
+                             " - unknown value '%s'"),
                            starter_bus);
             }
           else
@@ -1566,13 +1639,13 @@ g_dbus_address_get_for_bus_sync (GBusType       bus_type,
       _g_dbus_debug_print_lock ();
       if (ret != NULL)
         {
-          g_print ("GDBus-debug:Address: Returning address `%s' for bus type `%s'\n",
+          g_print ("GDBus-debug:Address: Returning address '%s' for bus type '%s'\n",
                    ret,
                    _g_dbus_enum_to_string (G_TYPE_BUS_TYPE, bus_type));
         }
       else
         {
-          g_print ("GDBus-debug:Address: Cannot look-up address bus type `%s': %s\n",
+          g_print ("GDBus-debug:Address: Cannot look-up address bus type '%s': %s\n",
                    _g_dbus_enum_to_string (G_TYPE_BUS_TYPE, bus_type),
                    local_error ? local_error->message : "");
         }
@@ -1584,3 +1657,50 @@ g_dbus_address_get_for_bus_sync (GBusType       bus_type,
 
   return ret;
 }
+
+/**
+ * g_dbus_address_escape_value:
+ * @string: an unescaped string to be included in a D-Bus address
+ *     as the value in a key-value pair
+ *
+ * Escape @string so it can appear in a D-Bus address as the value
+ * part of a key-value pair.
+ *
+ * For instance, if @string is "/run/bus-for-:0",
+ * this function would return "/run/bus-for-%3A0",
+ * which could be used in a D-Bus address like
+ * "unix:nonce-tcp:host=127.0.0.1,port=42,noncefile=/run/bus-for-%3A0".
+ *
+ * Returns: (transfer full): a copy of @string with all
+ *     non-optionally-escaped bytes escaped
+ *
+ * Since: 2.36
+ */
+gchar *
+g_dbus_address_escape_value (const gchar *string)
+{
+  GString *s;
+  gsize i;
+
+  g_return_val_if_fail (string != NULL, NULL);
+
+  /* There will often not be anything needing escaping at all. */
+  s = g_string_sized_new (strlen (string));
+
+  /* D-Bus address escaping is mostly the same as URI escaping... */
+  g_string_append_uri_escaped (s, string, "\\/", FALSE);
+
+  /* ... but '~' is an unreserved character in URIs, but a
+   * non-optionally-escaped character in D-Bus addresses. */
+  for (i = 0; i < s->len; i++)
+    {
+      if (G_UNLIKELY (s->str[i] == '~'))
+        {
+          s->str[i] = '%';
+          g_string_insert (s, i + 1, "7E");
+          i += 2;
+        }
+    }
+
+  return g_string_free (s, FALSE);
+}