Coverage Report

Created: 2018-09-25 13:52

/src/glib/gio/gdbusaddress.c
Line
Count
Source (jump to first uncovered line)
1
/* GDBus - GLib D-Bus Library
2
 *
3
 * Copyright (C) 2008-2010 Red Hat, Inc.
4
 *
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.
9
 *
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.
14
 *
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/>.
17
 *
18
 * Author: David Zeuthen <davidz@redhat.com>
19
 */
20
21
#include "config.h"
22
23
#include <stdlib.h>
24
#include <string.h>
25
#include <stdio.h>
26
#include <errno.h>
27
28
#include "gioerror.h"
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"
37
#include "gtask.h"
38
#include "glib-private.h"
39
#include "gdbusprivate.h"
40
#include "giomodule-priv.h"
41
#include "gdbusdaemon.h"
42
#include "gstdio.h"
43
44
#ifdef G_OS_UNIX
45
#include <unistd.h>
46
#include <sys/stat.h>
47
#include <sys/types.h>
48
#include <gio/gunixsocketaddress.h>
49
#endif
50
51
#ifdef G_OS_WIN32
52
#include <windows.h>
53
#include <io.h>
54
#include <conio.h>
55
#endif
56
57
#include "glibintl.h"
58
59
/**
60
 * SECTION:gdbusaddress
61
 * @title: D-Bus Addresses
62
 * @short_description: D-Bus connection endpoints
63
 * @include: gio/gio.h
64
 *
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).
69
 *
70
 * TCP D-Bus connections are supported, but accessing them via a proxy is
71
 * currently not supported.
72
 */
73
74
static gchar *get_session_address_platform_specific (GError **error);
75
static gchar *get_session_address_dbus_launch       (GError **error);
76
77
/* ---------------------------------------------------------------------------------------------------- */
78
79
/**
80
 * g_dbus_is_address:
81
 * @string: A string.
82
 *
83
 * Checks if @string is a
84
 * [D-Bus address](https://dbus.freedesktop.org/doc/dbus-specification.html#addresses).
85
 *
86
 * This doesn't check if @string is actually supported by #GDBusServer
87
 * or #GDBusConnection - use g_dbus_is_supported_address() to do more
88
 * checks.
89
 *
90
 * Returns: %TRUE if @string is a valid D-Bus address, %FALSE otherwise.
91
 *
92
 * Since: 2.26
93
 */
94
gboolean
95
g_dbus_is_address (const gchar *string)
96
0
{
97
0
  guint n;
98
0
  gchar **a;
99
0
  gboolean ret;
100
0
101
0
  ret = FALSE;
102
0
103
0
  g_return_val_if_fail (string != NULL, FALSE);
104
0
105
0
  a = g_strsplit (string, ";", 0);
106
0
  if (a[0] == NULL)
107
0
    goto out;
108
0
109
0
  for (n = 0; a[n] != NULL; n++)
110
0
    {
111
0
      if (!_g_dbus_address_parse_entry (a[n],
112
0
                                        NULL,
113
0
                                        NULL,
114
0
                                        NULL))
115
0
        goto out;
116
0
    }
117
0
118
0
  ret = TRUE;
119
0
120
0
 out:
121
0
  g_strfreev (a);
122
0
  return ret;
123
0
}
124
125
static gboolean
126
is_valid_unix (const gchar  *address_entry,
127
               GHashTable   *key_value_pairs,
128
               GError      **error)
129
0
{
130
0
  gboolean ret;
131
0
  GList *keys;
132
0
  GList *l;
133
0
  const gchar *path;
134
0
  const gchar *tmpdir;
135
0
  const gchar *abstract;
136
0
137
0
  ret = FALSE;
138
0
  keys = NULL;
139
0
  path = NULL;
140
0
  tmpdir = NULL;
141
0
  abstract = NULL;
142
0
143
0
  keys = g_hash_table_get_keys (key_value_pairs);
144
0
  for (l = keys; l != NULL; l = l->next)
145
0
    {
146
0
      const gchar *key = l->data;
147
0
      if (g_strcmp0 (key, "path") == 0)
148
0
        path = g_hash_table_lookup (key_value_pairs, key);
149
0
      else if (g_strcmp0 (key, "tmpdir") == 0)
150
0
        tmpdir = g_hash_table_lookup (key_value_pairs, key);
151
0
      else if (g_strcmp0 (key, "abstract") == 0)
152
0
        abstract = g_hash_table_lookup (key_value_pairs, key);
153
0
      else
154
0
        {
155
0
          g_set_error (error,
156
0
                       G_IO_ERROR,
157
0
                       G_IO_ERROR_INVALID_ARGUMENT,
158
0
                       _("Unsupported key “%s” in address entry “%s”"),
159
0
                       key,
160
0
                       address_entry);
161
0
          goto out;
162
0
        }
163
0
    }
164
0
165
0
  if (path != NULL)
166
0
    {
167
0
      if (tmpdir != NULL || abstract != NULL)
168
0
        goto meaningless;
169
0
    }
170
0
  else if (tmpdir != NULL)
171
0
    {
172
0
      if (path != NULL || abstract != NULL)
173
0
        goto meaningless;
174
0
    }
175
0
  else if (abstract != NULL)
176
0
    {
177
0
      if (path != NULL || tmpdir != NULL)
178
0
        goto meaningless;
179
0
    }
180
0
  else
181
0
    {
182
0
      g_set_error (error,
183
0
                   G_IO_ERROR,
184
0
                   G_IO_ERROR_INVALID_ARGUMENT,
185
0
                   _("Address “%s” is invalid (need exactly one of path, tmpdir or abstract keys)"),
186
0
                   address_entry);
187
0
      goto out;
188
0
    }
189
0
190
0
191
0
  ret= TRUE;
192
0
  goto out;
193
0
194
0
 meaningless:
195
0
  g_set_error (error,
196
0
               G_IO_ERROR,
197
0
               G_IO_ERROR_INVALID_ARGUMENT,
198
0
               _("Meaningless key/value pair combination in address entry “%s”"),
199
0
               address_entry);
200
0
201
0
 out:
202
0
  g_list_free (keys);
203
0
204
0
  return ret;
205
0
}
206
207
static gboolean
208
is_valid_nonce_tcp (const gchar  *address_entry,
209
                    GHashTable   *key_value_pairs,
210
                    GError      **error)
