Coverage Report

Created: 2025-07-23 08:13

/src/pango/subprojects/glib/gio/gunixsocketaddress.c
Line
Count
Source (jump to first uncovered line)
1
/* GIO - GLib Input, Output and Streaming Library
2
 *
3
 * Copyright (C) 2008 Christian Kellner, Samuel Cormier-Iijima
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
 * Authors: Christian Kellner <gicmo@gnome.org>
21
 *          Samuel Cormier-Iijima <sciyoshi@gmail.com>
22
 */
23
24
#include <config.h>
25
#include <glib.h>
26
#include <string.h>
27
28
#include "gunixsocketaddress.h"
29
#include "gsocketconnectable.h"
30
#include "glibintl.h"
31
#include "gnetworking.h"
32
33
#ifdef G_OS_WIN32
34
#include "giowin32-afunix.h"
35
#endif
36
37
/**
38
 * GUnixSocketAddress:
39
 *
40
 * Support for UNIX-domain (also known as local) sockets, corresponding to
41
 * `struct sockaddr_un`.
42
 *
43
 * UNIX domain sockets are generally visible in the filesystem.
44
 * However, some systems support abstract socket names which are not
45
 * visible in the filesystem and not affected by the filesystem
46
 * permissions, visibility, etc. Currently this is only supported
47
 * under Linux. If you attempt to use abstract sockets on other
48
 * systems, function calls may return `G_IO_ERROR_NOT_SUPPORTED`
49
 * errors. You can use [func@Gio.UnixSocketAddress.abstract_names_supported]
50
 * to see if abstract names are supported.
51
 *
52
 * Since GLib 2.72, `GUnixSocketAddress` is available on all platforms. It
53
 * requires underlying system support (such as Windows 10 with `AF_UNIX`) at
54
 * run time.
55
 *
56
 * Before GLib 2.72, `<gio/gunixsocketaddress.h>` belonged to the UNIX-specific
57
 * GIO interfaces, thus you had to use the `gio-unix-2.0.pc` pkg-config file
58
 * when using it. This is no longer necessary since GLib 2.72.
59
 */
60
61
enum
62
{
63
  PROP_0,
64
  PROP_PATH,
65
  PROP_PATH_AS_ARRAY,
66
  PROP_ABSTRACT,
67
  PROP_ADDRESS_TYPE
68
};
69
70
#ifndef UNIX_PATH_MAX
71
#define UNIX_PATH_MAX G_SIZEOF_MEMBER (struct sockaddr_un, sun_path)
72
#endif
73
74
struct _GUnixSocketAddressPrivate
75
{
76
  char path[UNIX_PATH_MAX]; /* Not including the initial zero in abstract case, so
77
             we can guarantee zero termination of abstract
78
             pathnames in the get_path() API */
79
  gsize path_len; /* Not including any terminating zeros */
80
  GUnixSocketAddressType address_type;
81
};
82
83
static void   g_unix_socket_address_connectable_iface_init (GSocketConnectableIface *iface);
84
static gchar *g_unix_socket_address_connectable_to_string  (GSocketConnectable      *connectable);
85
86
G_DEFINE_TYPE_WITH_CODE (GUnixSocketAddress, g_unix_socket_address, G_TYPE_SOCKET_ADDRESS,
87
                         G_ADD_PRIVATE (GUnixSocketAddress)
88
                         G_IMPLEMENT_INTERFACE (G_TYPE_SOCKET_CONNECTABLE,
89
                                                g_unix_socket_address_connectable_iface_init))
90
91
static void
92
g_unix_socket_address_set_property (GObject      *object,
93
            guint         prop_id,
94
            const GValue *value,
95
            GParamSpec   *pspec)
