gkdbus: Fix underflow and unreachable code bug
[platform/upstream/glib.git] / gio / gunixsocketaddress.c
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 {
105   GUnixSocketAddress *address = G_UNIX_SOCKET_ADDRESS (object);
106   const char *str;
107   GByteArray *array;
108   gsize len;
109
110   switch (prop_id)
111     {
112     case PROP_PATH:
113       str = g_value_get_string (value);
114       if (str)
115         {
116           g_strlcpy (address->priv->path, str,
117                      sizeof (address->priv->path));
118           address->priv->path_len = strlen (address->priv->path);
119         }
120       break;
121
122     case PROP_PATH_AS_ARRAY:
123       array = g_value_get_boxed (value);
124
125       if (array)
126         {
127           /* Clip to fit in UNIX_PATH_MAX with zero termination or first byte */
128           len = MIN (array->len, UNIX_PATH_MAX-1);
129
130           if (len != 0)
131             memcpy (address->priv->path, array->data, len);
132
133           address->priv->path[len] = 0; /* Ensure null-terminated */
134           address->priv->path_len = len;
135         }
136       break;
137
138     case PROP_ABSTRACT:
139       /* Only set it if it's not the default... */
140       if (g_value_get_boolean (value))
141        address->priv->address_type = G_UNIX_SOCKET_ADDRESS_ABSTRACT_PADDED;
142       break;
143
144     case PROP_ADDRESS_TYPE:
145       /* Only set it if it's not the default... */
146       if (g_value_get_enum (value) != G_UNIX_SOCKET_ADDRESS_PATH)
147         address->priv->address_type = g_value_get_enum (value);
148       break;
149
150     default:
151       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
152     }
153 }
154
155 static void
156 g_unix_socket_address_get_property (GObject    *object,
157                                     guint       prop_id,
158                                     GValue     *value,
159                                     GParamSpec *pspec)
160 {
161   GUnixSocketAddress *address = G_UNIX_SOCKET_ADDRESS (object);
162   GByteArray *array;
163
164   switch (prop_id)
165     {
166       case PROP_PATH:
167         g_value_set_string (value, address->priv->path);
168         break;
169
170       case PROP_PATH_AS_ARRAY:
171         array = g_byte_array_sized_new (address->priv->path_len);
172         g_byte_array_append (array, (guint8 *)address->priv->path, address->priv->path_len);
173         g_value_take_boxed (value, array);
174         break;
175
176       case PROP_ABSTRACT:
177         g_value_set_boolean (value, (address->priv->address_type == G_UNIX_SOCKET_ADDRESS_ABSTRACT ||
178                                      address->priv->address_type == G_UNIX_SOCKET_ADDRESS_ABSTRACT_PADDED));
179
180         break;
181
182       case PROP_ADDRESS_TYPE:
183         g_value_set_enum (value, address->priv->address_type);
184         break;
185
186       default:
187         G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
188     }
189 }
190
191 static GSocketFamily
192 g_unix_socket_address_get_family (GSocketAddress *address)
193 {
194   g_assert (PF_UNIX == G_SOCKET_FAMILY_UNIX);
195
196   return G_SOCKET_FAMILY_UNIX;
197 }
198
199 static gssize
200 g_unix_socket_address_get_native_size (GSocketAddress *address)
201 {
202   GUnixSocketAddress *addr = G_UNIX_SOCKET_ADDRESS (address);
203
204   switch (addr->priv->address_type)
205     {
206     case G_UNIX_SOCKET_ADDRESS_ANONYMOUS:
207       return G_STRUCT_OFFSET(struct sockaddr_un, sun_path);
208     case G_UNIX_SOCKET_ADDRESS_ABSTRACT:
209       return G_STRUCT_OFFSET(struct sockaddr_un, sun_path) + addr->priv->path_len + 1;
210     default:
211       return sizeof (struct sockaddr_un);
212     }
213 }
214
215 static gboolean
216 g_unix_socket_address_to_native (GSocketAddress *address,
217                                  gpointer        dest,
218                                  gsize           destlen,
219                                  GError        **error)
220 {
221   GUnixSocketAddress *addr = G_UNIX_SOCKET_ADDRESS (address);
222   struct sockaddr_un *sock;
223   gssize socklen;
224
225   socklen = g_unix_socket_address_get_native_size (address);
226   g_assert (socklen >= 0);
227   if (destlen < (gsize) socklen)
228     {
229       g_set_error_literal (error, G_IO_ERROR, G_IO_ERROR_NO_SPACE,
230                            _("Not enough space for socket address"));
231       return FALSE;
232     }
233
234   sock = (struct sockaddr_un *) dest;
235   memset (sock, 0, socklen);
236   sock->sun_family = AF_UNIX;
237
238   switch (addr->priv->address_type)
239     {
240     case G_UNIX_SOCKET_ADDRESS_INVALID:
241     case G_UNIX_SOCKET_ADDRESS_ANONYMOUS:
242       break;
243
244     case G_UNIX_SOCKET_ADDRESS_PATH:
245       strcpy (sock->sun_path, addr->priv->path);
246       break;
247
248     case G_UNIX_SOCKET_ADDRESS_ABSTRACT:
249     case G_UNIX_SOCKET_ADDRESS_ABSTRACT_PADDED:
250       if (!g_unix_socket_address_abstract_names_supported ())
251         {
252           g_set_error_literal (error, G_IO_ERROR, G_IO_ERROR_NOT_SUPPORTED,
253                                _("Abstract UNIX domain socket addresses not supported on this system"));
254           return FALSE;
255         }
256
257       sock->sun_path[0] = 0;
258       memcpy (sock->sun_path+1, addr->priv->path, addr->priv->path_len);
259       break;
260     }
261
262   return TRUE;
263 }
264
265 static void
266 g_unix_socket_address_class_init (GUnixSocketAddressClass *klass)
267 {
268   GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
269   GSocketAddressClass *gsocketaddress_class = G_SOCKET_ADDRESS_CLASS (klass);
270
271   gobject_class->set_property = g_unix_socket_address_set_property;
272   gobject_class->get_property = g_unix_socket_address_get_property;
273
274   gsocketaddress_class->get_family = g_unix_socket_address_get_family;
275   gsocketaddress_class->to_native = g_unix_socket_address_to_native;
276   gsocketaddress_class->get_native_size = g_unix_socket_address_get_native_size;
277
278   g_object_class_install_property (gobject_class,
279                                    PROP_PATH,
280                                    g_param_spec_string ("path",
281                                                         P_("Path"),
282                                                         P_("UNIX socket path"),
283                                                         NULL,
284                                                         G_PARAM_READWRITE |
285                                                         G_PARAM_CONSTRUCT_ONLY |
286                                                         G_PARAM_STATIC_STRINGS));
287   g_object_class_install_property (gobject_class, PROP_PATH_AS_ARRAY,
288                                    g_param_spec_boxed ("path-as-array",
289                                                        P_("Path array"),
290                                                        P_("UNIX socket path, as byte array"),
291                                                        G_TYPE_BYTE_ARRAY,
292                                                        G_PARAM_READWRITE |
293                                                        G_PARAM_CONSTRUCT_ONLY |
294                                                        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   g_object_class_install_property (gobject_class, PROP_ABSTRACT,
305                                    g_param_spec_boolean ("abstract",
306                                                          P_("Abstract"),
307                                                          P_("Whether or not this is an abstract address"),
308                                                          FALSE,
309                                                          G_PARAM_READWRITE |
310                                                          G_PARAM_CONSTRUCT_ONLY |
311                                                          G_PARAM_STATIC_STRINGS));
312   g_object_class_install_property (gobject_class, PROP_ADDRESS_TYPE,
313                                    g_param_spec_enum ("address-type",
314                                                       P_("Address type"),
315                                                       P_("The type of UNIX socket address"),
316                                                       G_TYPE_UNIX_SOCKET_ADDRESS_TYPE,
317                                                       G_UNIX_SOCKET_ADDRESS_PATH,
318                                                       G_PARAM_READWRITE |
319                                                       G_PARAM_CONSTRUCT_ONLY |
320                                                       G_PARAM_STATIC_STRINGS));
321 }
322
323 static void
324 g_unix_socket_address_connectable_iface_init (GSocketConnectableIface *iface)
325 {
326   GSocketConnectableIface *parent_iface = g_type_interface_peek_parent (iface);
327
328   iface->enumerate = parent_iface->enumerate;
329   iface->proxy_enumerate = parent_iface->proxy_enumerate;
330   iface->to_string = g_unix_socket_address_connectable_to_string;
331 }
332
333 static gchar *
334 g_unix_socket_address_connectable_to_string (GSocketConnectable *connectable)
335 {
336   GUnixSocketAddress *ua;
337   GString *out;
338   const gchar *path;
339   gsize path_len, i;
340
341   ua = G_UNIX_SOCKET_ADDRESS (connectable);
342
343   /* Anonymous sockets have no path. */
344   if (ua->priv->address_type == G_UNIX_SOCKET_ADDRESS_ANONYMOUS)
345     return g_strdup ("anonymous");
346
347   path = g_unix_socket_address_get_path (ua);
348   path_len = g_unix_socket_address_get_path_len (ua);
349   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   for (i = 0; i < path_len; i++)
354     {
355       guint8 c = path[i];
356
357       if (g_ascii_isprint (path[i]))
358         g_string_append_c (out, c);
359       else
360         g_string_append_printf (out, "\\x%02x", (guint) c);
361     }
362
363   return g_string_free (out, FALSE);
364 }
365
366 static void
367 g_unix_socket_address_init (GUnixSocketAddress *address)
368 {
369   address->priv = g_unix_socket_address_get_instance_private (address);
370
371   memset (address->priv->path, 0, sizeof (address->priv->path));
372   address->priv->path_len = -1;
373   address->priv->address_type = G_UNIX_SOCKET_ADDRESS_PATH;
374 }
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 {
392   return g_object_new (G_TYPE_UNIX_SOCKET_ADDRESS,
393                        "path", path,
394                        "abstract", FALSE,
395                        NULL);
396 }
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 {
414   return g_unix_socket_address_new_with_type (path, path_len,
415                                               G_UNIX_SOCKET_ADDRESS_ABSTRACT_PADDED);
416 }
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 {
465   GSocketAddress *address;
466   GByteArray *array;
467
468   if (type == G_UNIX_SOCKET_ADDRESS_ANONYMOUS)
469     path_len = 0;
470   else if (path_len == -1)
471     path_len = strlen (path);
472
473   array = g_byte_array_sized_new (path_len);
474
475   g_byte_array_append (array, (guint8 *)path, path_len);
476
477   address = g_object_new (G_TYPE_UNIX_SOCKET_ADDRESS,
478                           "path-as-array", array,
479                           "address-type", type,
480                           NULL);
481
482   g_byte_array_unref (array);
483
484   return address;
485 }
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 {
505   return address->priv->path;
506 }
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 {
523   return address->priv->path_len;
524 }
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 {
539   return address->priv->address_type;
540 }
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 {
557   return (address->priv->address_type == G_UNIX_SOCKET_ADDRESS_ABSTRACT ||
558           address->priv->address_type == G_UNIX_SOCKET_ADDRESS_ABSTRACT_PADDED);
559 }
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 {
573 #ifdef __linux__
574   return TRUE;
575 #else
576   return FALSE;
577 #endif
578 }