211
0
{
212
0
  gboolean ret;
213
0
  GList *keys;
214
0
  GList *l;
215
0
  const gchar *host;
216
0
  const gchar *port;
217
0
  const gchar *family;
218
0
  const gchar *nonce_file;
219
0
  gint port_num;
220
0
  gchar *endp;
221
0
222
0
  ret = FALSE;
223
0
  keys = NULL;
224
0
  host = NULL;
225
0
  port = NULL;
226
0
  family = NULL;
227
0
  nonce_file = NULL;
228
0
229
0
  keys = g_hash_table_get_keys (key_value_pairs);
230
0
  for (l = keys; l != NULL; l = l->next)
231
0
    {
232
0
      const gchar *key = l->data;
233
0
      if (g_strcmp0 (key, "host") == 0)
234
0
        host = g_hash_table_lookup (key_value_pairs, key);
235
0
      else if (g_strcmp0 (key, "port") == 0)
236
0
        port = g_hash_table_lookup (key_value_pairs, key);
237
0
      else if (g_strcmp0 (key, "family") == 0)
238
0
        family = g_hash_table_lookup (key_value_pairs, key);
239
0
      else if (g_strcmp0 (key, "noncefile") == 0)
240
0
        nonce_file = g_hash_table_lookup (key_value_pairs, key);
241
0
      else
242
0
        {
243
0
          g_set_error (error,
244
0
                       G_IO_ERROR,
245
0
                       G_IO_ERROR_INVALID_ARGUMENT,
246
0
                       _("Unsupported key “%s” in address entry “%s”"),
247
0
                       key,
248
0
                       address_entry);
249
0
          goto out;
250
0
        }
251
0
    }
252
0
253
0
  if (port != NULL)
254
0
    {
255
0
      port_num = strtol (port, &endp, 10);
256
0
      if ((*port == '\0' || *endp != '\0') || port_num < 0 || port_num >= 65536)
257
0
        {
258
0
          g_set_error (error,
259
0
                       G_IO_ERROR,
260
0
                       G_IO_ERROR_INVALID_ARGUMENT,
261
0
                       _("Error in address “%s” — the port attribute is malformed"),
262
0
                       address_entry);
263
0
          goto out;
264
0
        }
265
0
    }
266
0
267
0
  if (family != NULL && !(g_strcmp0 (family, "ipv4") == 0 || g_strcmp0 (family, "ipv6") == 0))
268
0
    {
269
0
      g_set_error (error,
270
0
                   G_IO_ERROR,
271
0
                   G_IO_ERROR_INVALID_ARGUMENT,
272
0
                   _("Error in address “%s” — the family attribute is malformed"),
273
0
                   address_entry);
274
0
      goto out;
275
0
    }
276
0
277
0
  if (host != NULL)
278
0
    {
279
0
      /* TODO: validate host */
280
0
    }
281
0
282
0
  nonce_file = nonce_file; /* To avoid -Wunused-but-set-variable */
283
0
284
0
  ret= TRUE;
285
0
286
0
 out:
287
0
  g_list_free (keys);
288
0
289
0
  return ret;
290
0
}
291
292
static gboolean
293
is_valid_tcp (const gchar  *address_entry,
294
              GHashTable   *key_value_pairs,
295
              GError      **error)
296
0
{
297
0
  gboolean ret;
298
0
  GList *keys;
299
0
  GList *l;
300
0
  const gchar *host;
301
0
  const gchar *port;
302
0
  const gchar *family;
303
0
  gint port_num;
304
0
  gchar *endp;
305
0
306
0
  ret = FALSE;
307
0
  keys = NULL;
308
0
  host = NULL;
309
0
  port = NULL;
310
0
  family = NULL;
311
0
312
0
  keys = g_hash_table_get_keys (key_value_pairs);
313
0
  for (l = keys; l != NULL; l = l->next)
314
0
    {
315
0
      const gchar *key = l->data;
316
0
      if (g_strcmp0 (key, "host") == 0)
317
0
        host = g_hash_table_lookup (key_value_pairs, key);
318
0
      else if (g_strcmp0 (key, "port") == 0)
319
0
        port = g_hash_table_lookup (key_value_pairs, key);
320
0
      else if (g_strcmp0 (key, "family") == 0)
321
0
        family = g_hash_table_lookup (key_value_pairs, key);
322
0
      else
323
0
        {
324
0
          g_set_error (error,
325
0
                       G_IO_ERROR,
326
0
                       G_IO_ERROR_INVALID_ARGUMENT,
327
0
                       _("Unsupported key “%s” in address entry “%s”"),
328
0
                       key,
329
0
                       address_entry);
330
0
          goto out;
331
0
        }
332
0
    }
333
0
334
0
  if (port != NULL)
335
0
    {
336
0
      port_num = strtol (port, &endp, 10);
337
0
      if ((*port == '\0' || *endp != '\0') || port_num < 0 || port_num >= 65536)
338
0
        {
339
0
          g_set_error (error,
340
0
                       G_IO_ERROR,
341
0
                       G_IO_ERROR_INVALID_ARGUMENT,
342
0
                       _("Error in address “%s” — the port attribute is malformed"),
343
0
                       address_entry);
344
0
          goto out;
345
0
        }
346
0
    }
347
0
348
0
  if (family != NULL && !(g_strcmp0 (family, "ipv4") == 0 || g_strcmp0 (family, "ipv6") == 0))
349
0
    {
350
0
      g_set_error (error,
351
0
                   G_IO_ERROR,
352
0
                   G_IO_ERROR_INVALID_ARGUMENT,
353
0
                   _("Error in address “%s” — the family attribute is malformed"),
354
0
                   address_entry);
355
0
      goto out;
356
0
    }
357
0
358
0
  if (host != NULL)
359
0
    {
360
0
      /* TODO: validate host */
361
0
    }
362
0
363
0
  ret= TRUE;
364
0
365
0
 out:
366
0
  g_list_free (keys);
367
0
368
0
  return ret;
369
0
}
370
371
/**
372
 * g_dbus_is_supported_address:
373
 * @string: A string.
374
 * @error: Return location for error or %NULL.
375
 *
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).
380
 *
381
 * Returns: %TRUE if @string is a valid D-Bus address that is
382
 * supported by this library, %FALSE if @error is set.
383
 *
384
 * Since: 2.26
385
 */
386
gboolean
387
g_dbus_is_supported_address (const gchar  *string,
388
                             GError      **error)
389
0
{
390
0
  guint n;
391
0
  gchar **a;
392
0
  gboolean ret;
393
0
394
0
  ret = FALSE;
395
0
396
0
  g_return_val_if_fail (string != NULL, FALSE);
397
0
  g_return_val_if_fail (error == NULL || *error == NULL, FALSE);
398
0
399
0
  a = g_strsplit (string, ";", 0);
400
0
  for (n = 0; a[n] != NULL; n++)
401
0
    {
402
0
      gchar *transport_name;
403
0
      GHashTable *key_value_pairs;
404
0
      gboolean supported;
405
0
406
0
      if (!_g_dbus_address_parse_entry (a[n],
407
0
                                        &transport_name,
408
0
                                        &key_value_pairs,
409
0
                                        error))
410
0
        goto out;
411
0
412
0
      supported = FALSE;
413
0
      if (g_strcmp0 (transport_name, "unix") == 0)
414
0
        supported = is_valid_unix (a[n], key_value_pairs, error);
415
0
      else if (g_strcmp0 (transport_name, "tcp") == 0)
416
0
        supported = is_valid_tcp (a[n], key_value_pairs, error);
417
0
      else if (g_strcmp0 (transport_name, "nonce-tcp") == 0)
418
0
        supported = is_valid_nonce_tcp (a[n], key_value_pairs, error);
419
0
      else if (g_strcmp0 (a[n], "autolaunch:") == 0)
420
0
        supported = TRUE;
421
0
      else
422
0
        g_set_error (error, G_IO_ERROR, G_IO_ERROR_INVALID_ARGUMENT,
423
0
                     _("Unknown or unsupported transport “%s” for address “%s”"),
424
0
                     transport_name, a[n]);
425
0
426
0
      g_free (transport_name);
427
0
      g_hash_table_unref (key_value_pairs);
428
0
429
0
      if (!supported)
430
0
        goto out;
431
0
    }
432
0
433
0
  ret = TRUE;
434
0
435
0
 out:
436
0
  g_strfreev (a);
437
0
438
0
  g_assert (ret || (!ret && (error == NULL || *error != NULL)));
439
0
440
0
  return ret;
441
0
}
442
443
gboolean
444
_g_dbus_address_parse_entry (const gchar  *address_entry,
445
                             gchar       **out_transport_name,
446
                             GHashTable  **out_key_value_pairs,
447
                             GError      **error)
448
0
{
449
0
  gboolean ret;
450
0
  GHashTable *key_value_pairs;
451
0
  gchar *transport_name;
452
0
  gchar **kv_pairs;
453
0
  const gchar *s;
454
0
  guint n;
455
0
456
0
  ret = FALSE;
457
0
  kv_pairs = NULL;
458
0
  transport_name = NULL;
459
0
  key_value_pairs = NULL;
460
0
461
0
  s = strchr (address_entry, ':');
462
0
  if (s == NULL)
463
0
    {
464
0
      g_set_error (error,
465
0
                   G_IO_ERROR,
466
0
                   G_IO_ERROR_INVALID_ARGUMENT,
467
0
                   _("Address element “%s” does not contain a colon (:)"),
468
0
                   address_entry);
469
0
      goto out;
470
0
    }
471
0
472
0
  transport_name = g_strndup (address_entry, s - address_entry);
473
0
  key_value_pairs = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, g_free);