96
0
{
97
0
  GUnixSocketAddress *address = G_UNIX_SOCKET_ADDRESS (object);
98
0
  const char *str;
99
0
  GByteArray *array;
100
0
  gsize len;
101
102
0
  switch (prop_id)
103
0
    {
104
0
    case PROP_PATH:
105
0
      str = g_value_get_string (value);
106
0
      if (str)
107
0
  {
108
0
    g_strlcpy (address->priv->path, str,
109
0
         sizeof (address->priv->path));
110
0
    address->priv->path_len = strlen (address->priv->path);
111
0
  }
112
0
      break;
113
114
0
    case PROP_PATH_AS_ARRAY:
115
0
      array = g_value_get_boxed (value);
116
117
0
      if (array)
118
0
  {
119
    /* Clip to fit in UNIX_PATH_MAX with zero termination or first byte */
120
0
    len = MIN (array->len, UNIX_PATH_MAX-1);
121
122
0
    if (len != 0)
123
0
      memcpy (address->priv->path, array->data, len);
124
125
0
    address->priv->path[len] = 0; /* Ensure null-terminated */
126
0
    address->priv->path_len = len;
127
0
  }
128
0
      break;
129
130
0
    case PROP_ABSTRACT:
131
      /* Only set it if it's not the default... */
132
0
      if (g_value_get_boolean (value))
133
0
       address->priv->address_type = G_UNIX_SOCKET_ADDRESS_ABSTRACT_PADDED;
134
0
      break;
135
136
0
    case PROP_ADDRESS_TYPE:
137
      /* Only set it if it's not the default... */
138
0
      if (g_value_get_enum (value) != G_UNIX_SOCKET_ADDRESS_PATH)
139
0
        address->priv->address_type = g_value_get_enum (value);
140
0
      break;
141
142
0
    default:
143
0
      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
144
0
    }
145
0
}
146
147
static void
148
g_unix_socket_address_get_property (GObject    *object,
149
            guint       prop_id,
150
            GValue     *value,
151
            GParamSpec *pspec)
152
0
{
153
0
  GUnixSocketAddress *address = G_UNIX_SOCKET_ADDRESS (object);
154
0
  GByteArray *array;
155
156
0
  switch (prop_id)
157
0
    {
158
0
      case PROP_PATH:
159
0
  g_value_set_string (value, address->priv->path);
160
0
  break;
161
162
0
      case PROP_PATH_AS_ARRAY:
163
0
  array = g_byte_array_sized_new (address->priv->path_len);
164
0
  g_byte_array_append (array, (guint8 *)address->priv->path, address->priv->path_len);
165
0
  g_value_take_boxed (value, array);
166
0
  break;
167
168
0
      case PROP_ABSTRACT:
169
0
  g_value_set_boolean (value, (address->priv->address_type == G_UNIX_SOCKET_ADDRESS_ABSTRACT ||
170
0
             address->priv->address_type == G_UNIX_SOCKET_ADDRESS_ABSTRACT_PADDED));
171
172
0
  break;
173
174
0
      case PROP_ADDRESS_TYPE:
175
0
  g_value_set_enum (value, address->priv->address_type);
176
0
  break;
177
178
0
      default:
179
0
  G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
180
0
    }
181
0
}
182
183
static GSocketFamily
184
g_unix_socket_address_get_family (GSocketAddress *address)
185
0
{
186
0
  g_assert (PF_UNIX == G_SOCKET_FAMILY_UNIX);
187
188
0
  return G_SOCKET_FAMILY_UNIX;
189
0
}
190
191
static gssize
192
g_unix_socket_address_get_native_size (GSocketAddress *address)
193
0
{
194
0
  GUnixSocketAddress *addr = G_UNIX_SOCKET_ADDRESS (address);
195
196
0
  switch (addr->priv->address_type)
197
0
    {
198
0
    case G_UNIX_SOCKET_ADDRESS_ANONYMOUS:
199
0
      return G_STRUCT_OFFSET(struct sockaddr_un, sun_path);
200
0
    case G_UNIX_SOCKET_ADDRESS_ABSTRACT:
201
0
      return G_STRUCT_OFFSET(struct sockaddr_un, sun_path) + addr->priv->path_len + 1;
202
0
    default:
203
0
      return sizeof (struct sockaddr_un);
204
0
    }
205
0
}
206
207
static gboolean
208
g_unix_socket_address_to_native (GSocketAddress *address,
209
         gpointer        dest,
210
         gsize           destlen,
211
         GError        **error)
