Branch data Line data Source code
1 : : /* GDBus - GLib D-Bus Library
2 : : *
3 : : * Copyright (C) 2008-2010 Red Hat, Inc.
4 : : *
5 : : * SPDX-License-Identifier: LGPL-2.1-or-later
6 : : *
7 : : * This library is free software; you can redistribute it and/or
8 : : * modify it under the terms of the GNU Lesser General Public
9 : : * License as published by the Free Software Foundation; either
10 : : * version 2.1 of the License, or (at your option) any later version.
11 : : *
12 : : * This library is distributed in the hope that it will be useful,
13 : : * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 : : * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 : : * Lesser General Public License for more details.
16 : : *
17 : : * You should have received a copy of the GNU Lesser General
18 : : * Public License along with this library; if not, see <http://www.gnu.org/licenses/>.
19 : : *
20 : : * Author: David Zeuthen <davidz@redhat.com>
21 : : */
22 : :
23 : : #include "config.h"
24 : :
25 : : #include <stdlib.h>
26 : : #include <string.h>
27 : : #include <stdio.h>
28 : : #include <errno.h>
29 : :
30 : : #include "gioerror.h"
31 : : #include "gdbusutils.h"
32 : : #include "gdbusaddress.h"
33 : : #include "gdbuserror.h"
34 : : #include "gioenumtypes.h"
35 : : #include "glib-private.h"
36 : : #include "gnetworkaddress.h"
37 : : #include "gsocketclient.h"
38 : : #include "giostream.h"
39 : : #include "gasyncresult.h"
40 : : #include "gtask.h"
41 : : #include "glib-private.h"
42 : : #include "gdbusprivate.h"
43 : : #include "gstdio.h"
44 : :
45 : : #ifdef HAVE_UNISTD_H
46 : : #include <unistd.h>
47 : : #endif
48 : : #include <sys/stat.h>
49 : : #include <sys/types.h>
50 : : #include <gio/gunixsocketaddress.h>
51 : :
52 : : #ifdef G_OS_WIN32
53 : : #include <windows.h>
54 : : #endif
55 : :
56 : : #ifdef G_OS_WIN32
57 : : #define FO_CLOEXEC ""
58 : : #else
59 : : #define FO_CLOEXEC "e"
60 : : #endif
61 : :
62 : : #include "glibintl.h"
63 : :
64 : : /**
65 : : * GDBusAddress:
66 : : *
67 : : * Routines for working with D-Bus addresses. A D-Bus address is a string
68 : : * like `unix:tmpdir=/tmp/my-app-name`. The exact format of addresses
69 : : * is explained in detail in the
70 : : * [D-Bus specification](http://dbus.freedesktop.org/doc/dbus-specification.html#addresses).
71 : : *
72 : : * TCP D-Bus connections are supported, but accessing them via a proxy is
73 : : * currently not supported.
74 : : *
75 : : * Since GLib 2.72, `unix:` addresses are supported on Windows with `AF_UNIX`
76 : : * support (Windows 10).
77 : : */
78 : :
79 : : static gchar *get_session_address_platform_specific (GError **error);
80 : : static gchar *get_session_address_dbus_launch (GError **error);
81 : :
82 : : /* ---------------------------------------------------------------------------------------------------- */
83 : :
84 : : /**
85 : : * g_dbus_is_address:
86 : : * @string: A string.
87 : : *
88 : : * Checks if @string is a
89 : : * [D-Bus address](https://dbus.freedesktop.org/doc/dbus-specification.html#addresses).
90 : : *
91 : : * This doesn't check if @string is actually supported by #GDBusServer
92 : : * or #GDBusConnection - use g_dbus_is_supported_address() to do more
93 : : * checks.
94 : : *
95 : : * Returns: %TRUE if @string is a valid D-Bus address, %FALSE otherwise.
96 : : *
97 : : * Since: 2.26
98 : : */
99 : : gboolean
100 : 63 : g_dbus_is_address (const gchar *string)
101 : : {
102 : : guint n;
103 : : gchar **a;
104 : : gboolean ret;
105 : :
106 : 63 : ret = FALSE;
107 : :
108 : 63 : g_return_val_if_fail (string != NULL, FALSE);
109 : :
110 : 63 : a = g_strsplit (string, ";", 0);
111 : 63 : if (a[0] == NULL)
112 : 1 : goto out;
113 : :
114 : 121 : for (n = 0; a[n] != NULL; n++)
115 : : {
116 : 69 : if (!_g_dbus_address_parse_entry (a[n],
117 : : NULL,
118 : : NULL,
119 : : NULL))
120 : 10 : goto out;
121 : : }
122 : :
123 : 52 : ret = TRUE;
124 : :
125 : 63 : out:
126 : 63 : g_strfreev (a);
127 : 63 : return ret;
128 : : }
129 : :
130 : : static gboolean
131 : 56 : is_valid_unix (const gchar *address_entry,
132 : : GHashTable *key_value_pairs,
133 : : GError **error)
134 : : {
135 : : gboolean ret;
136 : : GPtrArray *keys;
137 : : const gchar *path;
138 : : const gchar *dir;
139 : : const gchar *tmpdir;
140 : : const gchar *abstract;
141 : :
142 : 56 : ret = FALSE;
143 : 56 : path = NULL;
144 : 56 : dir = NULL;
145 : 56 : tmpdir = NULL;
146 : 56 : abstract = NULL;
147 : :
148 : 56 : keys = g_hash_table_get_keys_as_ptr_array (key_value_pairs);
149 : 124 : for (guint i = 0; i < keys->len; ++i)
150 : : {
151 : 70 : const gchar *key = g_ptr_array_index (keys, i);
152 : 70 : if (g_strcmp0 (key, "path") == 0)
153 : 18 : path = g_hash_table_lookup (key_value_pairs, key);
154 : 52 : else if (g_strcmp0 (key, "dir") == 0)
155 : 17 : dir = g_hash_table_lookup (key_value_pairs, key);
156 : 35 : else if (g_strcmp0 (key, "tmpdir") == 0)
157 : 17 : tmpdir = g_hash_table_lookup (key_value_pairs, key);
158 : 18 : else if (g_strcmp0 (key, "abstract") == 0)
159 : 12 : abstract = g_hash_table_lookup (key_value_pairs, key);
160 : 6 : else if (g_strcmp0 (key, "guid") != 0)
161 : : {
162 : 2 : g_set_error (error,
163 : : G_IO_ERROR,
164 : : G_IO_ERROR_INVALID_ARGUMENT,
165 : : _("Unsupported key “%s” in address entry “%s”"),
166 : : key,
167 : : address_entry);
168 : 2 : goto out;
169 : : }
170 : : }
171 : :
172 : : /* Exactly one key must be set */
173 : 54 : if ((path != NULL) + (dir != NULL) + (tmpdir != NULL) + (abstract != NULL) > 1)
174 : : {
175 : 12 : g_set_error (error,
176 : : G_IO_ERROR,
177 : : G_IO_ERROR_INVALID_ARGUMENT,
178 : : _("Meaningless key/value pair combination in address entry “%s”"),
179 : : address_entry);
180 : 12 : goto out;
181 : : }
182 : 42 : else if (path == NULL && dir == NULL && tmpdir == NULL && abstract == NULL)
183 : : {
184 : 2 : g_set_error (error,
185 : : G_IO_ERROR,
186 : : G_IO_ERROR_INVALID_ARGUMENT,
187 : : _("Address “%s” is invalid (need exactly one of path, dir, tmpdir, or abstract keys)"),
188 : : address_entry);
189 : 2 : goto out;
190 : : }
191 : :
192 : 40 : ret = TRUE;
193 : :
194 : 56 : out:
195 : 56 : g_ptr_array_unref (keys);
196 : :
197 : 56 : return ret;
198 : : }
199 : :
200 : : static gboolean
201 : 35 : is_valid_nonce_tcp (const gchar *address_entry,
202 : : GHashTable *key_value_pairs,
203 : : GError **error)
204 : : {
205 : : gboolean ret;
206 : : GPtrArray *keys;
207 : : const gchar *host;
208 : : const gchar *port;
209 : : const gchar *family;
210 : : const gchar *nonce_file;
211 : : gint port_num;
212 : : gchar *endp;
213 : :
214 : 35 : ret = FALSE;
215 : 35 : host = NULL;
216 : 35 : port = NULL;
217 : 35 : family = NULL;
218 : 35 : nonce_file = NULL;
219 : :
220 : 35 : keys = g_hash_table_get_keys_as_ptr_array (key_value_pairs);
221 : 134 : for (guint i = 0; i < keys->len; ++i)
222 : : {
223 : 101 : const gchar *key = g_ptr_array_index (keys, i);
224 : 101 : if (g_strcmp0 (key, "host") == 0)
225 : 33 : host = g_hash_table_lookup (key_value_pairs, key);
226 : 68 : else if (g_strcmp0 (key, "port") == 0)
227 : 28 : port = g_hash_table_lookup (key_value_pairs, key);
228 : 40 : else if (g_strcmp0 (key, "family") == 0)
229 : 14 : family = g_hash_table_lookup (key_value_pairs, key);
230 : 26 : else if (g_strcmp0 (key, "noncefile") == 0)
231 : 20 : nonce_file = g_hash_table_lookup (key_value_pairs, key);
232 : 6 : else if (g_strcmp0 (key, "guid") != 0)
233 : : {
234 : 2 : g_set_error (error,
235 : : G_IO_ERROR,
236 : : G_IO_ERROR_INVALID_ARGUMENT,
237 : : _("Unsupported key “%s” in address entry “%s”"),
238 : : key,
239 : : address_entry);
240 : 2 : goto out;
241 : : }
242 : : }
243 : :
244 : 33 : if (port != NULL)
245 : : {
246 : 28 : port_num = strtol (port, &endp, 10);
247 : 28 : if ((*port == '\0' || *endp != '\0') || port_num < 0 || port_num >= 65536)
248 : : {
249 : 16 : g_set_error (error,
250 : : G_IO_ERROR,
251 : : G_IO_ERROR_INVALID_ARGUMENT,
252 : : _("Error in address “%s” — the “%s” attribute is malformed"),
253 : : address_entry, "port");
254 : 16 : goto out;
255 : : }
256 : : }
257 : :
258 : 17 : if (family != NULL && !(g_strcmp0 (family, "ipv4") == 0 || g_strcmp0 (family, "ipv6") == 0))
259 : : {
260 : 2 : g_set_error (error,
261 : : G_IO_ERROR,
262 : : G_IO_ERROR_INVALID_ARGUMENT,
263 : : _("Error in address “%s” — the “%s” attribute is malformed"),
264 : : address_entry, "family");
265 : 2 : goto out;
266 : : }
267 : :
268 : : if (host != NULL)
269 : : {
270 : : /* TODO: validate host */
271 : : }
272 : :
273 : 15 : if (nonce_file != NULL && *nonce_file == '\0')
274 : : {
275 : 2 : g_set_error (error,
276 : : G_IO_ERROR,
277 : : G_IO_ERROR_INVALID_ARGUMENT,
278 : : _("Error in address “%s” — the “%s” attribute is malformed"),
279 : : address_entry, "noncefile");
280 : 2 : goto out;
281 : : }
282 : :
283 : 13 : ret = TRUE;
284 : :
285 : 35 : out:
286 : 35 : g_ptr_array_unref (keys);
287 : :
288 : 35 : return ret;
289 : : }
290 : :
291 : : static gboolean
292 : 34 : is_valid_tcp (const gchar *address_entry,
293 : : GHashTable *key_value_pairs,
294 : : GError **error)
295 : : {
296 : : gboolean ret;
297 : : GPtrArray *keys;
298 : : const gchar *host;
299 : : const gchar *port;
300 : : const gchar *family;
301 : : gint port_num;
302 : : gchar *endp;
303 : :
304 : 34 : ret = FALSE;
305 : 34 : host = NULL;
306 : 34 : port = NULL;
307 : 34 : family = NULL;
308 : :
309 : 34 : keys = g_hash_table_get_keys_as_ptr_array (key_value_pairs);
310 : 98 : for (guint i = 0; i < keys->len; ++i)
311 : : {
312 : 66 : const gchar *key = g_ptr_array_index (keys, i);
313 : 66 : if (g_strcmp0 (key, "host") == 0)
314 : 30 : host = g_hash_table_lookup (key_value_pairs, key);
315 : 36 : else if (g_strcmp0 (key, "port") == 0)
316 : 22 : port = g_hash_table_lookup (key_value_pairs, key);
317 : 14 : else if (g_strcmp0 (key, "family") == 0)
318 : 8 : family = g_hash_table_lookup (key_value_pairs, key);
319 : 6 : else if (g_strcmp0 (key, "guid") != 0)
320 : : {
321 : 2 : g_set_error (error,
322 : : G_IO_ERROR,
323 : : G_IO_ERROR_INVALID_ARGUMENT,
324 : : _("Unsupported key “%s” in address entry “%s”"),
325 : : key,
326 : : address_entry);
327 : 2 : goto out;
328 : : }
329 : : }
330 : :
331 : 32 : if (port != NULL)
332 : : {
333 : 22 : port_num = strtol (port, &endp, 10);
334 : 22 : if ((*port == '\0' || *endp != '\0') || port_num < 0 || port_num >= 65536)
335 : : {
336 : 8 : g_set_error (error,
337 : : G_IO_ERROR,
338 : : G_IO_ERROR_INVALID_ARGUMENT,
339 : : _("Error in address “%s” — the “%s” attribute is malformed"),
340 : : address_entry, "port");
341 : 8 : goto out;
342 : : }
343 : : }
344 : :
345 : 24 : if (family != NULL && !(g_strcmp0 (family, "ipv4") == 0 || g_strcmp0 (family, "ipv6") == 0))
346 : : {
347 : 4 : g_set_error (error,
348 : : G_IO_ERROR,
349 : : G_IO_ERROR_INVALID_ARGUMENT,
350 : : _("Error in address “%s” — the “%s” attribute is malformed"),
351 : : address_entry, "family");
352 : 4 : goto out;
353 : : }
354 : :
355 : : if (host != NULL)
356 : : {
357 : : /* TODO: validate host */
358 : : }
359 : :
360 : 20 : ret= TRUE;
361 : :
362 : 34 : out:
363 : 34 : g_ptr_array_unref (keys);
364 : :
365 : 34 : return ret;
366 : : }
367 : :
368 : : /**
369 : : * g_dbus_is_supported_address:
370 : : * @string: A string.
371 : : * @error: Return location for error or %NULL.
372 : : *
373 : : * Like g_dbus_is_address() but also checks if the library supports the
374 : : * transports in @string and that key/value pairs for each transport
375 : : * are valid. See the specification of the
376 : : * [D-Bus address format](https://dbus.freedesktop.org/doc/dbus-specification.html#addresses).
377 : : *
378 : : * Returns: %TRUE if @string is a valid D-Bus address that is
379 : : * supported by this library, %FALSE if @error is set.
380 : : *
381 : : * Since: 2.26
382 : : */
383 : : gboolean
384 : 128 : g_dbus_is_supported_address (const gchar *string,
385 : : GError **error)
386 : : {
387 : : guint n;
388 : : gchar **a;
389 : : gboolean ret;
390 : :
391 : 128 : ret = FALSE;
392 : :
393 : 128 : g_return_val_if_fail (string != NULL, FALSE);
394 : 128 : g_return_val_if_fail (error == NULL || *error == NULL, FALSE);
395 : :
396 : 128 : a = g_strsplit (string, ";", 0);
397 : 205 : for (n = 0; a[n] != NULL; n++)
398 : : {
399 : : gchar *transport_name;
400 : : GHashTable *key_value_pairs;
401 : : gboolean supported;
402 : :
403 : 136 : if (!_g_dbus_address_parse_entry (a[n],
404 : : &transport_name,
405 : : &key_value_pairs,
406 : : error))
407 : 59 : goto out;
408 : :
409 : 135 : supported = FALSE;
410 : 135 : if (g_strcmp0 (transport_name, "unix") == 0)
411 : 56 : supported = is_valid_unix (a[n], key_value_pairs, error);
412 : 79 : else if (g_strcmp0 (transport_name, "tcp") == 0)
413 : 34 : supported = is_valid_tcp (a[n], key_value_pairs, error);
414 : 45 : else if (g_strcmp0 (transport_name, "nonce-tcp") == 0)
415 : 35 : supported = is_valid_nonce_tcp (a[n], key_value_pairs, error);
416 : 10 : else if (g_strcmp0 (a[n], "autolaunch:") == 0)
417 : 4 : supported = TRUE;
418 : : else
419 : 6 : g_set_error (error, G_IO_ERROR, G_IO_ERROR_INVALID_ARGUMENT,
420 : : _("Unknown or unsupported transport “%s” for address “%s”"),
421 : 6 : transport_name, a[n]);
422 : :
423 : 135 : g_free (transport_name);
424 : 135 : g_hash_table_unref (key_value_pairs);
425 : :
426 : 135 : if (!supported)
427 : 58 : goto out;
428 : : }
429 : :
430 : 69 : ret = TRUE;
431 : :
432 : 128 : out:
433 : 128 : g_strfreev (a);
434 : :
435 : 128 : g_assert (ret || (!ret && (error == NULL || *error != NULL)));
436 : :
437 : 128 : return ret;
438 : : }
439 : :
440 : : gboolean
441 : 1855 : _g_dbus_address_parse_entry (const gchar *address_entry,
442 : : gchar **out_transport_name,
443 : : GHashTable **out_key_value_pairs,
444 : : GError **error)
445 : : {
446 : : gboolean ret;
447 : : GHashTable *key_value_pairs;
448 : : gchar *transport_name;
449 : : gchar **kv_pairs;
450 : : const gchar *s;
451 : : guint n;
452 : :
453 : 1855 : ret = FALSE;
454 : 1855 : kv_pairs = NULL;
455 : 1855 : transport_name = NULL;
456 : 1855 : key_value_pairs = NULL;
457 : :
458 : 1855 : s = strchr (address_entry, ':');
459 : 1855 : if (s == NULL)
460 : : {
461 : 4 : g_set_error (error,
462 : : G_IO_ERROR,
463 : : G_IO_ERROR_INVALID_ARGUMENT,
464 : : _("Address element “%s” does not contain a colon (:)"),
465 : : address_entry);
466 : 4 : goto out;
467 : : }
468 : 1851 : else if (s == address_entry)
469 : : {
470 : 2 : g_set_error (error,
471 : : G_IO_ERROR,
472 : : G_IO_ERROR_INVALID_ARGUMENT,
473 : : _("Transport name in address element “%s” must not be empty"),
474 : : address_entry);
475 : 2 : goto out;
476 : : }
477 : :
478 : 1849 : transport_name = g_strndup (address_entry, s - address_entry);
479 : 1849 : key_value_pairs = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, g_free);
480 : :
481 : 1849 : kv_pairs = g_strsplit (s + 1, ",", 0);
482 : 5430 : for (n = 0; kv_pairs[n] != NULL; n++)
483 : : {
484 : 3586 : const gchar *kv_pair = kv_pairs[n];
485 : : gchar *key;
486 : : gchar *value;
487 : :
488 : 3586 : s = strchr (kv_pair, '=');
489 : 3586 : if (s == NULL)
490 : : {
491 : 1 : g_set_error (error,
492 : : G_IO_ERROR,
493 : : G_IO_ERROR_INVALID_ARGUMENT,
494 : : _("Key/Value pair %d, “%s”, in address element “%s” does not contain an equal sign"),
495 : : n,
496 : : kv_pair,
497 : : address_entry);
498 : 1 : goto out;
499 : : }
500 : 3585 : else if (s == kv_pair)
501 : : {
502 : 2 : g_set_error (error,
503 : : G_IO_ERROR,
504 : : G_IO_ERROR_INVALID_ARGUMENT,
505 : : _("Key/Value pair %d, “%s”, in address element “%s” must not have an empty key"),
506 : : n,
507 : : kv_pair,
508 : : address_entry);
509 : 2 : goto out;
510 : : }
511 : :
512 : 3583 : key = g_uri_unescape_segment (kv_pair, s, NULL);
513 : 3583 : value = g_uri_unescape_segment (s + 1, kv_pair + strlen (kv_pair), NULL);
514 : 3583 : if (key == NULL || value == NULL)
515 : : {
516 : 2 : g_set_error (error,
517 : : G_IO_ERROR,
518 : : G_IO_ERROR_INVALID_ARGUMENT,
519 : : _("Error unescaping key or value in Key/Value pair %d, “%s”, in address element “%s”"),
520 : : n,
521 : : kv_pair,
522 : : address_entry);
523 : 2 : g_free (key);
524 : 2 : g_free (value);
525 : 2 : goto out;
526 : : }
527 : 3581 : g_hash_table_insert (key_value_pairs, key, value);
528 : : }
529 : :
530 : 1844 : ret = TRUE;
531 : :
532 : 1855 : out:
533 : 1855 : if (ret)
534 : : {
535 : 1844 : if (out_transport_name != NULL)
536 : 1785 : *out_transport_name = g_steal_pointer (&transport_name);
537 : 1844 : if (out_key_value_pairs != NULL)
538 : 1785 : *out_key_value_pairs = g_steal_pointer (&key_value_pairs);
539 : : }
540 : :
541 : 1855 : g_clear_pointer (&key_value_pairs, g_hash_table_unref);
542 : 1855 : g_free (transport_name);
543 : 1855 : g_strfreev (kv_pairs);
544 : :
545 : 1855 : return ret;
546 : : }
547 : :
548 : : /* ---------------------------------------------------------------------------------------------------- */
549 : :
550 : : static GIOStream *
551 : : g_dbus_address_try_connect_one (const gchar *address_entry,
552 : : gchar **out_guid,
553 : : GCancellable *cancellable,
554 : : GError **error);
555 : :
556 : : /* TODO: Declare an extension point called GDBusTransport (or similar)
557 : : * and move code below to extensions implementing said extension
558 : : * point. That way we can implement a D-Bus transport over X11 without
559 : : * making libgio link to libX11...
560 : : */
561 : : static GIOStream *
562 : 1625 : g_dbus_address_connect (const gchar *address_entry,
563 : : const gchar *transport_name,
564 : : GHashTable *key_value_pairs,
565 : : GCancellable *cancellable,
566 : : GError **error)
567 : : {
568 : : GIOStream *ret;
569 : : GSocketConnectable *connectable;
570 : : const gchar *nonce_file;
571 : :
572 : 1625 : connectable = NULL;
573 : 1625 : ret = NULL;
574 : 1625 : nonce_file = NULL;
575 : :
576 : 1625 : if (g_strcmp0 (transport_name, "unix") == 0)
577 : : {
578 : : const gchar *path;
579 : : const gchar *abstract;
580 : 1617 : path = g_hash_table_lookup (key_value_pairs, "path");
581 : 1617 : abstract = g_hash_table_lookup (key_value_pairs, "abstract");
582 : 1617 : if ((path == NULL && abstract == NULL) || (path != NULL && abstract != NULL))
583 : : {
584 : 0 : g_set_error (error,
585 : : G_IO_ERROR,
586 : : G_IO_ERROR_INVALID_ARGUMENT,
587 : : _("Error in address “%s” — the unix transport requires exactly one of the "
588 : : "keys “path” or “abstract” to be set"),
589 : : address_entry);
590 : : }
591 : 1617 : else if (path != NULL)
592 : : {
593 : 1617 : connectable = G_SOCKET_CONNECTABLE (g_unix_socket_address_new (path));
594 : : }
595 : 0 : else if (abstract != NULL)
596 : : {
597 : 0 : connectable = G_SOCKET_CONNECTABLE (g_unix_socket_address_new_with_type (abstract,
598 : : -1,
599 : : G_UNIX_SOCKET_ADDRESS_ABSTRACT));
600 : : }
601 : : else
602 : : {
603 : : g_assert_not_reached ();
604 : : }
605 : : }
606 : 8 : else if (g_strcmp0 (transport_name, "tcp") == 0 || g_strcmp0 (transport_name, "nonce-tcp") == 0)
607 : 8 : {
608 : : const gchar *s;
609 : : const gchar *host;
610 : : glong port;
611 : : gchar *endp;
612 : : gboolean is_nonce;
613 : :
614 : 8 : is_nonce = (g_strcmp0 (transport_name, "nonce-tcp") == 0);
615 : :
616 : 8 : host = g_hash_table_lookup (key_value_pairs, "host");
617 : 8 : if (host == NULL)
618 : : {
619 : 0 : g_set_error (error,
620 : : G_IO_ERROR,
621 : : G_IO_ERROR_INVALID_ARGUMENT,
622 : : /* Translators: The first placeholder is a D-Bus connection address,
623 : : * the second is the literal name of an attribute in the address.
624 : : */
625 : : _("Error in address “%s” — the %s attribute is missing or malformed"),
626 : : address_entry,
627 : : "host");
628 : 0 : goto out;
629 : : }
630 : :
631 : 8 : s = g_hash_table_lookup (key_value_pairs, "port");
632 : 8 : if (s == NULL)
633 : 0 : s = "0";
634 : 8 : port = strtol (s, &endp, 10);
635 : 8 : if ((*s == '\0' || *endp != '\0') || port < 0 || port >= 65536)
636 : : {
637 : 0 : g_set_error (error,
638 : : G_IO_ERROR,
639 : : G_IO_ERROR_INVALID_ARGUMENT,
640 : : _("Error in address “%s” — the %s attribute is missing or malformed"),
641 : : address_entry,
642 : : "port");
643 : 0 : goto out;
644 : : }
645 : :
646 : :
647 : 8 : if (is_nonce)
648 : : {
649 : 4 : nonce_file = g_hash_table_lookup (key_value_pairs, "noncefile");
650 : 4 : if (nonce_file == NULL)
651 : : {
652 : 0 : g_set_error (error,
653 : : G_IO_ERROR,
654 : : G_IO_ERROR_INVALID_ARGUMENT,
655 : : _("Error in address “%s” — the %s attribute is missing or malformed"),
656 : : address_entry,
657 : : "noncefile");
658 : 0 : goto out;
659 : : }
660 : : }
661 : :
662 : : /* TODO: deal with family key/value-pair */
663 : 8 : connectable = g_network_address_new (host, port);
664 : : }
665 : 0 : else if (g_strcmp0 (address_entry, "autolaunch:") == 0)
666 : : {
667 : : gchar *autolaunch_address;
668 : 0 : autolaunch_address = get_session_address_dbus_launch (error);
669 : 0 : if (autolaunch_address != NULL)
670 : : {
671 : 0 : ret = g_dbus_address_try_connect_one (autolaunch_address, NULL, cancellable, error);
672 : 0 : g_free (autolaunch_address);
673 : 0 : goto out;
674 : : }
675 : : else
676 : : {
677 : 0 : g_prefix_error (error, _("Error auto-launching: "));
678 : : }
679 : : }
680 : : else
681 : : {
682 : 0 : g_set_error (error,
683 : : G_IO_ERROR,
684 : : G_IO_ERROR_INVALID_ARGUMENT,
685 : : _("Unknown or unsupported transport “%s” for address “%s”"),
686 : : transport_name,
687 : : address_entry);
688 : : }
689 : :
690 : 1625 : if (connectable != NULL)
691 : : {
692 : : GSocketClient *client;
693 : : GSocketConnection *connection;
694 : :
695 : 1625 : g_assert (ret == NULL);
696 : 1625 : client = g_socket_client_new ();
697 : :
698 : : /* Disable proxy support to prevent a deadlock on startup, since loading a
699 : : * proxy resolver causes the GIO modules to be loaded, and there will
700 : : * almost certainly be one of them which then tries to use GDBus.
701 : : * See: https://bugzilla.gnome.org/show_bug.cgi?id=792499 */
702 : 1625 : g_socket_client_set_enable_proxy (client, FALSE);
703 : :
704 : 1625 : connection = g_socket_client_connect (client,
705 : : connectable,
706 : : cancellable,
707 : : error);
708 : 1625 : g_object_unref (connectable);
709 : 1625 : g_object_unref (client);
710 : 1625 : if (connection == NULL)
711 : 26 : goto out;
712 : :
713 : 1599 : ret = G_IO_STREAM (connection);
714 : :
715 : 1599 : if (nonce_file != NULL)
716 : : {
717 : : gchar nonce_contents[16 + 1];
718 : : size_t num_bytes_read;
719 : : FILE *f;
720 : : int errsv;
721 : :
722 : : /* be careful to read only 16 bytes - we also check that the file is only 16 bytes long */
723 : 4 : f = fopen (nonce_file, "rb" FO_CLOEXEC);
724 : 4 : errsv = errno;
725 : 4 : if (f == NULL)
726 : : {
727 : 1 : g_set_error (error,
728 : : G_IO_ERROR,
729 : : G_IO_ERROR_INVALID_ARGUMENT,
730 : : _("Error opening nonce file “%s”: %s"),
731 : : nonce_file,
732 : : g_strerror (errsv));
733 : 1 : g_object_unref (ret);
734 : 1 : ret = NULL;
735 : 2 : goto out;
736 : : }
737 : 3 : num_bytes_read = fread (nonce_contents,
738 : : sizeof (gchar),
739 : : 16 + 1,
740 : : f);
741 : 3 : errsv = errno;
742 : 3 : if (num_bytes_read != 16)
743 : : {
744 : 1 : if (num_bytes_read == 0)
745 : : {
746 : 0 : g_set_error (error,
747 : : G_IO_ERROR,
748 : : G_IO_ERROR_INVALID_ARGUMENT,
749 : : _("Error reading from nonce file “%s”: %s"),
750 : : nonce_file,
751 : : g_strerror (errsv));
752 : : }
753 : : else
754 : : {
755 : 1 : g_set_error (error,
756 : : G_IO_ERROR,
757 : : G_IO_ERROR_INVALID_ARGUMENT,
758 : : _("Error reading from nonce file “%s”, expected 16 bytes, got %d"),
759 : : nonce_file,
760 : : (gint) num_bytes_read);
761 : : }
762 : 1 : g_object_unref (ret);
763 : 1 : ret = NULL;
764 : 1 : fclose (f);
765 : 1 : goto out;
766 : : }
767 : 2 : fclose (f);
768 : :
769 : 2 : if (!g_output_stream_write_all (g_io_stream_get_output_stream (ret),
770 : : nonce_contents,
771 : : 16,
772 : : NULL,
773 : : cancellable,
774 : : error))
775 : : {
776 : 0 : g_prefix_error (error, _("Error writing contents of nonce file “%s” to stream:"), nonce_file);
777 : 0 : g_object_unref (ret);
778 : 0 : ret = NULL;
779 : 0 : goto out;
780 : : }
781 : : }
782 : : }
783 : :
784 : 1595 : out:
785 : :
786 : 1625 : return ret;
787 : : }
788 : :
789 : : static GIOStream *
790 : 1625 : g_dbus_address_try_connect_one (const gchar *address_entry,
791 : : gchar **out_guid,
792 : : GCancellable *cancellable,
793 : : GError **error)
794 : : {
795 : : GIOStream *ret;
796 : : GHashTable *key_value_pairs;
797 : : gchar *transport_name;
798 : : const gchar *guid;
799 : :
800 : 1625 : ret = NULL;
801 : 1625 : transport_name = NULL;
802 : 1625 : key_value_pairs = NULL;
803 : :
804 : 1625 : if (!_g_dbus_address_parse_entry (address_entry,
805 : : &transport_name,
806 : : &key_value_pairs,
807 : : error))
808 : 0 : goto out;
809 : :
810 : 1625 : ret = g_dbus_address_connect (address_entry,
811 : : transport_name,
812 : : key_value_pairs,
813 : : cancellable,
814 : : error);
815 : 1625 : if (ret == NULL)
816 : 28 : goto out;
817 : :
818 : 1597 : guid = g_hash_table_lookup (key_value_pairs, "guid");
819 : 1597 : if (guid != NULL && out_guid != NULL)
820 : 0 : *out_guid = g_strdup (guid);
821 : :
822 : 1597 : out:
823 : 1625 : g_free (transport_name);
824 : 1625 : if (key_value_pairs != NULL)
825 : 1625 : g_hash_table_unref (key_value_pairs);
826 : 1625 : return ret;
827 : : }
828 : :
829 : :
830 : : /* ---------------------------------------------------------------------------------------------------- */
831 : :
832 : : typedef struct {
833 : : gchar *address;
834 : : gchar *guid;
835 : : } GetStreamData;
836 : :
837 : : static void
838 : 0 : get_stream_data_free (GetStreamData *data)
839 : : {
840 : 0 : g_free (data->address);
841 : 0 : g_free (data->guid);
842 : 0 : g_free (data);
843 : 0 : }
844 : :
845 : : static void
846 : 0 : get_stream_thread_func (GTask *task,
847 : : gpointer source_object,
848 : : gpointer task_data,
849 : : GCancellable *cancellable)
850 : : {
851 : 0 : GetStreamData *data = task_data;
852 : : GIOStream *stream;
853 : 0 : GError *error = NULL;
854 : :
855 : 0 : stream = g_dbus_address_get_stream_sync (data->address,
856 : : &data->guid,
857 : : cancellable,
858 : : &error);
859 : 0 : if (stream)
860 : 0 : g_task_return_pointer (task, stream, g_object_unref);
861 : : else
862 : 0 : g_task_return_error (task, error);
863 : 0 : }
864 : :
865 : : /**
866 : : * g_dbus_address_get_stream:
867 : : * @address: A valid D-Bus address.
868 : : * @cancellable: (nullable): A #GCancellable or %NULL.
869 : : * @callback: A #GAsyncReadyCallback to call when the request is satisfied.
870 : : * @user_data: Data to pass to @callback.
871 : : *
872 : : * Asynchronously connects to an endpoint specified by @address and
873 : : * sets up the connection so it is in a state to run the client-side
874 : : * of the D-Bus authentication conversation. @address must be in the
875 : : * [D-Bus address format](https://dbus.freedesktop.org/doc/dbus-specification.html#addresses).
876 : : *
877 : : * When the operation is finished, @callback will be invoked. You can
878 : : * then call g_dbus_address_get_stream_finish() to get the result of
879 : : * the operation.
880 : : *
881 : : * This is an asynchronous failable function. See
882 : : * g_dbus_address_get_stream_sync() for the synchronous version.
883 : : *
884 : : * Since: 2.26
885 : : */
886 : : void
887 : 0 : g_dbus_address_get_stream (const gchar *address,
888 : : GCancellable *cancellable,
889 : : GAsyncReadyCallback callback,
890 : : gpointer user_data)
891 : : {
892 : : GTask *task;
893 : : GetStreamData *data;
894 : :
895 : 0 : g_return_if_fail (address != NULL);
896 : :
897 : 0 : data = g_new0 (GetStreamData, 1);
898 : 0 : data->address = g_strdup (address);
899 : :
900 : 0 : task = g_task_new (NULL, cancellable, callback, user_data);
901 : 0 : g_task_set_source_tag (task, g_dbus_address_get_stream);
902 : 0 : g_task_set_task_data (task, data, (GDestroyNotify) get_stream_data_free);
903 : 0 : g_task_run_in_thread (task, get_stream_thread_func);
904 : 0 : g_object_unref (task);
905 : : }
906 : :
907 : : /**
908 : : * g_dbus_address_get_stream_finish:
909 : : * @res: A #GAsyncResult obtained from the GAsyncReadyCallback passed to g_dbus_address_get_stream().
910 : : * @out_guid: (optional) (out) (nullable): %NULL or return location to store the GUID extracted from @address, if any.
911 : : * @error: Return location for error or %NULL.
912 : : *
913 : : * Finishes an operation started with g_dbus_address_get_stream().
914 : : *
915 : : * A server is not required to set a GUID, so @out_guid may be set to %NULL
916 : : * even on success.
917 : : *
918 : : * Returns: (transfer full): A #GIOStream or %NULL if @error is set.
919 : : *
920 : : * Since: 2.26
921 : : */
922 : : GIOStream *
923 : 0 : g_dbus_address_get_stream_finish (GAsyncResult *res,
924 : : gchar **out_guid,
925 : : GError **error)
926 : : {
927 : : GTask *task;
928 : : GetStreamData *data;
929 : : GIOStream *ret;
930 : :
931 : 0 : g_return_val_if_fail (g_task_is_valid (res, NULL), NULL);
932 : 0 : g_return_val_if_fail (error == NULL || *error == NULL, NULL);
933 : :
934 : 0 : task = G_TASK (res);
935 : 0 : ret = g_task_propagate_pointer (task, error);
936 : :
937 : 0 : if (ret != NULL && out_guid != NULL)
938 : : {
939 : 0 : data = g_task_get_task_data (task);
940 : 0 : *out_guid = data->guid;
941 : 0 : data->guid = NULL;
942 : : }
943 : :
944 : 0 : return ret;
945 : : }
946 : :
947 : : /**
948 : : * g_dbus_address_get_stream_sync:
949 : : * @address: A valid D-Bus address.
950 : : * @out_guid: (optional) (out) (nullable): %NULL or return location to store the GUID extracted from @address, if any.
951 : : * @cancellable: (nullable): A #GCancellable or %NULL.
952 : : * @error: Return location for error or %NULL.
953 : : *
954 : : * Synchronously connects to an endpoint specified by @address and
955 : : * sets up the connection so it is in a state to run the client-side
956 : : * of the D-Bus authentication conversation. @address must be in the
957 : : * [D-Bus address format](https://dbus.freedesktop.org/doc/dbus-specification.html#addresses).
958 : : *
959 : : * A server is not required to set a GUID, so @out_guid may be set to %NULL
960 : : * even on success.
961 : : *
962 : : * This is a synchronous failable function. See
963 : : * g_dbus_address_get_stream() for the asynchronous version.
964 : : *
965 : : * Returns: (transfer full): A #GIOStream or %NULL if @error is set.
966 : : *
967 : : * Since: 2.26
968 : : */
969 : : GIOStream *
970 : 1626 : g_dbus_address_get_stream_sync (const gchar *address,
971 : : gchar **out_guid,
972 : : GCancellable *cancellable,
973 : : GError **error)
974 : : {
975 : : GIOStream *ret;
976 : : gchar **addr_array;
977 : : guint n;
978 : : GError *last_error;
979 : :
980 : 1626 : g_return_val_if_fail (address != NULL, NULL);
981 : 1626 : g_return_val_if_fail (error == NULL || *error == NULL, NULL);
982 : :
983 : 1626 : ret = NULL;
984 : 1626 : last_error = NULL;
985 : :
986 : 1626 : addr_array = g_strsplit (address, ";", 0);
987 : 1626 : if (addr_array[0] == NULL)
988 : : {
989 : 1 : last_error = g_error_new_literal (G_IO_ERROR,
990 : : G_IO_ERROR_INVALID_ARGUMENT,
991 : : _("The given address is empty"));
992 : 1 : goto out;
993 : : }
994 : :
995 : 1653 : for (n = 0; addr_array[n] != NULL; n++)
996 : : {
997 : 1625 : const gchar *addr = addr_array[n];
998 : : GError *this_error;
999 : :
1000 : 1625 : this_error = NULL;
1001 : 1625 : ret = g_dbus_address_try_connect_one (addr,
1002 : : out_guid,
1003 : : cancellable,
1004 : : &this_error);
1005 : 1625 : if (ret != NULL)
1006 : : {
1007 : 1597 : goto out;
1008 : : }
1009 : : else
1010 : : {
1011 : 28 : g_assert (this_error != NULL);
1012 : 28 : if (last_error != NULL)
1013 : 0 : g_error_free (last_error);
1014 : 28 : last_error = this_error;
1015 : : }
1016 : : }
1017 : :
1018 : 28 : out:
1019 : 1626 : if (ret != NULL)
1020 : : {
1021 : 1597 : if (last_error != NULL)
1022 : 0 : g_error_free (last_error);
1023 : : }
1024 : : else
1025 : : {
1026 : 29 : g_assert (last_error != NULL);
1027 : 29 : g_propagate_error (error, last_error);
1028 : : }
1029 : :
1030 : 1626 : g_strfreev (addr_array);
1031 : 1626 : return ret;
1032 : : }
1033 : :
1034 : : /* ---------------------------------------------------------------------------------------------------- */
1035 : :
1036 : : /*
1037 : : * Return the address of XDG_RUNTIME_DIR/bus if it exists, belongs to
1038 : : * us, and is a socket, and we are on Unix.
1039 : : */
1040 : : static gchar *
1041 : 61 : get_session_address_xdg (void)
1042 : : {
1043 : : #ifdef G_OS_UNIX
1044 : 61 : gchar *ret = NULL;
1045 : : gchar *bus;
1046 : : gchar *tmp;
1047 : : GStatBuf buf;
1048 : :
1049 : 61 : bus = g_build_filename (g_get_user_runtime_dir (), "bus", NULL);
1050 : :
1051 : : /* if ENOENT, EPERM, etc., quietly don't use it */
1052 : 61 : if (g_stat (bus, &buf) < 0)
1053 : 60 : goto out;
1054 : :
1055 : : /* if it isn't ours, we have incorrectly inherited someone else's
1056 : : * XDG_RUNTIME_DIR; silently don't use it
1057 : : */
1058 : 1 : if (buf.st_uid != geteuid ())
1059 : 0 : goto out;
1060 : :
1061 : : /* if it isn't a socket, silently don't use it */
1062 : 1 : if ((buf.st_mode & S_IFMT) != S_IFSOCK)
1063 : 0 : goto out;
1064 : :
1065 : 1 : tmp = g_dbus_address_escape_value (bus);
1066 : 1 : ret = g_strconcat ("unix:path=", tmp, NULL);
1067 : 1 : g_free (tmp);
1068 : :
1069 : 61 : out:
1070 : 61 : g_free (bus);
1071 : 61 : return ret;
1072 : : #else
1073 : : return NULL;
1074 : : #endif
1075 : : }
1076 : :
1077 : : /* ---------------------------------------------------------------------------------------------------- */
1078 : :
1079 : : #ifdef G_OS_UNIX
1080 : : static gchar *
1081 : 60 : get_session_address_dbus_launch (GError **error)
1082 : : {
1083 : : gchar *ret;
1084 : : gchar *machine_id;
1085 : : gchar *command_line;
1086 : : gchar *launch_stdout;
1087 : : gchar *launch_stderr;
1088 : : gint wait_status;
1089 : : gchar *old_dbus_verbose;
1090 : : gboolean restore_dbus_verbose;
1091 : :
1092 : 60 : ret = NULL;
1093 : 60 : machine_id = NULL;
1094 : 60 : command_line = NULL;
1095 : 60 : launch_stdout = NULL;
1096 : 60 : launch_stderr = NULL;
1097 : 60 : restore_dbus_verbose = FALSE;
1098 : 60 : old_dbus_verbose = NULL;
1099 : :
1100 : : /* Don't run binaries as root if we're setuid. */
1101 : 60 : if (GLIB_PRIVATE_CALL (g_check_setuid) ())
1102 : : {
1103 : 0 : g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED,
1104 : : _("Cannot spawn a message bus when AT_SECURE is set"));
1105 : 0 : goto out;
1106 : : }
1107 : :
1108 : 60 : machine_id = _g_dbus_get_machine_id (error);
1109 : 60 : if (machine_id == NULL)
1110 : : {
1111 : 0 : g_prefix_error (error, _("Cannot spawn a message bus without a machine-id: "));
1112 : 0 : goto out;
1113 : : }
1114 : :
1115 : 60 : if (g_getenv ("DISPLAY") == NULL)
1116 : : {
1117 : 59 : g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED,
1118 : : _("Cannot autolaunch D-Bus without X11 $DISPLAY"));
1119 : 59 : goto out;
1120 : : }
1121 : :
1122 : : /* We're using private libdbus facilities here. When everything
1123 : : * (X11, Mac OS X, Windows) is spec'ed out correctly (not even the
1124 : : * X11 property is correctly documented right now) we should
1125 : : * consider using the spec instead of dbus-launch.
1126 : : *
1127 : : * --autolaunch=MACHINEID
1128 : : * This option implies that dbus-launch should scan for a previ‐
1129 : : * ously-started session and reuse the values found there. If no
1130 : : * session is found, it will start a new session. The --exit-with-
1131 : : * session option is implied if --autolaunch is given. This option
1132 : : * is for the exclusive use of libdbus, you do not want to use it
1133 : : * manually. It may change in the future.
1134 : : */
1135 : :
1136 : : /* TODO: maybe provide a variable for where to look for the dbus-launch binary? */
1137 : 1 : command_line = g_strdup_printf ("dbus-launch --autolaunch=%s --binary-syntax --close-stderr", machine_id);
1138 : :
1139 : 1 : if (G_UNLIKELY (_g_dbus_debug_address ()))
1140 : : {
1141 : 0 : _g_dbus_debug_print_lock ();
1142 : 0 : g_print ("GDBus-debug:Address: Running '%s' to get bus address (possibly autolaunching)\n", command_line);
1143 : 0 : old_dbus_verbose = g_strdup (g_getenv ("DBUS_VERBOSE"));
1144 : 0 : restore_dbus_verbose = TRUE;
1145 : 0 : g_setenv ("DBUS_VERBOSE", "1", TRUE);
1146 : 0 : _g_dbus_debug_print_unlock ();
1147 : : }
1148 : :
1149 : 1 : if (!g_spawn_command_line_sync (command_line,
1150 : : &launch_stdout,
1151 : : &launch_stderr,
1152 : : &wait_status,
1153 : : error))
1154 : : {
1155 : 0 : goto out;
1156 : : }
1157 : :
1158 : 1 : if (!g_spawn_check_wait_status (wait_status, error))
1159 : : {
1160 : 0 : g_prefix_error (error, _("Error spawning command line “%s”: "), command_line);
1161 : 0 : goto out;
1162 : : }
1163 : :
1164 : : /* From the dbus-launch(1) man page:
1165 : : *
1166 : : * --binary-syntax Write to stdout a nul-terminated bus address,
1167 : : * then the bus PID as a binary integer of size sizeof(pid_t),
1168 : : * then the bus X window ID as a binary integer of size
1169 : : * sizeof(long). Integers are in the machine's byte order, not
1170 : : * network byte order or any other canonical byte order.
1171 : : */
1172 : 2 : ret = g_strdup (launch_stdout);
1173 : :
1174 : 60 : out:
1175 : 60 : if (G_UNLIKELY (_g_dbus_debug_address ()))
1176 : : {
1177 : : gchar *s;
1178 : 0 : _g_dbus_debug_print_lock ();
1179 : 0 : g_print ("GDBus-debug:Address: dbus-launch output:");
1180 : 0 : if (launch_stdout != NULL)
1181 : : {
1182 : 0 : s = _g_dbus_hexdump (launch_stdout, strlen (launch_stdout) + 1 + sizeof (pid_t) + sizeof (long), 2);
1183 : 0 : g_print ("\n%s", s);
1184 : 0 : g_free (s);
1185 : : }
1186 : : else
1187 : : {
1188 : 0 : g_print (" (none)\n");
1189 : : }
1190 : 0 : g_print ("GDBus-debug:Address: dbus-launch stderr output:");
1191 : 0 : if (launch_stderr != NULL)
1192 : 0 : g_print ("\n%s", launch_stderr);
1193 : : else
1194 : 0 : g_print (" (none)\n");
1195 : 0 : _g_dbus_debug_print_unlock ();
1196 : : }
1197 : :
1198 : 60 : g_free (machine_id);
1199 : 60 : g_free (command_line);
1200 : 60 : g_free (launch_stdout);
1201 : 60 : g_free (launch_stderr);
1202 : 60 : if (G_UNLIKELY (restore_dbus_verbose))
1203 : : {
1204 : 0 : if (old_dbus_verbose != NULL)
1205 : 0 : g_setenv ("DBUS_VERBOSE", old_dbus_verbose, TRUE);
1206 : : else
1207 : 0 : g_unsetenv ("DBUS_VERBOSE");
1208 : : }
1209 : 60 : g_free (old_dbus_verbose);
1210 : 60 : return ret;
1211 : : }
1212 : :
1213 : : /* end of G_OS_UNIX case */
1214 : : #elif defined(G_OS_WIN32)
1215 : :
1216 : : static gchar *
1217 : : get_session_address_dbus_launch (GError **error)
1218 : : {
1219 : : return _g_dbus_win32_get_session_address_dbus_launch (error);
1220 : : }
1221 : :
1222 : : #else /* neither G_OS_UNIX nor G_OS_WIN32 */
1223 : : static gchar *
1224 : : get_session_address_dbus_launch (GError **error)
1225 : : {
1226 : : g_set_error (error,
1227 : : G_IO_ERROR,
1228 : : G_IO_ERROR_FAILED,
1229 : : _("Cannot determine session bus address (not implemented for this OS)"));
1230 : : return NULL;
1231 : : }
1232 : : #endif /* neither G_OS_UNIX nor G_OS_WIN32 */
1233 : :
1234 : : /* ---------------------------------------------------------------------------------------------------- */
1235 : :
1236 : : static gchar *
1237 : 61 : get_session_address_platform_specific (GError **error)
1238 : : {
1239 : : gchar *ret;
1240 : :
1241 : : /* Use XDG_RUNTIME_DIR/bus if it exists and is suitable. This is appropriate
1242 : : * for systems using the "a session is a user-session" model described in
1243 : : * <http://lists.freedesktop.org/archives/dbus/2015-January/016522.html>,
1244 : : * and implemented in dbus >= 1.9.14 and sd-bus.
1245 : : *
1246 : : * On systems following the more traditional "a session is a login-session"
1247 : : * model, this will fail and we'll fall through to X11 autolaunching
1248 : : * (dbus-launch) below.
1249 : : */
1250 : 61 : ret = get_session_address_xdg ();
1251 : :
1252 : 61 : if (ret != NULL)
1253 : 1 : return ret;
1254 : :
1255 : : /* TODO (#694472): try launchd on OS X, like
1256 : : * _dbus_lookup_session_address_launchd() does, since
1257 : : * 'dbus-launch --autolaunch' probably won't work there
1258 : : */
1259 : :
1260 : : /* As a last resort, try the "autolaunch:" transport. On Unix this means
1261 : : * X11 autolaunching; on Windows this means a different autolaunching
1262 : : * mechanism based on shared memory.
1263 : : */
1264 : 60 : return get_session_address_dbus_launch (error);
1265 : : }
1266 : :
1267 : : /* ---------------------------------------------------------------------------------------------------- */
1268 : :
1269 : : /**
1270 : : * g_dbus_address_get_for_bus_sync:
1271 : : * @bus_type: a #GBusType
1272 : : * @cancellable: (nullable): a #GCancellable or %NULL
1273 : : * @error: return location for error or %NULL
1274 : : *
1275 : : * Synchronously looks up the D-Bus address for the well-known message
1276 : : * bus instance specified by @bus_type. This may involve using various
1277 : : * platform specific mechanisms.
1278 : : *
1279 : : * The returned address will be in the
1280 : : * [D-Bus address format](https://dbus.freedesktop.org/doc/dbus-specification.html#addresses).
1281 : : *
1282 : : * Returns: (transfer full): a valid D-Bus address string for @bus_type or
1283 : : * %NULL if @error is set
1284 : : *
1285 : : * Since: 2.26
1286 : : */
1287 : : gchar *
1288 : 1639 : g_dbus_address_get_for_bus_sync (GBusType bus_type,
1289 : : GCancellable *cancellable,
1290 : : GError **error)
1291 : : {
1292 : 1639 : gboolean has_elevated_privileges = GLIB_PRIVATE_CALL (g_check_setuid) ();
1293 : 1639 : gchar *ret, *s = NULL;
1294 : : const gchar *starter_bus;
1295 : : GError *local_error;
1296 : :
1297 : 1639 : g_return_val_if_fail (error == NULL || *error == NULL, NULL);
1298 : :
1299 : 1639 : ret = NULL;
1300 : 1639 : local_error = NULL;
1301 : :
1302 : 1639 : if (G_UNLIKELY (_g_dbus_debug_address ()))
1303 : : {
1304 : : guint n;
1305 : 0 : _g_dbus_debug_print_lock ();
1306 : 0 : s = _g_dbus_enum_to_string (G_TYPE_BUS_TYPE, bus_type);
1307 : 0 : g_print ("GDBus-debug:Address: In g_dbus_address_get_for_bus_sync() for bus type '%s'\n",
1308 : : s);
1309 : 0 : g_free (s);
1310 : 0 : for (n = 0; n < 3; n++)
1311 : : {
1312 : : const gchar *k;
1313 : : const gchar *v;
1314 : 0 : switch (n)
1315 : : {
1316 : 0 : case 0: k = "DBUS_SESSION_BUS_ADDRESS"; break;
1317 : 0 : case 1: k = "DBUS_SYSTEM_BUS_ADDRESS"; break;
1318 : 0 : case 2: k = "DBUS_STARTER_BUS_TYPE"; break;
1319 : : default: g_assert_not_reached ();
1320 : : }
1321 : 0 : v = g_getenv (k);
1322 : 0 : g_print ("GDBus-debug:Address: env var %s", k);
1323 : 0 : if (v != NULL)
1324 : 0 : g_print ("='%s'\n", v);
1325 : : else
1326 : 0 : g_print (" is not set\n");
1327 : : }
1328 : 0 : _g_dbus_debug_print_unlock ();
1329 : : }
1330 : :
1331 : : /* Don’t load the addresses from the environment if running as setuid, as they
1332 : : * come from an unprivileged caller. */
1333 : 1639 : switch (bus_type)
1334 : : {
1335 : 23 : case G_BUS_TYPE_SYSTEM:
1336 : 23 : if (has_elevated_privileges)
1337 : 0 : ret = NULL;
1338 : : else
1339 : 46 : ret = g_strdup (g_getenv ("DBUS_SYSTEM_BUS_ADDRESS"));
1340 : :
1341 : 23 : if (ret == NULL)
1342 : : {
1343 : : /* While the D-Bus specification says this must be `/var/run/dbus/system_bus_socket`,
1344 : : * a footnote allows it to use localstatedir:
1345 : : * https://dbus.freedesktop.org/doc/dbus-specification.html#ftn.id-1.13.6.4.3.3
1346 : : * or, on systems where /run is the same as /var/run, runstatedir:
1347 : : * https://gitlab.freedesktop.org/dbus/dbus/-/merge_requests/209 */
1348 : 23 : ret = g_strdup ("unix:path=" GLIB_RUNSTATEDIR "/dbus/system_bus_socket");
1349 : : }
1350 : 23 : break;
1351 : :
1352 : 1616 : case G_BUS_TYPE_SESSION:
1353 : 1616 : if (has_elevated_privileges)
1354 : 0 : ret = NULL;
1355 : : else
1356 : 3232 : ret = g_strdup (g_getenv ("DBUS_SESSION_BUS_ADDRESS"));
1357 : :
1358 : 1616 : if (ret == NULL)
1359 : : {
1360 : 61 : ret = get_session_address_platform_specific (&local_error);
1361 : : }
1362 : 1616 : break;
1363 : :
1364 : 0 : case G_BUS_TYPE_STARTER:
1365 : 0 : starter_bus = g_getenv ("DBUS_STARTER_BUS_TYPE");
1366 : 0 : if (g_strcmp0 (starter_bus, "session") == 0)
1367 : : {
1368 : 0 : ret = g_dbus_address_get_for_bus_sync (G_BUS_TYPE_SESSION, cancellable, &local_error);
1369 : 0 : goto out;
1370 : : }
1371 : 0 : else if (g_strcmp0 (starter_bus, "system") == 0)
1372 : : {
1373 : 0 : ret = g_dbus_address_get_for_bus_sync (G_BUS_TYPE_SYSTEM, cancellable, &local_error);
1374 : 0 : goto out;
1375 : : }
1376 : : else
1377 : : {
1378 : 0 : if (starter_bus != NULL)
1379 : : {
1380 : 0 : g_set_error (&local_error,
1381 : : G_IO_ERROR,
1382 : : G_IO_ERROR_FAILED,
1383 : : _("Cannot determine bus address from DBUS_STARTER_BUS_TYPE environment variable"
1384 : : " — unknown value “%s”"),
1385 : : starter_bus);
1386 : : }
1387 : : else
1388 : : {
1389 : 0 : g_set_error_literal (&local_error,
1390 : : G_IO_ERROR,
1391 : : G_IO_ERROR_FAILED,
1392 : : _("Cannot determine bus address because the DBUS_STARTER_BUS_TYPE environment "
1393 : : "variable is not set"));
1394 : : }
1395 : : }
1396 : 0 : break;
1397 : :
1398 : 0 : default:
1399 : 0 : g_set_error (&local_error,
1400 : : G_IO_ERROR,
1401 : : G_IO_ERROR_FAILED,
1402 : : _("Unknown bus type %d"),
1403 : : bus_type);
1404 : 0 : break;
1405 : : }
1406 : :
1407 : 1639 : out:
1408 : 1639 : if (G_UNLIKELY (_g_dbus_debug_address ()))
1409 : : {
1410 : 0 : _g_dbus_debug_print_lock ();
1411 : 0 : s = _g_dbus_enum_to_string (G_TYPE_BUS_TYPE, bus_type);
1412 : 0 : if (ret != NULL)
1413 : : {
1414 : 0 : g_print ("GDBus-debug:Address: Returning address '%s' for bus type '%s'\n",
1415 : : ret, s);
1416 : : }
1417 : : else
1418 : : {
1419 : 0 : g_print ("GDBus-debug:Address: Cannot look-up address bus type '%s': %s\n",
1420 : 0 : s, local_error ? local_error->message : "");
1421 : : }
1422 : 0 : g_free (s);
1423 : 0 : _g_dbus_debug_print_unlock ();
1424 : : }
1425 : :
1426 : 1639 : if (local_error != NULL)
1427 : 59 : g_propagate_error (error, local_error);
1428 : :
1429 : 1639 : return ret;
1430 : : }
1431 : :
1432 : : /**
1433 : : * g_dbus_address_escape_value:
1434 : : * @string: an unescaped string to be included in a D-Bus address
1435 : : * as the value in a key-value pair
1436 : : *
1437 : : * Escape @string so it can appear in a D-Bus address as the value
1438 : : * part of a key-value pair.
1439 : : *
1440 : : * For instance, if @string is `/run/bus-for-:0`,
1441 : : * this function would return `/run/bus-for-%3A0`,
1442 : : * which could be used in a D-Bus address like
1443 : : * `unix:nonce-tcp:host=127.0.0.1,port=42,noncefile=/run/bus-for-%3A0`.
1444 : : *
1445 : : * Returns: (transfer full): a copy of @string with all
1446 : : * non-optionally-escaped bytes escaped
1447 : : *
1448 : : * Since: 2.36
1449 : : */
1450 : : gchar *
1451 : 35 : g_dbus_address_escape_value (const gchar *string)
1452 : : {
1453 : : GString *s;
1454 : : gsize i;
1455 : :
1456 : 35 : g_return_val_if_fail (string != NULL, NULL);
1457 : :
1458 : : /* There will often not be anything needing escaping at all. */
1459 : 35 : s = g_string_sized_new (strlen (string));
1460 : :
1461 : : /* D-Bus address escaping is mostly the same as URI escaping... */
1462 : 35 : g_string_append_uri_escaped (s, string, "\\/", FALSE);
1463 : :
1464 : : /* ... but '~' is an unreserved character in URIs, but a
1465 : : * non-optionally-escaped character in D-Bus addresses. */
1466 : 1801 : for (i = 0; i < s->len; i++)
1467 : : {
1468 : 1766 : if (G_UNLIKELY (s->str[i] == '~'))
1469 : : {
1470 : 1 : s->str[i] = '%';
1471 : 1 : g_string_insert (s, i + 1, "7E");
1472 : 1 : i += 2;
1473 : : }
1474 : : }
1475 : :
1476 : 35 : return g_string_free (s, FALSE);
1477 : : }
|