474
0
475
0
  kv_pairs = g_strsplit (s + 1, ",", 0);
476
0
  for (n = 0; kv_pairs != NULL && kv_pairs[n] != NULL; n++)
477
0
    {
478
0
      const gchar *kv_pair = kv_pairs[n];
479
0
      gchar *key;
480
0
      gchar *value;
481
0
482
0
      s = strchr (kv_pair, '=');
483
0
      if (s == NULL)
484
0
        {
485
0
          g_set_error (error,
486
0
                       G_IO_ERROR,
487
0
                       G_IO_ERROR_INVALID_ARGUMENT,
488
0
                       _("Key/Value pair %d, “%s”, in address element “%s” does not contain an equal sign"),
489
0
                       n,
490
0
                       kv_pair,
491
0
                       address_entry);
492
0
          goto out;
493
0
        }
494
0
495
0
      key = g_uri_unescape_segment (kv_pair, s, NULL);
496
0
      value = g_uri_unescape_segment (s + 1, kv_pair + strlen (kv_pair), NULL);
497
0
      if (key == NULL || value == NULL)
498
0
        {
499
0
          g_set_error (error,
500
0
                       G_IO_ERROR,
501
0
                       G_IO_ERROR_INVALID_ARGUMENT,
502
0
                       _("Error unescaping key or value in Key/Value pair %d, “%s”, in address element “%s”"),
503
0
                       n,
504
0
                       kv_pair,
505
0
                       address_entry);
506
0
          g_free (key);
507
0
          g_free (value);
508
0
          goto out;
509
0
        }
510
0
      g_hash_table_insert (key_value_pairs, key, value);
511
0
    }
512
0
513
0
  ret = TRUE;
514
0
515
0
out:
516
0
  g_strfreev (kv_pairs);
517
0
  if (ret)
518
0
    {
519
0
      if (out_transport_name != NULL)
520
0
        *out_transport_name = transport_name;
521
0
      else
522
0
        g_free (transport_name);
523
0
      if (out_key_value_pairs != NULL)
524
0
        *out_key_value_pairs = key_value_pairs;
525
0
      else if (key_value_pairs != NULL)
526
0
        g_hash_table_unref (key_value_pairs);
527
0
    }
528
0
  else
529
0
    {
530
0
      g_free (transport_name);
531
0
      if (key_value_pairs != NULL)
532
0
        g_hash_table_unref (key_value_pairs);
533
0
    }
534
0
  return ret;
535
0
}
536
537
/* ---------------------------------------------------------------------------------------------------- */
538
539
static GIOStream *
540
g_dbus_address_try_connect_one (const gchar   *address_entry,
541
                                gchar        **out_guid,
542
                                GCancellable  *cancellable,
543
                                GError       **error);
544
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...
549
 */
550
static GIOStream *
551
g_dbus_address_connect (const gchar   *address_entry,
552
                        const gchar   *transport_name,
553
                        GHashTable    *key_value_pairs,
554
                        GCancellable  *cancellable,
555
                        GError       **error)
556
0
{
557
0
  GIOStream *ret;
558
0
  GSocketConnectable *connectable;
559
0
  const gchar *nonce_file;
560
0
561
0
  connectable = NULL;
562
0
  ret = NULL;
563
0
  nonce_file = NULL;
564
0
565
0
  if (FALSE)
566
0
    {
567
0
    }
568
0
#ifdef G_OS_UNIX
569
0
  else if (g_strcmp0 (transport_name, "unix") == 0)
570
0
    {
571
0
      const gchar *path;
572
0
      const gchar *abstract;
573
0
      path = g_hash_table_lookup (key_value_pairs, "path");
574
0
      abstract = g_hash_table_lookup (key_value_pairs, "abstract");
575
0
      if ((path == NULL && abstract == NULL) || (path != NULL && abstract != NULL))
576
0
        {
577
0
          g_set_error (error,
578
0
                       G_IO_ERROR,
579
0
                       G_IO_ERROR_INVALID_ARGUMENT,
580
0
                       _("Error in address “%s” — the unix transport requires exactly one of the "
581
0
                         "keys “path” or “abstract” to be set"),
582
0
                       address_entry);
583
0
        }
584
0
      else if (path != NULL)
585
0
        {
586
0
          connectable = G_SOCKET_CONNECTABLE (g_unix_socket_address_new (path));
587
0
        }
588
0
      else if (abstract != NULL)
589
0
        {
590
0
          connectable = G_SOCKET_CONNECTABLE (g_unix_socket_address_new_with_type (abstract,
591
0
                                                                                   -1,
592
0
                                                                                   G_UNIX_SOCKET_ADDRESS_ABSTRACT));
593
0
        }
594
0
      else
595
0
        {
596
0
          g_assert_not_reached ();
597
0
        }
598
0
    }
599
0
#endif
600
0
  else if (g_strcmp0 (transport_name, "tcp") == 0 || g_strcmp0 (transport_name, "nonce-tcp") == 0)
601
0
    {
602
0
      const gchar *s;
603
0
      const gchar *host;
604
0
      glong port;
605
0
      gchar *endp;
606
0
      gboolean is_nonce;
607
0
608
0
      is_nonce = (g_strcmp0 (transport_name, "nonce-tcp") == 0);
609
0
610
0
      host = g_hash_table_lookup (key_value_pairs, "host");
611
0
      if (host == NULL)
612
0
        {
613
0
          g_set_error (error,
614
0
                       G_IO_ERROR,
615
0
                       G_IO_ERROR_INVALID_ARGUMENT,
616
0
                       _("Error in address “%s” — the host attribute is missing or malformed"),
617
0
                       address_entry);
618
0
          goto out;
619
0
        }
620
0
621
0
      s = g_hash_table_lookup (key_value_pairs, "port");
622
0
      if (s == NULL)
623
0
        s = "0";
624
0
      port = strtol (s, &endp, 10);
625
0
      if ((*s == '\0' || *endp != '\0') || port < 0 || port >= 65536)
626
0
        {
627
0
          g_set_error (error,
628
0
                       G_IO_ERROR,
629
0
                       G_IO_ERROR_INVALID_ARGUMENT,
630
0
                       _("Error in address “%s” — the port attribute is missing or malformed"),
631
0
                       address_entry);
632
0
          goto out;
633
0
        }
634
0
635
0
636
0
      if (is_nonce)
637
0
        {
638
0
          nonce_file = g_hash_table_lookup (key_value_pairs, "noncefile");
639
0
          if (nonce_file == NULL)
640
0
            {
641
0
              g_set_error (error,
642
0
                           G_IO_ERROR,
643
0
                           G_IO_ERROR_INVALID_ARGUMENT,
644
0
                           _("Error in address “%s” — the noncefile attribute is missing or malformed"),
645
0
                           address_entry);
646
0
              goto out;
647
0
            }
648
0
        }
649
0
650
0
      /* TODO: deal with family key/value-pair */
651
0
      connectable = g_network_address_new (host, port);
652
0
    }
653
0
  else if (g_strcmp0 (address_entry, "autolaunch:") == 0)
654
0
    {
655
0
      gchar *autolaunch_address;
656
0
      autolaunch_address = get_session_address_dbus_launch (error);
657
0
      if (autolaunch_address != NULL)
658
0
        {
659
0
          ret = g_dbus_address_try_connect_one (autolaunch_address, NULL, cancellable, error);
660
0
          g_free (autolaunch_address);
661
0
          goto out;
662
0
        }
663
0
      else
664
0
        {
665
0
          g_prefix_error (error, _("Error auto-launching: "));
666
0
        }
667
0
    }
668
0
  else
669
0
    {
670
0
      g_set_error (error,
671
0
                   G_IO_ERROR,
672
0
                   G_IO_ERROR_INVALID_ARGUMENT,
673
0
                   _("Unknown or unsupported transport “%s” for address “%s”"),
674
0
                   transport_name,
675
0
                   address_entry);
676
0
    }
677
0
678
0
  if (connectable != NULL)
679
0
    {
680
0
      GSocketClient *client;
681
0
      GSocketConnection *connection;
682
0
683
0
      g_assert (ret == NULL);
684
0
      client = g_socket_client_new ();
685
0
686
0
      /* Disable proxy support to prevent a deadlock on startup, since loading a
687
0
       * proxy resolver causes the GIO modules to be loaded, and there will
688
0
       * almost certainly be one of them which then tries to use GDBus.
689
0
       * See: https://bugzilla.gnome.org/show_bug.cgi?id=792499 */
690
0
      g_socket_client_set_enable_proxy (client, FALSE);
691
0
692
0
      connection = g_socket_client_connect (client,
693
0
                                            connectable,
694
0
                                            cancellable,
695
0
                                            error);
696
0
      g_object_unref (connectable);
697
0
      g_object_unref (client);
698
0
      if (connection == NULL)
699
0
        goto out;
700
0
701
0
      ret = G_IO_STREAM (connection);
702
0
703
0
      if (nonce_file != NULL)
704
0
        {
705
0
          gchar nonce_contents[16 + 1];
706
0
          size_t num_bytes_read;
707
0
          FILE *f;
708
0
          int errsv;
709
0
710
0
          /* be careful to read only 16 bytes - we also check that the file is only 16 bytes long */
711
0
          f = fopen (nonce_file, "rb");
712
0
          errsv = errno;
713
0
          if (f == NULL)
714
0
            {
715
0
              g_set_error (error,
716
0
                           G_IO_ERROR,
717
0
                           G_IO_ERROR_INVALID_ARGUMENT,
718
0
                           _("Error opening nonce file “%s”: %s"),
719
0
                           nonce_file,
720
0
                           g_strerror (errsv));
721
0
              g_object_unref (ret);
722
0
              ret = NULL;
723
0
              goto out;
724
0
            }
725
0
          num_bytes_read = fread (nonce_contents,
726
0
                                  sizeof (gchar),
727
0
                                  16 + 1,
728
0
                                  f);
729
0
          errsv = errno;
730
0
          if (num_bytes_read != 16)
731
0
            {
732
0
              if (num_bytes_read == 0)
733
0
                {
734
0
                  g_set_error (error,
735
0
                               G_IO_ERROR,
736
0
                               G_IO_ERROR_INVALID_ARGUMENT,
737
0
                               _("Error reading from nonce file “%s”: %s"),
738
0
                               nonce_file,
739
0
                               g_strerror (errsv));
740
0
                }
741
0
              else
742
0
                {
743
0
                  g_set_error (error,
744
0
                               G_IO_ERROR,
745
0
                               G_IO_ERROR_INVALID_ARGUMENT,
746
0
                               _("Error reading from nonce file “%s”, expected 16 bytes, got %d"),
747
0
                               nonce_file,
748
0
                               (gint) num_bytes_read);
749
0
                }
750
0
              g_object_unref (ret);
751
0
              ret = NULL;
752
0
              fclose (f);
753
0
              goto out;
754
0
            }
755
0
          fclose (f);
756
0
757
0
          if (!g_output_stream_write_all (g_io_stream_get_output_stream (ret),
758
0
                                          nonce_contents,
759
0
                                          16,
760
0
                                          NULL,
761
0
                                          cancellable,
762
0
                                          error))
763
0
            {
764
0
              g_prefix_error (error, _("Error writing contents of nonce file “%s” to stream:"), nonce_file);
765
0
              g_object_unref (ret);
766
0
              ret = NULL;
767
0
              goto out;
768
0
            }
769
0
        }
770
0
    }
771
0
772
0
 out:
773
0
774
0
  return ret;
775
0
}
776
777
static GIOStream *
778
g_dbus_address_try_connect_one (const gchar   *address_entry,
779
                                gchar        **out_guid,
780
                                GCancellable  *cancellable,
781
                                GError       **error)