212
0
{
213
0
  GUnixSocketAddress *addr = G_UNIX_SOCKET_ADDRESS (address);
214
0
  struct sockaddr_un *sock;
215
0
  gssize socklen;
216
217
0
  socklen = g_unix_socket_address_get_native_size (address);
218
0
  g_assert (socklen >= 0);
219
0
  if (destlen < (gsize) socklen)
220
0
    {
221
0
      g_set_error_literal (error, G_IO_ERROR, G_IO_ERROR_NO_SPACE,
222
0
         _("Not enough space for socket address"));
223
0
      return FALSE;
224
0
    }
225
226
0
  sock = (struct sockaddr_un *) dest;
227
0
  memset (sock, 0, socklen);
228
0
  sock->sun_family = AF_UNIX;
229
230
0
  switch (addr->priv->address_type)
231
0
    {
232
0
    case G_UNIX_SOCKET_ADDRESS_INVALID:
233
0
    case G_UNIX_SOCKET_ADDRESS_ANONYMOUS:
234
0
      break;
235
236
0
    case G_UNIX_SOCKET_ADDRESS_PATH:
237
0
      strcpy (sock->sun_path, addr->priv->path);
238
0
      break;
239
240
0
    case G_UNIX_SOCKET_ADDRESS_ABSTRACT:
241
0
    case G_UNIX_SOCKET_ADDRESS_ABSTRACT_PADDED:
242
0
      if (!g_unix_socket_address_abstract_names_supported ())
243
0
  {
244
0
    g_set_error_literal (error, G_IO_ERROR, G_IO_ERROR_NOT_SUPPORTED,
245
0
             _("Abstract UNIX domain socket addresses not supported on this system"));
246
0
    return FALSE;
247
0
  }
248
249
0
      sock->sun_path[0] = 0;
250
0
      memcpy (sock->sun_path+1, addr->priv->path, addr->priv->path_len);
251
0
      break;
252
0
    }
253
254
0
  return TRUE;
255
0
}
256
257
static void
258
g_unix_socket_address_class_init (GUnixSocketAddressClass *klass)
259
0
{
260
0
  GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
261
0
  GSocketAddressClass *gsocketaddress_class = G_SOCKET_ADDRESS_CLASS (klass);
262
263
0
  gobject_class->set_property = g_unix_socket_address_set_property;
264
0
  gobject_class->get_property = g_unix_socket_address_get_property;
265
266
0
  gsocketaddress_class->get_family = g_unix_socket_address_get_family;
267
0
  gsocketaddress_class->to_native = g_unix_socket_address_to_native;
268
0
  gsocketaddress_class->get_native_size = g_unix_socket_address_get_native_size;
269
270
  /**
271
   * GUnixSocketAddress:path:
272
   *
273
   * Unix socket path.
274
   *
275
   * Since: 2.22
276
   */
277
0
  g_object_class_install_property (gobject_class,
278
0
           PROP_PATH,
279
0
           g_param_spec_string ("path", NULL, NULL,
280
0
              NULL,
281
0
              G_PARAM_READWRITE |
282
0
              G_PARAM_CONSTRUCT_ONLY |
283
0
              G_PARAM_STATIC_STRINGS));
284
285
  /**
286
   * GUnixSocketAddress:path-as-array:
287
   *
288
   * Unix socket path, as a byte array.
289
   *
290
   * Since: 2.22
291
   */
292
0
  g_object_class_install_property (gobject_class, PROP_PATH_AS_ARRAY,
293
0
           g_param_spec_boxed ("path-as-array", NULL, NULL,
294
0
                   G_TYPE_BYTE_ARRAY,
295
0
                   G_PARAM_READWRITE |
296
0
                   G_PARAM_CONSTRUCT_ONLY |
297
0
                   G_PARAM_STATIC_STRINGS));
298
299
  /**
300
   * GUnixSocketAddress:abstract:
301
   *
302
   * Whether or not this is an abstract address
303
   *
304
   * Deprecated: Use #GUnixSocketAddress:address-type, which
305
   * distinguishes between zero-padded and non-zero-padded
306
   * abstract addresses.
307
   */
308
0
  g_object_class_install_property (gobject_class, PROP_ABSTRACT,
309
0
           g_param_spec_boolean ("abstract", NULL, NULL,
310
0
               FALSE,
311
0
               G_PARAM_READWRITE |
312
0
               G_PARAM_CONSTRUCT_ONLY |
313
0
               G_PARAM_STATIC_STRINGS));
314
315
  /**
316
   * GUnixSocketAddress:address-type:
317
   *
318
   * The type of Unix socket address.
319
   *
320
   * Since: 2.22
321
   */
322
0
  g_object_class_install_property (gobject_class, PROP_ADDRESS_TYPE,
323
0
           g_param_spec_enum ("address-type", NULL, NULL,
324
0
                  G_TYPE_UNIX_SOCKET_ADDRESS_TYPE,
325
0
                  G_UNIX_SOCKET_ADDRESS_PATH,
326
0
                  G_PARAM_READWRITE |
327
0
                  G_PARAM_CONSTRUCT_ONLY |
328
0
                  G_PARAM_STATIC_STRINGS));
329
0
}
330
331
static void
332
g_unix_socket_address_connectable_iface_init (GSocketConnectableIface *iface)
333
0
{
334
0
  GSocketConnectableIface *parent_iface = g_type_interface_peek_parent (iface);
335
336
0
  iface->enumerate = parent_iface->enumerate;
337
0
  iface->proxy_enumerate = parent_iface->proxy_enumerate;
338
0
  iface->to_string = g_unix_socket_address_connectable_to_string;
339
0
}
340
341
static gchar *
342
g_unix_socket_address_connectable_to_string (GSocketConnectable *connectable)
343
0
{
344
0
  GUnixSocketAddress *ua;
345
0
  GString *out;
346
0
  const gchar *path;
347
0
  gsize path_len, i;
348
349
0
  ua = G_UNIX_SOCKET_ADDRESS (connectable);
350
351
  /* Anonymous sockets have no path. */
352
0
  if (ua->priv->address_type == G_UNIX_SOCKET_ADDRESS_ANONYMOUS)
353
0
    return g_strdup ("anonymous");
354
355
0
  path = g_unix_socket_address_get_path (ua);
356
0
  path_len = g_unix_socket_address_get_path_len (ua);
357
0
  out = g_string_sized_new (path_len);
358
359
  /* Return the #GUnixSocketAddress:path, but with all non-printable characters
360
   * (including nul bytes) escaped to hex. */
361
0
  for (i = 0; i < path_len; i++)
362
0
    {
363
0
      guint8 c = path[i];
364
365
0
      if (g_ascii_isprint (path[i]))
366
0
        g_string_append_c (out, c);
367
0
      else
368
0
        g_string_append_printf (out, "\\x%02x", (guint) c);
369
0
    }
370
371
0
  return g_string_free (out, FALSE);
372
0
}
373
374
static void
375
g_unix_socket_address_init (GUnixSocketAddress *address)
376
0
{
377
0
  address->priv = g_unix_socket_address_get_instance_private (address);
378
379
0
  memset (address->priv->path, 0, sizeof (address->priv->path));
380
0
  address->priv->path_len = -1;
381
0
  address->priv->address_type = G_UNIX_SOCKET_ADDRESS_PATH;
382
0
}
383
384
/**
385
 * g_unix_socket_address_new:
386
 * @path: the socket path
387
 *
388
 * Creates a new #GUnixSocketAddress for @path.
389
 *
390
 * To create abstract socket addresses, on systems that support that,
391
 * use g_unix_socket_address_new_abstract().
392
 *
393
 * Returns: a new #GUnixSocketAddress
394
 *
395
 * Since: 2.22
396
 */
