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