782
0
{
783
0
  GIOStream *ret;
784
0
  GHashTable *key_value_pairs;
785
0
  gchar *transport_name;
786
0
  const gchar *guid;
787
0
788
0
  ret = NULL;
789
0
  transport_name = NULL;
790
0
  key_value_pairs = NULL;
791
0
792
0
  if (!_g_dbus_address_parse_entry (address_entry,
793
0
                                    &transport_name,
794
0
                                    &key_value_pairs,
795
0
                                    error))
796
0
    goto out;
797
0
798
0
  ret = g_dbus_address_connect (address_entry,
799
0
                                transport_name,
800
0
                                key_value_pairs,
801
0
                                cancellable,
802
0
                                error);
803
0
  if (ret == NULL)
804
0
    goto out;
805
0
806
0
  guid = g_hash_table_lookup (key_value_pairs, "guid");
807
0
  if (guid != NULL && out_guid != NULL)
808
0
    *out_guid = g_strdup (guid);
809
0
810
0
out:
811
0
  g_free (transport_name);
812
0
  if (key_value_pairs != NULL)
813
0
    g_hash_table_unref (key_value_pairs);
814
0
  return ret;
815
0
}
816
817
818
/* ---------------------------------------------------------------------------------------------------- */
819
820
typedef struct {
821
  gchar *address;
822
  gchar *guid;
823
} GetStreamData;
824
825
static void
826
get_stream_data_free (GetStreamData *data)
827
0
{
828
0
  g_free (data->address);
829
0
  g_free (data->guid);
830
0
  g_free (data);
831
0
}
832
833
static void
834
get_stream_thread_func (GTask         *task,
835
                        gpointer       source_object,
836
                        gpointer       task_data,
837
                        GCancellable  *cancellable)
838
0
{
839
0
  GetStreamData *data = task_data;
840
0
  GIOStream *stream;
841
0
  GError *error = NULL;
842
0
843
0
  stream = g_dbus_address_get_stream_sync (data->address,
844
0
                                           &data->guid,
845
0
                                           cancellable,
846
0
                                           &error);
847
0
  if (stream)
848
0
    g_task_return_pointer (task, stream, g_object_unref);
849
0
  else
850
0
    g_task_return_error (task, error);
851
0
}
852
853
/**
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.
859
 *
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).
864
 *
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
867
 * the operation.
868
 *
869
 * This is an asynchronous failable function. See
870
 * g_dbus_address_get_stream_sync() for the synchronous version.
871
 *
872
 * Since: 2.26
873
 */
874
void
875
g_dbus_address_get_stream (const gchar         *address,
876
                           GCancellable        *cancellable,
877
                           GAsyncReadyCallback  callback,
878
                           gpointer             user_data)
879
0
{
880
0
  GTask *task;
881
0
  GetStreamData *data;
882
0
883
0
  g_return_if_fail (address != NULL);
884
0
885
0
  data = g_new0 (GetStreamData, 1);
886
0
  data->address = g_strdup (address);
887
0
888
0
  task = g_task_new (NULL, cancellable, callback, user_data);
889
0
  g_task_set_source_tag (task, g_dbus_address_get_stream);
890
0
  g_task_set_task_data (task, data, (GDestroyNotify) get_stream_data_free);
891
0
  g_task_run_in_thread (task, get_stream_thread_func);
892
0
  g_object_unref (task);
893
0
}
894
895
/**
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.
900
 *
901
 * Finishes an operation started with g_dbus_address_get_stream().
902
 *
903
 * Returns: (transfer full): A #GIOStream or %NULL if @error is set.
904
 *
905
 * Since: 2.26
906
 */
907
GIOStream *
908
g_dbus_address_get_stream_finish (GAsyncResult        *res,
909
                                  gchar              **out_guid,
910
                                  GError             **error)