397
GSocketAddress *
398
g_unix_socket_address_new (const gchar *path)
399
0
{
400
0
  return g_object_new (G_TYPE_UNIX_SOCKET_ADDRESS,
401
0
           "path", path,
402
0
           "abstract", FALSE,
403
0
           NULL);
404
0
}
405
406
/**
407
 * g_unix_socket_address_new_abstract:
408
 * @path: (array length=path_len) (element-type gchar): the abstract name
409
 * @path_len: the length of @path, or -1
410
 *
411
 * Creates a new %G_UNIX_SOCKET_ADDRESS_ABSTRACT_PADDED
412
 * #GUnixSocketAddress for @path.
413
 *
414
 * Returns: a new #GUnixSocketAddress
415
 *
416
 * Deprecated: Use g_unix_socket_address_new_with_type().
417
 */
418
GSocketAddress *
419
g_unix_socket_address_new_abstract (const gchar *path,
420
            gint         path_len)
421
0
{
422
0
  return g_unix_socket_address_new_with_type (path, path_len,
423
0
                G_UNIX_SOCKET_ADDRESS_ABSTRACT_PADDED);
424
0
}
425
426
/**
427
 * g_unix_socket_address_new_with_type:
428
 * @path: (array length=path_len) (element-type gchar): the name
429
 * @path_len: the length of @path, or -1
430
 * @type: a #GUnixSocketAddressType
431
 *
432
 * Creates a new #GUnixSocketAddress of type @type with name @path.
433
 *
434
 * If @type is %G_UNIX_SOCKET_ADDRESS_PATH, this is equivalent to
435
 * calling g_unix_socket_address_new().
436
 *
437
 * If @type is %G_UNIX_SOCKET_ADDRESS_ANONYMOUS, @path and @path_len will be
438
 * ignored.
439
 *
440
 * If @path_type is %G_UNIX_SOCKET_ADDRESS_ABSTRACT, then @path_len
441
 * bytes of @path will be copied to the socket's path, and only those
442
 * bytes will be considered part of the name. (If @path_len is -1,
443
 * then @path is assumed to be NUL-terminated.) For example, if @path
444
 * was "test", then calling g_socket_address_get_native_size() on the
445
 * returned socket would return 7 (2 bytes of overhead, 1 byte for the
446
 * abstract-socket indicator byte, and 4 bytes for the name "test").
447
 *
448
 * If @path_type is %G_UNIX_SOCKET_ADDRESS_ABSTRACT_PADDED, then
449
 * @path_len bytes of @path will be copied to the socket's path, the
450
 * rest of the path will be padded with 0 bytes, and the entire
451
 * zero-padded buffer will be considered the name. (As above, if
452
 * @path_len is -1, then @path is assumed to be NUL-terminated.) In
453
 * this case, g_socket_address_get_native_size() will always return
454
 * the full size of a `struct sockaddr_un`, although
455
 * g_unix_socket_address_get_path_len() will still return just the
456
 * length of @path.
457
 *
458
 * %G_UNIX_SOCKET_ADDRESS_ABSTRACT is preferred over
459
 * %G_UNIX_SOCKET_ADDRESS_ABSTRACT_PADDED for new programs. Of course,
460
 * when connecting to a server created by another process, you must
461
 * use the appropriate type corresponding to how that process created
462
 * its listening socket.
463
 *
464
 * Returns: a new #GUnixSocketAddress
465
 *
466
 * Since: 2.26
467
 */
