Coverage Report

Created: 2025-06-13 06:55

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