911
0
{
912
0
  GTask *task;
913
0
  GetStreamData *data;
914
0
  GIOStream *ret;
915
0
916
0
  g_return_val_if_fail (g_task_is_valid (res, NULL), NULL);
917
0
  g_return_val_if_fail (error == NULL || *error == NULL, NULL);
918
0
919
0
  task = G_TASK (res);
920
0
  ret = g_task_propagate_pointer (task, error);
921
0
922
0
  if (ret != NULL && out_guid != NULL)
923
0
    {
924
0
      data = g_task_get_task_data (task);
925
0
      *out_guid = data->guid;
926
0
      data->guid = NULL;
927
0
    }
928
0
929
0
  return ret;
930
0
}
931
932
/**
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.
938
 *
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).
943
 *
944
 * This is a synchronous failable function. See
945
 * g_dbus_address_get_stream() for the asynchronous version.
946
 *
947
 * Returns: (transfer full): A #GIOStream or %NULL if @error is set.
948
 *
949
 * Since: 2.26
950
 */
951
GIOStream *
952
g_dbus_address_get_stream_sync (const gchar   *address,
953
                                gchar        **out_guid,
954
                                GCancellable  *cancellable,
955
                                GError       **error)
956
0
{
957
0
  GIOStream *ret;
958
0
  gchar **addr_array;
959
0
  guint n;
960
0
  GError *last_error;
961
0
962
0
  g_return_val_if_fail (address != NULL, NULL);
963
0
  g_return_val_if_fail (error == NULL || *error == NULL, NULL);
964
0
965
0
  ret = NULL;
966
0
  last_error = NULL;
967
0
968
0
  addr_array = g_strsplit (address, ";", 0);
969
0
  if (addr_array != NULL && addr_array[0] == NULL)
970
0
    {
971
0
      last_error = g_error_new_literal (G_IO_ERROR,
972
0
                                        G_IO_ERROR_INVALID_ARGUMENT,
973
0
                                        _("The given address is empty"));
974
0
      goto out;
975
0
    }
976
0
977
0
  for (n = 0; addr_array != NULL && addr_array[n] != NULL; n++)
978
0
    {
979
0
      const gchar *addr = addr_array[n];
980
0
      GError *this_error;
981
0
982
0
      this_error = NULL;
983
0
      ret = g_dbus_address_try_connect_one (addr,
984
0
                                            out_guid,
985
0
                                            cancellable,
986
0
                                            &this_error);
987
0
      if (ret != NULL)
988
0
        {
989
0
          goto out;
990
0
        }
991
0
      else
992
0
        {
993
0
          g_assert (this_error != NULL);
994
0
          if (last_error != NULL)
995
0
            g_error_free (last_error);
996
0
          last_error = this_error;
997
0
        }
998
0
    }
999
0
1000
0
 out:
1001
0
  if (ret != NULL)
1002
0
    {
1003
0
      if (last_error != NULL)
1004
0
        g_error_free (last_error);
1005
0
    }
1006
0
  else
1007
0
    {
1008
0
      g_assert (last_error != NULL);
1009
0
      g_propagate_error (error, last_error);
1010
0
    }
1011
0
1012
0
  g_strfreev (addr_array);
1013
0
  return ret;
1014
0
}
1015
1016
/* ---------------------------------------------------------------------------------------------------- */
1017
1018
/*
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.
1021
 */
1022
static gchar *
1023
get_session_address_xdg (void)
1024
0
{
1025
0
#ifdef G_OS_UNIX
1026
0
  gchar *ret = NULL;
1027
0
  gchar *bus;
1028
0
  gchar *tmp;
1029
0
  GStatBuf buf;
1030
0
1031
0
  bus = g_build_filename (g_get_user_runtime_dir (), "bus", NULL);
1032
0
1033
0
  /* if ENOENT, EPERM, etc., quietly don't use it */
1034
0
  if (g_stat (bus, &buf) < 0)
1035
0
    goto out;
1036
0
1037
0
  /* if it isn't ours, we have incorrectly inherited someone else's
1038
0
   * XDG_RUNTIME_DIR; silently don't use it
1039
0
   */
1040
0
  if (buf.st_uid != geteuid ())
1041
0
    goto out;
1042
0
1043
0
  /* if it isn't a socket, silently don't use it */
1044
0
  if ((buf.st_mode & S_IFMT) != S_IFSOCK)
1045
0
    goto out;
1046
0
1047
0
  tmp = g_dbus_address_escape_value (bus);
1048
0
  ret = g_strconcat ("unix:path=", tmp, NULL);
1049
0
  g_free (tmp);
1050
0
1051
0
out:
1052
0
  g_free (bus);
1053
0
  return ret;
1054
#else
1055
  return NULL;
1056
#endif
1057
}
1058
1059
/* ---------------------------------------------------------------------------------------------------- */
1060
1061
#ifdef G_OS_UNIX
1062
static gchar *
1063
get_session_address_dbus_launch (GError **error)
1064
0
{
1065
0
  gchar *ret;
1066
0
  gchar *machine_id;
1067
0
  gchar *command_line;
1068
0
  gchar *launch_stdout;
1069
0
  gchar *launch_stderr;
1070
0
  gint exit_status;
1071
0
  gchar *old_dbus_verbose;
1072
0
  gboolean restore_dbus_verbose;
1073
0
1074
0
  ret = NULL;
1075
0
  machine_id = NULL;
1076
0
  command_line = NULL;
1077
0
  launch_stdout = NULL;
1078
0
  launch_stderr = NULL;
1079
0
  restore_dbus_verbose = FALSE;
1080
0
  old_dbus_verbose = NULL;
1081
0
1082
0
  /* Don't run binaries as root if we're setuid. */
1083
0
  if (GLIB_PRIVATE_CALL (g_check_setuid) ())
1084
0
    {
1085
0
      g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED,
1086
0
       _("Cannot spawn a message bus when setuid"));
1087
0
      goto out;
1088
0
    }
1089
0
1090
0
  machine_id = _g_dbus_get_machine_id (error);
1091
0
  if (machine_id == NULL)
1092
0
    {
1093
0
      g_prefix_error (error, _("Cannot spawn a message bus without a machine-id: "));
1094
0
      goto out;
1095
0
    }
1096
0
1097
0
  if (g_getenv ("DISPLAY") == NULL)
1098
0
    {
1099
0
      g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED,
1100
0
                   _("Cannot autolaunch D-Bus without X11 $DISPLAY"));
1101
0
      goto out;
1102
0
    }
1103
0
1104
0
  /* We're using private libdbus facilities here. When everything
1105
0
   * (X11, Mac OS X, Windows) is spec'ed out correctly (not even the
1106
0
   * X11 property is correctly documented right now) we should
1107
0
   * consider using the spec instead of dbus-launch.
1108
0
   *
1109
0
   *   --autolaunch=MACHINEID
1110
0
   *          This option implies that dbus-launch should scan  for  a  previ‐
1111
0
   *          ously-started  session  and  reuse the values found there. If no
1112
0
   *          session is found, it will start a new session. The  --exit-with-
1113
0
   *          session option is implied if --autolaunch is given.  This option
1114
0
   *          is for the exclusive use of libdbus, you do not want to  use  it
1115
0
   *          manually. It may change in the future.
1116
0
   */
1117
0
1118
0
  /* TODO: maybe provide a variable for where to look for the dbus-launch binary? */
1119
0
  command_line = g_strdup_printf ("dbus-launch --autolaunch=%s --binary-syntax --close-stderr", machine_id);
1120
0
1121
0
  if (G_UNLIKELY (_g_dbus_debug_address ()))
1122
0
    {
1123
0
      _g_dbus_debug_print_lock ();
1124
0
      g_print ("GDBus-debug:Address: Running '%s' to get bus address (possibly autolaunching)\n", command_line);
1125
0
      old_dbus_verbose = g_strdup (g_getenv ("DBUS_VERBOSE"));
1126
0
      restore_dbus_verbose = TRUE;
1127
0
      g_setenv ("DBUS_VERBOSE", "1", TRUE);
1128
0
      _g_dbus_debug_print_unlock ();
1129
0
    }
