1 /* GDBus - GLib D-Bus Library
3 * Copyright (C) 2008-2010 Red Hat, Inc.
5 * This library is free software; you can redistribute it and/or
6 * modify it under the terms of the GNU Lesser General Public
7 * License as published by the Free Software Foundation; either
8 * version 2.1 of the License, or (at your option) any later version.
10 * This library is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 * Lesser General Public License for more details.
15 * You should have received a copy of the GNU Lesser General
16 * Public License along with this library; if not, see <http://www.gnu.org/licenses/>.
18 * Author: David Zeuthen <davidz@redhat.com>
29 #include "gdbusutils.h"
30 #include "gdbusaddress.h"
31 #include "gdbuserror.h"
32 #include "gioenumtypes.h"
33 #include "gnetworkaddress.h"
34 #include "gsocketclient.h"
35 #include "giostream.h"
36 #include "gasyncresult.h"
38 #include "glib-private.h"
39 #include "gdbusprivate.h"
40 #include "giomodule-priv.h"
41 #include "gdbusdaemon.h"
47 #include <sys/types.h>
48 #include <gio/gunixsocketaddress.h>
60 * SECTION:gdbusaddress
61 * @title: D-Bus Addresses
62 * @short_description: D-Bus connection endpoints
65 * Routines for working with D-Bus addresses. A D-Bus address is a string
66 * like `unix:tmpdir=/tmp/my-app-name`. The exact format of addresses
67 * is explained in detail in the
68 * [D-Bus specification](http://dbus.freedesktop.org/doc/dbus-specification.html#addresses).
70 * TCP D-Bus connections are supported, but accessing them via a proxy is
71 * currently not supported.
74 static gchar
*get_session_address_platform_specific (GError
**error
);
75 static gchar
*get_session_address_dbus_launch (GError
**error
);
77 /* ---------------------------------------------------------------------------------------------------- */
83 * Checks if @string is a
84 * [D-Bus address](https://dbus.freedesktop.org/doc/dbus-specification.html#addresses).
86 * This doesn't check if @string is actually supported by #GDBusServer
87 * or #GDBusConnection - use g_dbus_is_supported_address() to do more
90 * Returns: %TRUE if @string is a valid D-Bus address, %FALSE otherwise.
95 g_dbus_is_address (const gchar
*string
)
103 g_return_val_if_fail (string
!= NULL
, FALSE
);
105 a
= g_strsplit (string
, ";", 0);
109 for (n
= 0; a
[n
] != NULL
; n
++)
111 if (!_g_dbus_address_parse_entry (a
[n
],
126 is_valid_unix (const gchar
*address_entry
,
127 GHashTable
*key_value_pairs
,
135 const gchar
*abstract
;
143 keys
= g_hash_table_get_keys (key_value_pairs
);
144 for (l
= keys
; l
!= NULL
; l
= l
->next
)
146 const gchar
*key
= l
->data
;
147 if (g_strcmp0 (key
, "path") == 0)
148 path
= g_hash_table_lookup (key_value_pairs
, key
);
149 else if (g_strcmp0 (key
, "tmpdir") == 0)
150 tmpdir
= g_hash_table_lookup (key_value_pairs
, key
);
151 else if (g_strcmp0 (key
, "abstract") == 0)
152 abstract
= g_hash_table_lookup (key_value_pairs
, key
);
157 G_IO_ERROR_INVALID_ARGUMENT
,
158 _("Unsupported key “%s” in address entry “%s”"),
167 if (tmpdir
!= NULL
|| abstract
!= NULL
)
170 else if (tmpdir
!= NULL
)
172 if (path
!= NULL
|| abstract
!= NULL
)
175 else if (abstract
!= NULL
)
177 if (path
!= NULL
|| tmpdir
!= NULL
)
184 G_IO_ERROR_INVALID_ARGUMENT
,
185 _("Address “%s” is invalid (need exactly one of path, tmpdir or abstract keys)"),
197 G_IO_ERROR_INVALID_ARGUMENT
,
198 _("Meaningless key/value pair combination in address entry “%s”"),
208 is_valid_nonce_tcp (const gchar
*address_entry
,
209 GHashTable
*key_value_pairs
,
218 const gchar
*nonce_file
;
229 keys
= g_hash_table_get_keys (key_value_pairs
);
230 for (l
= keys
; l
!= NULL
; l
= l
->next
)
232 const gchar
*key
= l
->data
;
233 if (g_strcmp0 (key
, "host") == 0)
234 host
= g_hash_table_lookup (key_value_pairs
, key
);
235 else if (g_strcmp0 (key
, "port") == 0)
236 port
= g_hash_table_lookup (key_value_pairs
, key
);
237 else if (g_strcmp0 (key
, "family") == 0)
238 family
= g_hash_table_lookup (key_value_pairs
, key
);
239 else if (g_strcmp0 (key
, "noncefile") == 0)
240 nonce_file
= g_hash_table_lookup (key_value_pairs
, key
);
245 G_IO_ERROR_INVALID_ARGUMENT
,
246 _("Unsupported key “%s” in address entry “%s”"),
255 port_num
= strtol (port
, &endp
, 10);
256 if ((*port
== '\0' || *endp
!= '\0') || port_num
< 0 || port_num
>= 65536)
260 G_IO_ERROR_INVALID_ARGUMENT
,
261 _("Error in address “%s” — the port attribute is malformed"),
267 if (family
!= NULL
&& !(g_strcmp0 (family
, "ipv4") == 0 || g_strcmp0 (family
, "ipv6") == 0))
271 G_IO_ERROR_INVALID_ARGUMENT
,
272 _("Error in address “%s” — the family attribute is malformed"),
279 /* TODO: validate host */
282 nonce_file
= nonce_file
; /* To avoid -Wunused-but-set-variable */
293 is_valid_tcp (const gchar
*address_entry
,
294 GHashTable
*key_value_pairs
,
312 keys
= g_hash_table_get_keys (key_value_pairs
);
313 for (l
= keys
; l
!= NULL
; l
= l
->next
)
315 const gchar
*key
= l
->data
;
316 if (g_strcmp0 (key
, "host") == 0)
317 host
= g_hash_table_lookup (key_value_pairs
, key
);
318 else if (g_strcmp0 (key
, "port") == 0)
319 port
= g_hash_table_lookup (key_value_pairs
, key
);
320 else if (g_strcmp0 (key
, "family") == 0)
321 family
= g_hash_table_lookup (key_value_pairs
, key
);
326 G_IO_ERROR_INVALID_ARGUMENT
,
327 _("Unsupported key “%s” in address entry “%s”"),
336 port_num
= strtol (port
, &endp
, 10);
337 if ((*port
== '\0' || *endp
!= '\0') || port_num
< 0 || port_num
>= 65536)
341 G_IO_ERROR_INVALID_ARGUMENT
,
342 _("Error in address “%s” — the port attribute is malformed"),
348 if (family
!= NULL
&& !(g_strcmp0 (family
, "ipv4") == 0 || g_strcmp0 (family
, "ipv6") == 0))
352 G_IO_ERROR_INVALID_ARGUMENT
,
353 _("Error in address “%s” — the family attribute is malformed"),
360 /* TODO: validate host */
372 * g_dbus_is_supported_address:
374 * @error: Return location for error or %NULL.
376 * Like g_dbus_is_address() but also checks if the library supports the
377 * transports in @string and that key/value pairs for each transport
378 * are valid. See the specification of the
379 * [D-Bus address format](https://dbus.freedesktop.org/doc/dbus-specification.html#addresses).
381 * Returns: %TRUE if @string is a valid D-Bus address that is
382 * supported by this library, %FALSE if @error is set.
387 g_dbus_is_supported_address (const gchar
*string
,
396 g_return_val_if_fail (string
!= NULL
, FALSE
);
397 g_return_val_if_fail (error
== NULL
|| *error
== NULL
, FALSE
);
399 a
= g_strsplit (string
, ";", 0);
400 for (n
= 0; a
[n
] != NULL
; n
++)
402 gchar
*transport_name
;
403 GHashTable
*key_value_pairs
;
406 if (!_g_dbus_address_parse_entry (a
[n
],
413 if (g_strcmp0 (transport_name
, "unix") == 0)
414 supported
= is_valid_unix (a
[n
], key_value_pairs
, error
);
415 else if (g_strcmp0 (transport_name
, "tcp") == 0)
416 supported
= is_valid_tcp (a
[n
], key_value_pairs
, error
);
417 else if (g_strcmp0 (transport_name
, "nonce-tcp") == 0)
418 supported
= is_valid_nonce_tcp (a
[n
], key_value_pairs
, error
);
419 else if (g_strcmp0 (a
[n
], "autolaunch:") == 0)
422 g_set_error (error
, G_IO_ERROR
, G_IO_ERROR_INVALID_ARGUMENT
,
423 _("Unknown or unsupported transport “%s” for address “%s”"),
424 transport_name
, a
[n
]);
426 g_free (transport_name
);
427 g_hash_table_unref (key_value_pairs
);
438 g_assert (ret
|| (!ret
&& (error
== NULL
|| *error
!= NULL
)));
444 _g_dbus_address_parse_entry (const gchar
*address_entry
,
445 gchar
**out_transport_name
,
446 GHashTable
**out_key_value_pairs
,
450 GHashTable
*key_value_pairs
;
451 gchar
*transport_name
;
458 transport_name
= NULL
;
459 key_value_pairs
= NULL
;
461 s
= strchr (address_entry
, ':');
466 G_IO_ERROR_INVALID_ARGUMENT
,
467 _("Address element “%s” does not contain a colon (:)"),
472 transport_name
= g_strndup (address_entry
, s
- address_entry
);
473 key_value_pairs
= g_hash_table_new_full (g_str_hash
, g_str_equal
, g_free
, g_free
);
475 kv_pairs
= g_strsplit (s
+ 1, ",", 0);
476 for (n
= 0; kv_pairs
!= NULL
&& kv_pairs
[n
] != NULL
; n
++)
478 const gchar
*kv_pair
= kv_pairs
[n
];
482 s
= strchr (kv_pair
, '=');
487 G_IO_ERROR_INVALID_ARGUMENT
,
488 _("Key/Value pair %d, “%s”, in address element “%s” does not contain an equal sign"),
495 key
= g_uri_unescape_segment (kv_pair
, s
, NULL
);
496 value
= g_uri_unescape_segment (s
+ 1, kv_pair
+ strlen (kv_pair
), NULL
);
497 if (key
== NULL
|| value
== NULL
)
501 G_IO_ERROR_INVALID_ARGUMENT
,
502 _("Error unescaping key or value in Key/Value pair %d, “%s”, in address element “%s”"),
510 g_hash_table_insert (key_value_pairs
, key
, value
);
516 g_strfreev (kv_pairs
);
519 if (out_transport_name
!= NULL
)
520 *out_transport_name
= transport_name
;
522 g_free (transport_name
);
523 if (out_key_value_pairs
!= NULL
)
524 *out_key_value_pairs
= key_value_pairs
;
525 else if (key_value_pairs
!= NULL
)
526 g_hash_table_unref (key_value_pairs
);
530 g_free (transport_name
);
531 if (key_value_pairs
!= NULL
)
532 g_hash_table_unref (key_value_pairs
);
537 /* ---------------------------------------------------------------------------------------------------- */
540 g_dbus_address_try_connect_one (const gchar
*address_entry
,
542 GCancellable
*cancellable
,
545 /* TODO: Declare an extension point called GDBusTransport (or similar)
546 * and move code below to extensions implementing said extension
547 * point. That way we can implement a D-Bus transport over X11 without
548 * making libgio link to libX11...
551 g_dbus_address_connect (const gchar
*address_entry
,
552 const gchar
*transport_name
,
553 GHashTable
*key_value_pairs
,
554 GCancellable
*cancellable
,
558 GSocketConnectable
*connectable
;
559 const gchar
*nonce_file
;
569 else if (g_strcmp0 (transport_name
, "unix") == 0)
572 const gchar
*abstract
;
573 path
= g_hash_table_lookup (key_value_pairs
, "path");
574 abstract
= g_hash_table_lookup (key_value_pairs
, "abstract");
575 if ((path
== NULL
&& abstract
== NULL
) || (path
!= NULL
&& abstract
!= NULL
))
579 G_IO_ERROR_INVALID_ARGUMENT
,
580 _("Error in address “%s” — the unix transport requires exactly one of the "
581 "keys “path” or “abstract” to be set"),
584 else if (path
!= NULL
)
586 connectable
= G_SOCKET_CONNECTABLE (g_unix_socket_address_new (path
));
588 else if (abstract
!= NULL
)
590 connectable
= G_SOCKET_CONNECTABLE (g_unix_socket_address_new_with_type (abstract
,
592 G_UNIX_SOCKET_ADDRESS_ABSTRACT
));
596 g_assert_not_reached ();
600 else if (g_strcmp0 (transport_name
, "tcp") == 0 || g_strcmp0 (transport_name
, "nonce-tcp") == 0)
608 is_nonce
= (g_strcmp0 (transport_name
, "nonce-tcp") == 0);
610 host
= g_hash_table_lookup (key_value_pairs
, "host");
615 G_IO_ERROR_INVALID_ARGUMENT
,
616 _("Error in address “%s” — the host attribute is missing or malformed"),
621 s
= g_hash_table_lookup (key_value_pairs
, "port");
624 port
= strtol (s
, &endp
, 10);
625 if ((*s
== '\0' || *endp
!= '\0') || port
< 0 || port
>= 65536)
629 G_IO_ERROR_INVALID_ARGUMENT
,
630 _("Error in address “%s” — the port attribute is missing or malformed"),
638 nonce_file
= g_hash_table_lookup (key_value_pairs
, "noncefile");
639 if (nonce_file
== NULL
)
643 G_IO_ERROR_INVALID_ARGUMENT
,
644 _("Error in address “%s” — the noncefile attribute is missing or malformed"),
650 /* TODO: deal with family key/value-pair */
651 connectable
= g_network_address_new (host
, port
);
653 else if (g_strcmp0 (address_entry
, "autolaunch:") == 0)
655 gchar
*autolaunch_address
;
656 autolaunch_address
= get_session_address_dbus_launch (error
);
657 if (autolaunch_address
!= NULL
)
659 ret
= g_dbus_address_try_connect_one (autolaunch_address
, NULL
, cancellable
, error
);
660 g_free (autolaunch_address
);
665 g_prefix_error (error
, _("Error auto-launching: "));
672 G_IO_ERROR_INVALID_ARGUMENT
,
673 _("Unknown or unsupported transport “%s” for address “%s”"),
678 if (connectable
!= NULL
)
680 GSocketClient
*client
;
681 GSocketConnection
*connection
;
683 g_assert (ret
== NULL
);
684 client
= g_socket_client_new ();
686 /* Disable proxy support to prevent a deadlock on startup, since loading a
687 * proxy resolver causes the GIO modules to be loaded, and there will
688 * almost certainly be one of them which then tries to use GDBus.
689 * See: https://bugzilla.gnome.org/show_bug.cgi?id=792499 */
690 g_socket_client_set_enable_proxy (client
, FALSE
);
692 connection
= g_socket_client_connect (client
,
696 g_object_unref (connectable
);
697 g_object_unref (client
);
698 if (connection
== NULL
)
701 ret
= G_IO_STREAM (connection
);
703 if (nonce_file
!= NULL
)
705 gchar nonce_contents
[16 + 1];
706 size_t num_bytes_read
;
710 /* be careful to read only 16 bytes - we also check that the file is only 16 bytes long */
711 f
= fopen (nonce_file
, "rb");
717 G_IO_ERROR_INVALID_ARGUMENT
,
718 _("Error opening nonce file “%s”: %s"),
721 g_object_unref (ret
);
725 num_bytes_read
= fread (nonce_contents
,
730 if (num_bytes_read
!= 16)
732 if (num_bytes_read
== 0)
736 G_IO_ERROR_INVALID_ARGUMENT
,
737 _("Error reading from nonce file “%s”: %s"),
745 G_IO_ERROR_INVALID_ARGUMENT
,
746 _("Error reading from nonce file “%s”, expected 16 bytes, got %d"),
748 (gint
) num_bytes_read
);
750 g_object_unref (ret
);
757 if (!g_output_stream_write_all (g_io_stream_get_output_stream (ret
),
764 g_prefix_error (error
, _("Error writing contents of nonce file “%s” to stream:"), nonce_file
);
765 g_object_unref (ret
);
778 g_dbus_address_try_connect_one (const gchar
*address_entry
,
780 GCancellable
*cancellable
,
784 GHashTable
*key_value_pairs
;
785 gchar
*transport_name
;
789 transport_name
= NULL
;
790 key_value_pairs
= NULL
;
792 if (!_g_dbus_address_parse_entry (address_entry
,
798 ret
= g_dbus_address_connect (address_entry
,
806 guid
= g_hash_table_lookup (key_value_pairs
, "guid");
807 if (guid
!= NULL
&& out_guid
!= NULL
)
808 *out_guid
= g_strdup (guid
);
811 g_free (transport_name
);
812 if (key_value_pairs
!= NULL
)
813 g_hash_table_unref (key_value_pairs
);
818 /* ---------------------------------------------------------------------------------------------------- */
826 get_stream_data_free (GetStreamData
*data
)
828 g_free (data
->address
);
834 get_stream_thread_func (GTask
*task
,
835 gpointer source_object
,
837 GCancellable
*cancellable
)
839 GetStreamData
*data
= task_data
;
841 GError
*error
= NULL
;
843 stream
= g_dbus_address_get_stream_sync (data
->address
,
848 g_task_return_pointer (task
, stream
, g_object_unref
);
850 g_task_return_error (task
, error
);
854 * g_dbus_address_get_stream:
855 * @address: A valid D-Bus address.
856 * @cancellable: (nullable): A #GCancellable or %NULL.
857 * @callback: A #GAsyncReadyCallback to call when the request is satisfied.
858 * @user_data: Data to pass to @callback.
860 * Asynchronously connects to an endpoint specified by @address and
861 * sets up the connection so it is in a state to run the client-side
862 * of the D-Bus authentication conversation. @address must be in the
863 * [D-Bus address format](https://dbus.freedesktop.org/doc/dbus-specification.html#addresses).
865 * When the operation is finished, @callback will be invoked. You can
866 * then call g_dbus_address_get_stream_finish() to get the result of
869 * This is an asynchronous failable function. See
870 * g_dbus_address_get_stream_sync() for the synchronous version.
875 g_dbus_address_get_stream (const gchar
*address
,
876 GCancellable
*cancellable
,
877 GAsyncReadyCallback callback
,
883 g_return_if_fail (address
!= NULL
);
885 data
= g_new0 (GetStreamData
, 1);
886 data
->address
= g_strdup (address
);
888 task
= g_task_new (NULL
, cancellable
, callback
, user_data
);
889 g_task_set_source_tag (task
, g_dbus_address_get_stream
);
890 g_task_set_task_data (task
, data
, (GDestroyNotify
) get_stream_data_free
);
891 g_task_run_in_thread (task
, get_stream_thread_func
);
892 g_object_unref (task
);
896 * g_dbus_address_get_stream_finish:
897 * @res: A #GAsyncResult obtained from the GAsyncReadyCallback passed to g_dbus_address_get_stream().
898 * @out_guid: (optional) (out): %NULL or return location to store the GUID extracted from @address, if any.
899 * @error: Return location for error or %NULL.
901 * Finishes an operation started with g_dbus_address_get_stream().
903 * Returns: (transfer full): A #GIOStream or %NULL if @error is set.
908 g_dbus_address_get_stream_finish (GAsyncResult
*res
,
916 g_return_val_if_fail (g_task_is_valid (res
, NULL
), NULL
);
917 g_return_val_if_fail (error
== NULL
|| *error
== NULL
, NULL
);
920 ret
= g_task_propagate_pointer (task
, error
);
922 if (ret
!= NULL
&& out_guid
!= NULL
)
924 data
= g_task_get_task_data (task
);
925 *out_guid
= data
->guid
;
933 * g_dbus_address_get_stream_sync:
934 * @address: A valid D-Bus address.
935 * @out_guid: (optional) (out): %NULL or return location to store the GUID extracted from @address, if any.
936 * @cancellable: (nullable): A #GCancellable or %NULL.
937 * @error: Return location for error or %NULL.
939 * Synchronously connects to an endpoint specified by @address and
940 * sets up the connection so it is in a state to run the client-side
941 * of the D-Bus authentication conversation. @address must be in the
942 * [D-Bus address format](https://dbus.freedesktop.org/doc/dbus-specification.html#addresses).
944 * This is a synchronous failable function. See
945 * g_dbus_address_get_stream() for the asynchronous version.
947 * Returns: (transfer full): A #GIOStream or %NULL if @error is set.
952 g_dbus_address_get_stream_sync (const gchar
*address
,
954 GCancellable
*cancellable
,
962 g_return_val_if_fail (address
!= NULL
, NULL
);
963 g_return_val_if_fail (error
== NULL
|| *error
== NULL
, NULL
);
968 addr_array
= g_strsplit (address
, ";", 0);
969 if (addr_array
!= NULL
&& addr_array
[0] == NULL
)
971 last_error
= g_error_new_literal (G_IO_ERROR
,
972 G_IO_ERROR_INVALID_ARGUMENT
,
973 _("The given address is empty"));
977 for (n
= 0; addr_array
!= NULL
&& addr_array
[n
] != NULL
; n
++)
979 const gchar
*addr
= addr_array
[n
];
983 ret
= g_dbus_address_try_connect_one (addr
,
993 g_assert (this_error
!= NULL
);
994 if (last_error
!= NULL
)
995 g_error_free (last_error
);
996 last_error
= this_error
;
1003 if (last_error
!= NULL
)
1004 g_error_free (last_error
);
1008 g_assert (last_error
!= NULL
);
1009 g_propagate_error (error
, last_error
);
1012 g_strfreev (addr_array
);
1016 /* ---------------------------------------------------------------------------------------------------- */
1019 * Return the address of XDG_RUNTIME_DIR/bus if it exists, belongs to
1020 * us, and is a socket, and we are on Unix.
1023 get_session_address_xdg (void)
1031 bus
= g_build_filename (g_get_user_runtime_dir (), "bus", NULL
);
1033 /* if ENOENT, EPERM, etc., quietly don't use it */
1034 if (g_stat (bus
, &buf
) < 0)
1037 /* if it isn't ours, we have incorrectly inherited someone else's
1038 * XDG_RUNTIME_DIR; silently don't use it
1040 if (buf
.st_uid
!= geteuid ())
1043 /* if it isn't a socket, silently don't use it */
1044 if ((buf
.st_mode
& S_IFMT
) != S_IFSOCK
)
1047 tmp
= g_dbus_address_escape_value (bus
);
1048 ret
= g_strconcat ("unix:path=", tmp
, NULL
);
1059 /* ---------------------------------------------------------------------------------------------------- */
1063 get_session_address_dbus_launch (GError
**error
)
1067 gchar
*command_line
;
1068 gchar
*launch_stdout
;
1069 gchar
*launch_stderr
;
1071 gchar
*old_dbus_verbose
;
1072 gboolean restore_dbus_verbose
;
1076 command_line
= NULL
;
1077 launch_stdout
= NULL
;
1078 launch_stderr
= NULL
;
1079 restore_dbus_verbose
= FALSE
;
1080 old_dbus_verbose
= NULL
;
1082 /* Don't run binaries as root if we're setuid. */
1083 if (GLIB_PRIVATE_CALL (g_check_setuid
) ())
1085 g_set_error (error
, G_IO_ERROR
, G_IO_ERROR_FAILED
,
1086 _("Cannot spawn a message bus when setuid"));
1090 machine_id
= _g_dbus_get_machine_id (error
);
1091 if (machine_id
== NULL
)
1093 g_prefix_error (error
, _("Cannot spawn a message bus without a machine-id: "));
1097 if (g_getenv ("DISPLAY") == NULL
)
1099 g_set_error (error
, G_IO_ERROR
, G_IO_ERROR_FAILED
,
1100 _("Cannot autolaunch D-Bus without X11 $DISPLAY"));
1104 /* We're using private libdbus facilities here. When everything
1105 * (X11, Mac OS X, Windows) is spec'ed out correctly (not even the
1106 * X11 property is correctly documented right now) we should
1107 * consider using the spec instead of dbus-launch.
1109 * --autolaunch=MACHINEID
1110 * This option implies that dbus-launch should scan for a previ‐
1111 * ously-started session and reuse the values found there. If no
1112 * session is found, it will start a new session. The --exit-with-
1113 * session option is implied if --autolaunch is given. This option
1114 * is for the exclusive use of libdbus, you do not want to use it
1115 * manually. It may change in the future.
1118 /* TODO: maybe provide a variable for where to look for the dbus-launch binary? */
1119 command_line
= g_strdup_printf ("dbus-launch --autolaunch=%s --binary-syntax --close-stderr", machine_id
);
1121 if (G_UNLIKELY (_g_dbus_debug_address ()))
1123 _g_dbus_debug_print_lock ();
1124 g_print ("GDBus-debug:Address: Running '%s' to get bus address (possibly autolaunching)\n", command_line
);
1125 old_dbus_verbose
= g_strdup (g_getenv ("DBUS_VERBOSE"));
1126 restore_dbus_verbose
= TRUE
;
1127 g_setenv ("DBUS_VERBOSE", "1", TRUE
);
1128 _g_dbus_debug_print_unlock ();
1131 if (!g_spawn_command_line_sync (command_line
,
1140 if (!g_spawn_check_exit_status (exit_status
, error
))
1142 g_prefix_error (error
, _("Error spawning command line “%s”: "), command_line
);
1146 /* From the dbus-launch(1) man page:
1148 * --binary-syntax Write to stdout a nul-terminated bus address,
1149 * then the bus PID as a binary integer of size sizeof(pid_t),
1150 * then the bus X window ID as a binary integer of size
1151 * sizeof(long). Integers are in the machine's byte order, not
1152 * network byte order or any other canonical byte order.
1154 ret
= g_strdup (launch_stdout
);
1157 if (G_UNLIKELY (_g_dbus_debug_address ()))
1160 _g_dbus_debug_print_lock ();
1161 g_print ("GDBus-debug:Address: dbus-launch output:");
1162 if (launch_stdout
!= NULL
)
1164 s
= _g_dbus_hexdump (launch_stdout
, strlen (launch_stdout
) + 1 + sizeof (pid_t
) + sizeof (long), 2);
1165 g_print ("\n%s", s
);
1170 g_print (" (none)\n");
1172 g_print ("GDBus-debug:Address: dbus-launch stderr output:");
1173 if (launch_stderr
!= NULL
)
1174 g_print ("\n%s", launch_stderr
);
1176 g_print (" (none)\n");
1177 _g_dbus_debug_print_unlock ();
1180 g_free (machine_id
);
1181 g_free (command_line
);
1182 g_free (launch_stdout
);
1183 g_free (launch_stderr
);
1184 if (G_UNLIKELY (restore_dbus_verbose
))
1186 if (old_dbus_verbose
!= NULL
)
1187 g_setenv ("DBUS_VERBOSE", old_dbus_verbose
, TRUE
);
1189 g_unsetenv ("DBUS_VERBOSE");
1191 g_free (old_dbus_verbose
);
1195 /* end of G_OS_UNIX case */
1196 #elif defined(G_OS_WIN32)
1198 #define DBUS_DAEMON_ADDRESS_INFO "DBusDaemonAddressInfo"
1199 #define DBUS_DAEMON_MUTEX "DBusDaemonMutex"
1200 #define UNIQUE_DBUS_INIT_MUTEX "UniqueDBusInitMutex"
1201 #define DBUS_AUTOLAUNCH_MUTEX "DBusAutolaunchMutex"
1204 release_mutex (HANDLE mutex
)
1206 ReleaseMutex (mutex
);
1207 CloseHandle (mutex
);
1211 acquire_mutex (const char *mutexname
)
1216 mutex
= CreateMutexA (NULL
, FALSE
, mutexname
);
1220 res
= WaitForSingleObject (mutex
, INFINITE
);
1223 case WAIT_ABANDONED
:
1224 release_mutex (mutex
);
1235 is_mutex_owned (const char *mutexname
)
1238 gboolean res
= FALSE
;
1240 mutex
= CreateMutexA (NULL
, FALSE
, mutexname
);
1241 if (WaitForSingleObject (mutex
, 10) == WAIT_TIMEOUT
)
1244 ReleaseMutex (mutex
);
1245 CloseHandle (mutex
);
1251 read_shm (const char *shm_name
)
1260 for (i
= 0; i
< 20; i
++)
1262 shared_mem
= OpenFileMappingA (FILE_MAP_READ
, FALSE
, shm_name
);
1263 if (shared_mem
!= 0)
1268 if (shared_mem
!= 0)
1270 shared_data
= MapViewOfFile (shared_mem
, FILE_MAP_READ
, 0, 0, 0);
1271 if (shared_data
!= NULL
)
1273 res
= g_strdup (shared_data
);
1274 UnmapViewOfFile (shared_data
);
1276 CloseHandle (shared_mem
);
1283 set_shm (const char *shm_name
, const char *value
)
1288 shared_mem
= CreateFileMappingA (INVALID_HANDLE_VALUE
, NULL
, PAGE_READWRITE
,
1289 0, strlen (value
) + 1, shm_name
);
1290 if (shared_mem
== 0)
1293 shared_data
= MapViewOfFile (shared_mem
, FILE_MAP_WRITE
, 0, 0, 0 );
1294 if (shared_data
== NULL
)
1297 strcpy (shared_data
, value
);
1299 UnmapViewOfFile (shared_data
);
1304 /* These keep state between publish_session_bus and unpublish_session_bus */
1305 static HANDLE published_daemon_mutex
;
1306 static HANDLE published_shared_mem
;
1309 publish_session_bus (const char *address
)
1313 init_mutex
= acquire_mutex (UNIQUE_DBUS_INIT_MUTEX
);
1315 published_daemon_mutex
= CreateMutexA (NULL
, FALSE
, DBUS_DAEMON_MUTEX
);
1316 if (WaitForSingleObject (published_daemon_mutex
, 10 ) != WAIT_OBJECT_0
)
1318 release_mutex (init_mutex
);
1319 CloseHandle (published_daemon_mutex
);
1320 published_daemon_mutex
= NULL
;
1324 published_shared_mem
= set_shm (DBUS_DAEMON_ADDRESS_INFO
, address
);
1325 if (!published_shared_mem
)
1327 release_mutex (init_mutex
);
1328 CloseHandle (published_daemon_mutex
);
1329 published_daemon_mutex
= NULL
;
1333 release_mutex (init_mutex
);
1338 unpublish_session_bus (void)
1342 init_mutex
= acquire_mutex (UNIQUE_DBUS_INIT_MUTEX
);
1344 CloseHandle (published_shared_mem
);
1345 published_shared_mem
= NULL
;
1347 release_mutex (published_daemon_mutex
);
1348 published_daemon_mutex
= NULL
;
1350 release_mutex (init_mutex
);
1354 wait_console_window (void)
1356 FILE *console
= fopen ("CONOUT$", "w");
1358 SetConsoleTitleW (L
"gdbus-daemon output. Type any character to close this window.");
1359 fprintf (console
, _("(Type any character to close this window)\n"));
1365 open_console_window (void)
1367 if (((HANDLE
) _get_osfhandle (fileno (stdout
)) == INVALID_HANDLE_VALUE
||
1368 (HANDLE
) _get_osfhandle (fileno (stderr
)) == INVALID_HANDLE_VALUE
) && AllocConsole ())
1370 if ((HANDLE
) _get_osfhandle (fileno (stdout
)) == INVALID_HANDLE_VALUE
)
1371 freopen ("CONOUT$", "w", stdout
);
1373 if ((HANDLE
) _get_osfhandle (fileno (stderr
)) == INVALID_HANDLE_VALUE
)
1374 freopen ("CONOUT$", "w", stderr
);
1376 SetConsoleTitleW (L
"gdbus-daemon debug output.");
1378 atexit (wait_console_window
);
1383 idle_timeout_cb (GDBusDaemon
*daemon
, gpointer user_data
)
1385 GMainLoop
*loop
= user_data
;
1386 g_main_loop_quit (loop
);
1389 /* Satisfies STARTF_FORCEONFEEDBACK */
1391 turn_off_the_starting_cursor (void)
1396 PostQuitMessage (0);
1398 while ((bRet
= GetMessage (&msg
, 0, 0, 0)) != 0)
1403 TranslateMessage (&msg
);
1404 DispatchMessage (&msg
);
1408 __declspec(dllexport
) void CALLBACK
g_win32_run_session_bus (HWND hwnd
, HINSTANCE hinst
, char *cmdline
, int nCmdShow
);
1410 __declspec(dllexport
) void CALLBACK
1411 g_win32_run_session_bus (HWND hwnd
, HINSTANCE hinst
, char *cmdline
, int nCmdShow
)
1413 GDBusDaemon
*daemon
;
1415 const char *address
;
1416 GError
*error
= NULL
;
1418 turn_off_the_starting_cursor ();
1420 if (g_getenv ("GDBUS_DAEMON_DEBUG") != NULL
)
1421 open_console_window ();
1423 loop
= g_main_loop_new (NULL
, FALSE
);
1425 address
= "nonce-tcp:";
1426 daemon
= _g_dbus_daemon_new (address
, NULL
, &error
);
1429 g_printerr ("Can't init bus: %s\n", error
->message
);
1430 g_error_free (error
);
1434 g_signal_connect (daemon
, "idle-timeout", G_CALLBACK (idle_timeout_cb
), loop
);
1436 if (publish_session_bus (_g_dbus_daemon_get_address (daemon
)))
1438 g_main_loop_run (loop
);
1440 unpublish_session_bus ();
1443 g_main_loop_unref (loop
);
1444 g_object_unref (daemon
);
1448 get_session_address_dbus_launch (GError
**error
)
1450 HANDLE autolaunch_mutex
, init_mutex
;
1451 char *address
= NULL
;
1452 wchar_t gio_path
[MAX_PATH
+1+200];
1454 autolaunch_mutex
= acquire_mutex (DBUS_AUTOLAUNCH_MUTEX
);
1456 init_mutex
= acquire_mutex (UNIQUE_DBUS_INIT_MUTEX
);
1458 if (is_mutex_owned (DBUS_DAEMON_MUTEX
))
1459 address
= read_shm (DBUS_DAEMON_ADDRESS_INFO
);
1461 release_mutex (init_mutex
);
1463 if (address
== NULL
)
1465 gio_path
[MAX_PATH
] = 0;
1466 if (GetModuleFileNameW (_g_io_win32_get_module (), gio_path
, MAX_PATH
))
1468 PROCESS_INFORMATION pi
= { 0 };
1469 STARTUPINFOW si
= { 0 };
1471 wchar_t gio_path_short
[MAX_PATH
];
1472 wchar_t rundll_path
[MAX_PATH
*2];
1473 wchar_t args
[MAX_PATH
*4];
1475 GetShortPathNameW (gio_path
, gio_path_short
, MAX_PATH
);
1477 GetWindowsDirectoryW (rundll_path
, MAX_PATH
);
1478 wcscat (rundll_path
, L
"\\rundll32.exe");
1479 if (GetFileAttributesW (rundll_path
) == INVALID_FILE_ATTRIBUTES
)
1481 GetSystemDirectoryW (rundll_path
, MAX_PATH
);
1482 wcscat (rundll_path
, L
"\\rundll32.exe");
1485 wcscpy (args
, L
"\"");
1486 wcscat (args
, rundll_path
);
1487 wcscat (args
, L
"\" ");
1488 wcscat (args
, gio_path_short
);
1489 #if defined(_WIN64) || defined(_M_X64) || defined(_M_AMD64)
1490 wcscat (args
, L
",g_win32_run_session_bus");
1491 #elif defined (_MSC_VER)
1492 wcscat (args
, L
",_g_win32_run_session_bus@16");
1494 wcscat (args
, L
",g_win32_run_session_bus@16");
1497 res
= CreateProcessW (rundll_path
, args
,
1499 NORMAL_PRIORITY_CLASS
| CREATE_NO_WINDOW
| DETACHED_PROCESS
,
1500 0, NULL
/* TODO: Should be root */,
1503 address
= read_shm (DBUS_DAEMON_ADDRESS_INFO
);
1507 release_mutex (autolaunch_mutex
);
1509 if (address
== NULL
)
1513 _("Session dbus not running, and autolaunch failed"));
1517 #else /* neither G_OS_UNIX nor G_OS_WIN32 */
1519 get_session_address_dbus_launch (GError
**error
)
1524 _("Cannot determine session bus address (not implemented for this OS)"));
1527 #endif /* neither G_OS_UNIX nor G_OS_WIN32 */
1529 /* ---------------------------------------------------------------------------------------------------- */
1532 get_session_address_platform_specific (GError
**error
)
1536 /* Use XDG_RUNTIME_DIR/bus if it exists and is suitable. This is appropriate
1537 * for systems using the "a session is a user-session" model described in
1538 * <http://lists.freedesktop.org/archives/dbus/2015-January/016522.html>,
1539 * and implemented in dbus >= 1.9.14 and sd-bus.
1541 * On systems following the more traditional "a session is a login-session"
1542 * model, this will fail and we'll fall through to X11 autolaunching
1543 * (dbus-launch) below.
1545 ret
= get_session_address_xdg ();
1550 /* TODO (#694472): try launchd on OS X, like
1551 * _dbus_lookup_session_address_launchd() does, since
1552 * 'dbus-launch --autolaunch' probably won't work there
1555 /* As a last resort, try the "autolaunch:" transport. On Unix this means
1556 * X11 autolaunching; on Windows this means a different autolaunching
1557 * mechanism based on shared memory.
1559 return get_session_address_dbus_launch (error
);
1562 /* ---------------------------------------------------------------------------------------------------- */
1565 * g_dbus_address_get_for_bus_sync:
1566 * @bus_type: a #GBusType
1567 * @cancellable: (nullable): a #GCancellable or %NULL
1568 * @error: return location for error or %NULL
1570 * Synchronously looks up the D-Bus address for the well-known message
1571 * bus instance specified by @bus_type. This may involve using various
1572 * platform specific mechanisms.
1574 * The returned address will be in the
1575 * [D-Bus address format](https://dbus.freedesktop.org/doc/dbus-specification.html#addresses).
1577 * Returns: a valid D-Bus address string for @bus_type or %NULL if
1583 g_dbus_address_get_for_bus_sync (GBusType bus_type
,
1584 GCancellable
*cancellable
,
1587 gchar
*ret
, *s
= NULL
;
1588 const gchar
*starter_bus
;
1589 GError
*local_error
;
1591 g_return_val_if_fail (error
== NULL
|| *error
== NULL
, NULL
);
1596 if (G_UNLIKELY (_g_dbus_debug_address ()))
1599 _g_dbus_debug_print_lock ();
1600 s
= _g_dbus_enum_to_string (G_TYPE_BUS_TYPE
, bus_type
);
1601 g_print ("GDBus-debug:Address: In g_dbus_address_get_for_bus_sync() for bus type '%s'\n",
1604 for (n
= 0; n
< 3; n
++)
1610 case 0: k
= "DBUS_SESSION_BUS_ADDRESS"; break;
1611 case 1: k
= "DBUS_SYSTEM_BUS_ADDRESS"; break;
1612 case 2: k
= "DBUS_STARTER_BUS_TYPE"; break;
1613 default: g_assert_not_reached ();
1616 g_print ("GDBus-debug:Address: env var %s", k
);
1618 g_print ("='%s'\n", v
);
1620 g_print (" is not set\n");
1622 _g_dbus_debug_print_unlock ();
1627 case G_BUS_TYPE_SYSTEM
:
1628 ret
= g_strdup (g_getenv ("DBUS_SYSTEM_BUS_ADDRESS"));
1631 ret
= g_strdup ("unix:path=/var/run/dbus/system_bus_socket");
1635 case G_BUS_TYPE_SESSION
:
1636 ret
= g_strdup (g_getenv ("DBUS_SESSION_BUS_ADDRESS"));
1639 ret
= get_session_address_platform_specific (&local_error
);
1643 case G_BUS_TYPE_STARTER
:
1644 starter_bus
= g_getenv ("DBUS_STARTER_BUS_TYPE");
1645 if (g_strcmp0 (starter_bus
, "session") == 0)
1647 ret
= g_dbus_address_get_for_bus_sync (G_BUS_TYPE_SESSION
, cancellable
, &local_error
);
1650 else if (g_strcmp0 (starter_bus
, "system") == 0)
1652 ret
= g_dbus_address_get_for_bus_sync (G_BUS_TYPE_SYSTEM
, cancellable
, &local_error
);
1657 if (starter_bus
!= NULL
)
1659 g_set_error (&local_error
,
1662 _("Cannot determine bus address from DBUS_STARTER_BUS_TYPE environment variable"
1663 " — unknown value “%s”"),
1668 g_set_error_literal (&local_error
,
1671 _("Cannot determine bus address because the DBUS_STARTER_BUS_TYPE environment "
1672 "variable is not set"));
1678 g_set_error (&local_error
,
1681 _("Unknown bus type %d"),
1687 if (G_UNLIKELY (_g_dbus_debug_address ()))
1689 _g_dbus_debug_print_lock ();
1690 s
= _g_dbus_enum_to_string (G_TYPE_BUS_TYPE
, bus_type
);
1693 g_print ("GDBus-debug:Address: Returning address '%s' for bus type '%s'\n",
1698 g_print ("GDBus-debug:Address: Cannot look-up address bus type '%s': %s\n",
1699 s
, local_error
? local_error
->message
: "");
1702 _g_dbus_debug_print_unlock ();
1705 if (local_error
!= NULL
)
1706 g_propagate_error (error
, local_error
);
1712 * g_dbus_address_escape_value:
1713 * @string: an unescaped string to be included in a D-Bus address
1714 * as the value in a key-value pair
1716 * Escape @string so it can appear in a D-Bus address as the value
1717 * part of a key-value pair.
1719 * For instance, if @string is `/run/bus-for-:0`,
1720 * this function would return `/run/bus-for-%3A0`,
1721 * which could be used in a D-Bus address like
1722 * `unix:nonce-tcp:host=127.0.0.1,port=42,noncefile=/run/bus-for-%3A0`.
1724 * Returns: (transfer full): a copy of @string with all
1725 * non-optionally-escaped bytes escaped
1730 g_dbus_address_escape_value (const gchar
*string
)
1735 g_return_val_if_fail (string
!= NULL
, NULL
);
1737 /* There will often not be anything needing escaping at all. */
1738 s
= g_string_sized_new (strlen (string
));
1740 /* D-Bus address escaping is mostly the same as URI escaping... */
1741 g_string_append_uri_escaped (s
, string
, "\\/", FALSE
);
1743 /* ... but '~' is an unreserved character in URIs, but a
1744 * non-optionally-escaped character in D-Bus addresses. */
1745 for (i
= 0; i
< s
->len
; i
++)
1747 if (G_UNLIKELY (s
->str
[i
] == '~'))
1750 g_string_insert (s
, i
+ 1, "7E");
1755 return g_string_free (s
, FALSE
);