468
GSocketAddress *
469
g_unix_socket_address_new_with_type (const gchar            *path,
470
             gint                    path_len,
471
             GUnixSocketAddressType  type)
472
0
{
473
0
  GSocketAddress *address;
474
0
  GByteArray *array;
475
0
  size_t path_len_unsigned;
476
477
0
  if (type == G_UNIX_SOCKET_ADDRESS_ANONYMOUS)
478
0
    path_len_unsigned = 0;
479
0
  else if (path_len < 0)
480
0
    path_len_unsigned = strlen (path);
481
0
  else
482
0
    path_len_unsigned = (size_t) path_len;
483
484
  /* The code below can’t handle anything longer. */
485
0
  g_return_val_if_fail (path_len_unsigned <= G_MAXUINT, NULL);
486
487
0
  array = g_byte_array_sized_new (path_len_unsigned);
488
489
0
  g_byte_array_append (array, (guint8 *)path, path_len_unsigned);
490
491
0
  address = g_object_new (G_TYPE_UNIX_SOCKET_ADDRESS,
492
0
        "path-as-array", array,
493
0
        "address-type", type,
494
0
        NULL);
495
496
0
  g_byte_array_unref (array);
497
498
0
  return address;
499
0
}
500
501
/**
502
 * g_unix_socket_address_get_path:
503
 * @address: a #GInetSocketAddress
504
 *
505
 * Gets @address's path, or for abstract sockets the "name".
506
 *
507
 * Guaranteed to be zero-terminated, but an abstract socket
508
 * may contain embedded zeros, and thus you should use
509
 * g_unix_socket_address_get_path_len() to get the true length
510
 * of this string.
511
 *
512
 * Returns: the path for @address
513
 *
514
 * Since: 2.22
515
 */