1130
0
1131
0
  if (!g_spawn_command_line_sync (command_line,
1132
0
                                  &launch_stdout,
1133
0
                                  &launch_stderr,
1134
0
                                  &exit_status,
1135
0
                                  error))
1136
0
    {
1137
0
      goto out;
1138
0
    }
1139
0
1140
0
  if (!g_spawn_check_exit_status (exit_status, error))
1141
0
    {
1142
0
      g_prefix_error (error, _("Error spawning command line “%s”: "), command_line);
1143
0
      goto out;
1144
0
    }
1145
0
1146
0
  /* From the dbus-launch(1) man page:
1147
0
   *
1148
0
   *   --binary-syntax Write to stdout a nul-terminated bus address,
1149
0
   *   then the bus PID as a binary integer of size sizeof(pid_t),
1150
0
   *   then the bus X window ID as a binary integer of size
1151
0
   *   sizeof(long).  Integers are in the machine's byte order, not
1152
0
   *   network byte order or any other canonical byte order.
1153
0
   */
1154
0
  ret = g_strdup (launch_stdout);
1155
0
1156
0
 out:
1157
0
  if (G_UNLIKELY (_g_dbus_debug_address ()))
1158
0
    {
1159
0
      gchar *s;
1160
0
      _g_dbus_debug_print_lock ();
1161
0
      g_print ("GDBus-debug:Address: dbus-launch output:");
1162
0
      if (launch_stdout != NULL)
1163
0
        {
1164
0
          s = _g_dbus_hexdump (launch_stdout, strlen (launch_stdout) + 1 + sizeof (pid_t) + sizeof (long), 2);
1165
0
          g_print ("\n%s", s);
1166
0
          g_free (s);
1167
0
        }
1168
0
      else
1169
0
        {
1170
0
          g_print (" (none)\n");
1171
0
        }
1172
0
      g_print ("GDBus-debug:Address: dbus-launch stderr output:");
1173
0
      if (launch_stderr != NULL)
1174
0
        g_print ("\n%s", launch_stderr);
1175
0
      else
1176
0
        g_print (" (none)\n");
1177
0
      _g_dbus_debug_print_unlock ();
1178
0
    }
1179
0
1180
0
  g_free (machine_id);
1181
0
  g_free (command_line);
1182
0
  g_free (launch_stdout);
1183
0
  g_free (launch_stderr);
1184
0
  if (G_UNLIKELY (restore_dbus_verbose))
1185
0
    {
1186
0
      if (old_dbus_verbose != NULL)
1187
0
        g_setenv ("DBUS_VERBOSE", old_dbus_verbose, TRUE);
1188
0
      else
1189
0
        g_unsetenv ("DBUS_VERBOSE");
1190
0
    }
1191
0
  g_free (old_dbus_verbose);
1192
0
  return ret;
