Coverage Report

Created: 2025-07-01 07:09

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