516
const char *
517
g_unix_socket_address_get_path (GUnixSocketAddress *address)
518
0
{
519
0
  return address->priv->path;
520
0
}
521
522
/**
523
 * g_unix_socket_address_get_path_len:
524
 * @address: a #GInetSocketAddress
525
 *
526
 * Gets the length of @address's path.
527
 *
528
 * For details, see g_unix_socket_address_get_path().
529
 *
530
 * Returns: the length of the path
531
 *
532
 * Since: 2.22
533
 */
534
gsize
535
g_unix_socket_address_get_path_len (GUnixSocketAddress *address)
536
0
{
537
0
  return address->priv->path_len;
538
0
}
539
540
/**
541
 * g_unix_socket_address_get_address_type:
542
 * @address: a #GInetSocketAddress
543
 *
544
 * Gets @address's type.
545
 *
546
 * Returns: a #GUnixSocketAddressType
547
 *
548
 * Since: 2.26
549
 */
550
GUnixSocketAddressType
551
g_unix_socket_address_get_address_type (GUnixSocketAddress *address)
552
0
{
553
0
  return address->priv->address_type;
554
0
}
555
556
/**
557
 * g_unix_socket_address_get_is_abstract:
558
 * @address: a #GInetSocketAddress
559
 *
560
 * Tests if @address is abstract.
561
 *
562
 * Returns: %TRUE if the address is abstract, %FALSE otherwise
563
 *
564
 * Since: 2.22
565
 *
566
 * Deprecated: Use g_unix_socket_address_get_address_type()
567
 */
568
gboolean
569
g_unix_socket_address_get_is_abstract (GUnixSocketAddress *address)
570
0
{
571
0
  return (address->priv->address_type == G_UNIX_SOCKET_ADDRESS_ABSTRACT ||
572
0
    address->priv->address_type == G_UNIX_SOCKET_ADDRESS_ABSTRACT_PADDED);
573
0
}
574
575
/**
576
 * g_unix_socket_address_abstract_names_supported:
577
 *
578
 * Checks if abstract UNIX domain socket names are supported.
579
 *
580
 * Returns: %TRUE if supported, %FALSE otherwise
581
 *
582
 * Since: 2.22
583
 */
584
gboolean
585
g_unix_socket_address_abstract_names_supported (void)
586
0
{
587
0
#ifdef __linux__
588
0
  return TRUE;
589
#else
590
  return FALSE;
591
#endif
592
0
}