1193
0
}
1194
1195
/* end of G_OS_UNIX case */
1196
#elif defined(G_OS_WIN32)
1197
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"
1202
1203
static void
1204
release_mutex (HANDLE mutex)
1205
{
1206
  ReleaseMutex (mutex);
1207
  CloseHandle (mutex);
1208
}
1209
1210
static HANDLE
1211
acquire_mutex (const char *mutexname)
1212
{
1213
  HANDLE mutex;
1214
  DWORD res;
1215
1216
  mutex = CreateMutexA (NULL, FALSE, mutexname);
1217
  if (!mutex)
1218
    return 0;
1219
1220
  res = WaitForSingleObject (mutex, INFINITE);
1221
  switch (res)
1222
    {
1223
    case WAIT_ABANDONED:
1224
      release_mutex (mutex);
1225
      return 0;
1226
    case WAIT_FAILED:
1227
    case WAIT_TIMEOUT:
1228
      return 0;
1229
    }
1230
1231
  return mutex;
1232
}
1233
1234
static gboolean
1235
is_mutex_owned (const char *mutexname)
1236
{
1237
  HANDLE mutex;
1238
  gboolean res = FALSE;
1239
1240
  mutex = CreateMutexA (NULL, FALSE, mutexname);
1241
  if (WaitForSingleObject (mutex, 10) == WAIT_TIMEOUT)
1242
    res = TRUE;
1243
  else
1244
    ReleaseMutex (mutex);
1245
  CloseHandle (mutex);
1246
1247
  return res;
1248
}
1249
1250
static char *
1251
read_shm (const char *shm_name)
1252
{
1253
  HANDLE shared_mem;
1254
  char *shared_data;
1255
  char *res;
1256
  int i;
1257
1258
  res = NULL;
1259
1260
  for (i = 0; i < 20; i++)
1261
    {
1262
      shared_mem = OpenFileMappingA (FILE_MAP_READ, FALSE, shm_name);
1263
      if (shared_mem != 0)
1264
  break;
1265
      Sleep (100);
1266
    }
1267
1268
  if (shared_mem != 0)
1269
    {
1270
      shared_data = MapViewOfFile (shared_mem, FILE_MAP_READ, 0, 0, 0);
1271
      if (shared_data != NULL)
1272
  {
1273
    res = g_strdup (shared_data);
1274
    UnmapViewOfFile (shared_data);
1275
  }
1276
      CloseHandle (shared_mem);
1277
    }
1278
1279
  return res;
1280
}
1281
1282
static HANDLE
1283
set_shm (const char *shm_name, const char *value)
1284
{
1285
  HANDLE shared_mem;
1286
  char *shared_data;
1287
1288
  shared_mem = CreateFileMappingA (INVALID_HANDLE_VALUE, NULL, PAGE_READWRITE,
1289
           0, strlen (value) + 1, shm_name);
1290
  if (shared_mem == 0)
1291
    return 0;
1292
1293
  shared_data = MapViewOfFile (shared_mem, FILE_MAP_WRITE, 0, 0, 0 );
1294
  if (shared_data == NULL)
1295
    return 0;
1296
1297
  strcpy (shared_data, value);
1298
1299
  UnmapViewOfFile (shared_data);
1300
1301
  return shared_mem;
1302
}
1303
1304
/* These keep state between publish_session_bus and unpublish_session_bus */
1305
static HANDLE published_daemon_mutex;
1306
static HANDLE published_shared_mem;
1307
1308
static gboolean
1309
publish_session_bus (const char *address)
1310
{
1311
  HANDLE init_mutex;
1312
1313
  init_mutex = acquire_mutex (UNIQUE_DBUS_INIT_MUTEX);
1314
1315
  published_daemon_mutex = CreateMutexA (NULL, FALSE, DBUS_DAEMON_MUTEX);
1316
  if (WaitForSingleObject (published_daemon_mutex, 10 ) != WAIT_OBJECT_0)
1317
    {
1318
      release_mutex (init_mutex);
1319
      CloseHandle (published_daemon_mutex);
1320
      published_daemon_mutex = NULL;
1321
      return FALSE;
1322
    }
1323
1324
  published_shared_mem = set_shm (DBUS_DAEMON_ADDRESS_INFO, address);
1325
  if (!published_shared_mem)
1326
    {
1327
      release_mutex (init_mutex);
1328
      CloseHandle (published_daemon_mutex);
1329
      published_daemon_mutex = NULL;
1330
      return FALSE;
1331
    }
1332
1333
  release_mutex (init_mutex);
1334
  return TRUE;
1335
}
1336
1337
static void
1338
unpublish_session_bus (void)
1339
{
1340
  HANDLE init_mutex;
1341
1342
  init_mutex = acquire_mutex (UNIQUE_DBUS_INIT_MUTEX);
1343
1344
  CloseHandle (published_shared_mem);
1345
  published_shared_mem = NULL;
1346
1347
  release_mutex (published_daemon_mutex);
1348
  published_daemon_mutex = NULL;
1349
1350
  release_mutex (init_mutex);
1351
}
1352
1353
static void
1354
wait_console_window (void)
1355
{
1356
  FILE *console = fopen ("CONOUT$", "w");
1357
1358
  SetConsoleTitleW (L"gdbus-daemon output. Type any character to close this window.");
1359
  fprintf (console, _("(Type any character to close this window)\n"));
1360
  fflush (console);
1361
  _getch ();
1362
}
1363
1364
static void
1365
open_console_window (void)
1366
{
1367
  if (((HANDLE) _get_osfhandle (fileno (stdout)) == INVALID_HANDLE_VALUE ||
1368
       (HANDLE) _get_osfhandle (fileno (stderr)) == INVALID_HANDLE_VALUE) && AllocConsole ())
1369
    {
1370
      if ((HANDLE) _get_osfhandle (fileno (stdout)) == INVALID_HANDLE_VALUE)
1371
        freopen ("CONOUT$", "w", stdout);
1372
1373
      if ((HANDLE) _get_osfhandle (fileno (stderr)) == INVALID_HANDLE_VALUE)
1374
        freopen ("CONOUT$", "w", stderr);
1375
1376
      SetConsoleTitleW (L"gdbus-daemon debug output.");
1377
1378
      atexit (wait_console_window);
1379
    }
1380
}
1381
1382
static void
1383
idle_timeout_cb (GDBusDaemon *daemon, gpointer user_data)
1384
{
1385
  GMainLoop *loop = user_data;
1386
  g_main_loop_quit (loop);
1387
}
1388
1389
/* Satisfies STARTF_FORCEONFEEDBACK */
1390
static void
1391
turn_off_the_starting_cursor (void)
1392
{
1393
  MSG msg;
1394
  BOOL bRet;
1395
1396
  PostQuitMessage (0);
1397
1398
  while ((bRet = GetMessage (&msg, 0, 0, 0)) != 0)
1399
    {
1400
      if (bRet == -1)
1401
        continue;
1402
1403
      TranslateMessage (&msg);
1404
      DispatchMessage (&msg);
1405
    }
1406
}
1407
1408
__declspec(dllexport) void CALLBACK g_win32_run_session_bus (HWND hwnd, HINSTANCE hinst, char *cmdline, int nCmdShow);
1409
1410
__declspec(dllexport) void CALLBACK
1411
g_win32_run_session_bus (HWND hwnd, HINSTANCE hinst, char *cmdline, int nCmdShow)
1412
{
1413
  GDBusDaemon *daemon;
1414
  GMainLoop *loop;
1415
  const char *address;
1416
  GError *error = NULL;
1417
1418
  turn_off_the_starting_cursor ();
1419
1420
  if (g_getenv ("GDBUS_DAEMON_DEBUG") != NULL)
1421
    open_console_window ();
1422
1423
  loop = g_main_loop_new (NULL, FALSE);
1424
1425
  address = "nonce-tcp:";
1426
  daemon = _g_dbus_daemon_new (address, NULL, &error);
1427
  if (daemon == NULL)
1428
    {
1429
      g_printerr ("Can't init bus: %s\n", error->message);
1430
      g_error_free (error);
1431
      return;
1432
    }
1433
1434
  g_signal_connect (daemon, "idle-timeout", G_CALLBACK (idle_timeout_cb), loop);
1435
1436
  if (publish_session_bus (_g_dbus_daemon_get_address (daemon)))
1437
    {
1438
      g_main_loop_run (loop);
1439
1440
      unpublish_session_bus ();
1441
    }
1442
1443
  g_main_loop_unref (loop);
1444
  g_object_unref (daemon);
1445
}
1446
1447
static gchar *
1448
get_session_address_dbus_launch (GError **error)
1449
{
1450
  HANDLE autolaunch_mutex, init_mutex;
1451
  char *address = NULL;
1452
  wchar_t gio_path[MAX_PATH+1+200];
1453
1454
  autolaunch_mutex = acquire_mutex (DBUS_AUTOLAUNCH_MUTEX);
1455
1456
  init_mutex = acquire_mutex (UNIQUE_DBUS_INIT_MUTEX);
1457
1458
  if (is_mutex_owned (DBUS_DAEMON_MUTEX))
1459
    address = read_shm (DBUS_DAEMON_ADDRESS_INFO);
1460
1461
  release_mutex (init_mutex);
1462
1463
  if (address == NULL)
1464
    {
1465
      gio_path[MAX_PATH] = 0;
1466
      if (GetModuleFileNameW (_g_io_win32_get_module (), gio_path, MAX_PATH))
1467
  {
1468
    PROCESS_INFORMATION pi = { 0 };
1469
    STARTUPINFOW si = { 0 };
1470
    BOOL res;
1471
    wchar_t gio_path_short[MAX_PATH];
1472
    wchar_t rundll_path[MAX_PATH*2];
1473
    wchar_t args[MAX_PATH*4];
1474
1475
    GetShortPathNameW (gio_path, gio_path_short, MAX_PATH);
1476
1477
    GetWindowsDirectoryW (rundll_path, MAX_PATH);
1478
    wcscat (rundll_path, L"\\rundll32.exe");
1479
    if (GetFileAttributesW (rundll_path) == INVALID_FILE_ATTRIBUTES)
1480
      {
1481
        GetSystemDirectoryW (rundll_path, MAX_PATH);
1482
        wcscat (rundll_path, L"\\rundll32.exe");
1483
      }
1484
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");
1493
#else
1494
    wcscat (args, L",g_win32_run_session_bus@16");
1495
#endif
1496
1497
    res = CreateProcessW (rundll_path, args,
1498
        0, 0, FALSE,
1499
        NORMAL_PRIORITY_CLASS | CREATE_NO_WINDOW | DETACHED_PROCESS,
1500
        0, NULL /* TODO: Should be root */,
1501
        &si, &pi);
1502
    if (res)
1503
      address = read_shm (DBUS_DAEMON_ADDRESS_INFO);
1504
  }
1505
    }
1506
1507
  release_mutex (autolaunch_mutex);
1508
1509
  if (address == NULL)
1510
    g_set_error (error,
1511
     G_IO_ERROR,
1512
     G_IO_ERROR_FAILED,
1513
     _("Session dbus not running, and autolaunch failed"));
1514
1515
  return address;
1516
}
1517
#else /* neither G_OS_UNIX nor G_OS_WIN32 */
1518
static gchar *
1519
get_session_address_dbus_launch (GError **error)
1520
{
1521
  g_set_error (error,
1522
               G_IO_ERROR,
1523
               G_IO_ERROR_FAILED,
1524
               _("Cannot determine session bus address (not implemented for this OS)"));
1525
  return NULL;
1526
}
1527
#endif /* neither G_OS_UNIX nor G_OS_WIN32 */
1528
1529
/* ---------------------------------------------------------------------------------------------------- */
1530
1531
static gchar *
1532
get_session_address_platform_specific (GError **error)
1533
0
{
1534
0
  gchar *ret;
1535
0
1536
0
  /* Use XDG_RUNTIME_DIR/bus if it exists and is suitable. This is appropriate
1537
0
   * for systems using the "a session is a user-session" model described in
1538
0
   * <http://lists.freedesktop.org/archives/dbus/2015-January/016522.html>,
1539
0
   * and implemented in dbus >= 1.9.14 and sd-bus.
1540
0
   *
1541
0
   * On systems following the more traditional "a session is a login-session"
1542
0
   * model, this will fail and we'll fall through to X11 autolaunching
1543
0
   * (dbus-launch) below.
1544
0
   */
1545
0
  ret = get_session_address_xdg ();
1546
0
1547
0
  if (ret != NULL)
1548
0
    return ret;
1549
0
1550
0
  /* TODO (#694472): try launchd on OS X, like
1551
0
   * _dbus_lookup_session_address_launchd() does, since
1552
0
   * 'dbus-launch --autolaunch' probably won't work there
1553
0
   */
1554
0
1555
0
  /* As a last resort, try the "autolaunch:" transport. On Unix this means
1556
0
   * X11 autolaunching; on Windows this means a different autolaunching
1557
0
   * mechanism based on shared memory.
1558
0
   */
1559
0
  return get_session_address_dbus_launch (error);
1560
0
}
1561
1562
/* ---------------------------------------------------------------------------------------------------- */
1563
1564
/**
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
1569
 *
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.
1573
 *
1574
 * The returned address will be in the
1575
 * [D-Bus address format](https://dbus.freedesktop.org/doc/dbus-specification.html#addresses).
1576
 *
1577
 * Returns: a valid D-Bus address string for @bus_type or %NULL if
1578
 *     @error is set
1579
 *
1580
 * Since: 2.26
1581
 */
1582
gchar *
1583
g_dbus_address_get_for_bus_sync (GBusType       bus_type,
1584
                                 GCancellable  *cancellable,
1585
                                 GError       **error)
1586
0
{
1587
0
  gchar *ret, *s = NULL;
1588
0
  const gchar *starter_bus;
1589
0
  GError *local_error;
1590
0
1591
0
  g_return_val_if_fail (error == NULL || *error == NULL, NULL);
1592
0
1593
0
  ret = NULL;
1594
0
  local_error = NULL;
1595
0
1596
0
  if (G_UNLIKELY (_g_dbus_debug_address ()))
1597
0
    {
1598
0
      guint n;
1599
0
      _g_dbus_debug_print_lock ();
1600
0
      s = _g_dbus_enum_to_string (G_TYPE_BUS_TYPE, bus_type);
1601
0
      g_print ("GDBus-debug:Address: In g_dbus_address_get_for_bus_sync() for bus type '%s'\n",
1602
0
               s);
1603
0
      g_free (s);
1604
0
      for (n = 0; n < 3; n++)
1605
0
        {
1606
0
          const gchar *k;
1607
0
          const gchar *v;
1608
0
          switch (n)
1609
0
            {
1610
0
            case 0: k = "DBUS_SESSION_BUS_ADDRESS"; break;
1611
0
            case 1: k = "DBUS_SYSTEM_BUS_ADDRESS"; break;
1612
0
            case 2: k = "DBUS_STARTER_BUS_TYPE"; break;
1613
0
            default: g_assert_not_reached ();
1614
0
            }
1615
0
          v = g_getenv (k);
1616
0
          g_print ("GDBus-debug:Address: env var %s", k);
1617
0
          if (v != NULL)
1618
0
            g_print ("='%s'\n", v);
1619
0
          else
1620
0
            g_print (" is not set\n");
1621
0
        }
1622
0
      _g_dbus_debug_print_unlock ();
1623
0
    }
1624
0
1625
0
  switch (bus_type)
1626
0
    {
1627
0
    case G_BUS_TYPE_SYSTEM:
1628
0
      ret = g_strdup (g_getenv ("DBUS_SYSTEM_BUS_ADDRESS"));
1629
0
      if (ret == NULL)
1630
0
        {
1631
0
          ret = g_strdup ("unix:path=/var/run/dbus/system_bus_socket");
1632
0
        }
1633
0
      break;
1634
0
1635
0
    case G_BUS_TYPE_SESSION:
1636
0
      ret = g_strdup (g_getenv ("DBUS_SESSION_BUS_ADDRESS"));
1637
0
      if (ret == NULL)
1638
0
        {
1639
0
          ret = get_session_address_platform_specific (&local_error);
1640
0
        }
1641
0
      break;
1642
0
1643
0
    case G_BUS_TYPE_STARTER:
1644
0
      starter_bus = g_getenv ("DBUS_STARTER_BUS_TYPE");
1645
0
      if (g_strcmp0 (starter_bus, "session") == 0)
1646
0
        {
1647
0
          ret = g_dbus_address_get_for_bus_sync (G_BUS_TYPE_SESSION, cancellable, &local_error);
1648
0
          goto out;
1649
0
        }
1650
0
      else if (g_strcmp0 (starter_bus, "system") == 0)
1651
0
        {
1652
0
          ret = g_dbus_address_get_for_bus_sync (G_BUS_TYPE_SYSTEM, cancellable, &local_error);
1653
0
          goto out;
1654
0
        }
1655
0
      else
1656
0
        {
1657
0
          if (starter_bus != NULL)
1658
0
            {
1659
0
              g_set_error (&local_error,
1660
0
                           G_IO_ERROR,
1661
0
                           G_IO_ERROR_FAILED,
1662
0
                           _("Cannot determine bus address from DBUS_STARTER_BUS_TYPE environment variable"
1663
0
                             " — unknown value “%s”"),
1664
0
                           starter_bus);
1665
0
            }
1666
0
          else
1667
0
            {
1668
0
              g_set_error_literal (&local_error,
1669
0
                                   G_IO_ERROR,
1670
0
                                   G_IO_ERROR_FAILED,
1671
0
                                   _("Cannot determine bus address because the DBUS_STARTER_BUS_TYPE environment "
1672
0
                                     "variable is not set"));
1673
0
            }
1674
0
        }
1675
0
      break;
1676
0
1677
0
    default:
1678
0
      g_set_error (&local_error,
1679
0
                   G_IO_ERROR,
1680
0
                   G_IO_ERROR_FAILED,
1681
0
                   _("Unknown bus type %d"),
1682
0
                   bus_type);
1683
0
      break;
1684
0
    }
1685
0
1686
0
 out:
1687
0
  if (G_UNLIKELY (_g_dbus_debug_address ()))
1688
0
    {
1689
0
      _g_dbus_debug_print_lock ();
1690
0
      s = _g_dbus_enum_to_string (G_TYPE_BUS_TYPE, bus_type);
1691
0
      if (ret != NULL)
1692
0
        {
1693
0
          g_print ("GDBus-debug:Address: Returning address '%s' for bus type '%s'\n",
1694
0
                   ret, s);
1695
0
        }
1696
0
      else
1697
0
        {
1698
0
          g_print ("GDBus-debug:Address: Cannot look-up address bus type '%s': %s\n",
1699
0
                   s, local_error ? local_error->message : "");
1700
0
        }
1701
0
      g_free (s);
1702
0
      _g_dbus_debug_print_unlock ();
1703
0
    }
1704
0
1705
0
  if (local_error != NULL)
1706
0
    g_propagate_error (error, local_error);
1707
0
1708
0
  return ret;
1709
0
}
1710
1711
/**
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
1715
 *
1716
 * Escape @string so it can appear in a D-Bus address as the value
1717
 * part of a key-value pair.
1718
 *
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`.
1723
 *
1724
 * Returns: (transfer full): a copy of @string with all
1725
 *     non-optionally-escaped bytes escaped
1726
 *
1727
 * Since: 2.36
1728
 */
1729
gchar *
1730
g_dbus_address_escape_value (const gchar *string)
1731
0
{
1732
0
  GString *s;
1733
0
  gsize i;
1734
0
1735
0
  g_return_val_if_fail (string != NULL, NULL);
1736
0
1737
0
  /* There will often not be anything needing escaping at all. */
1738
0
  s = g_string_sized_new (strlen (string));
1739
0
1740
0
  /* D-Bus address escaping is mostly the same as URI escaping... */
1741
0
  g_string_append_uri_escaped (s, string, "\\/", FALSE);
1742
0
1743
0
  /* ... but '~' is an unreserved character in URIs, but a
1744
0
   * non-optionally-escaped character in D-Bus addresses. */
1745
0
  for (i = 0; i < s->len; i++)
1746
0
    {
1747
0
      if (G_UNLIKELY (s->str[i] == '~'))
1748
0
        {
1749
0
          s->str[i] = '%';
1750
0
          g_string_insert (s, i + 1, "7E");
1751
0
          i += 2;
1752
0
        }
1753
0
    }
1754
0
1755
0
  return g_string_free (s, FALSE);
1756
0
}