gkdbus: Fix underflow and unreachable code bug
[platform/upstream/glib.git] / gio / gunixconnection.c
1 /* GIO - GLib Input, Output and Streaming Library
2  *
3  * Copyright © 2009 Codethink Limited
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  * See the included COPYING file for more information.
13  *
14  * Authors: Ryan Lortie <desrt@desrt.ca>
15  */
16
17 #include "config.h"
18
19 #include "gunixconnection.h"
20 #include "gnetworking.h"
21 #include "gsocket.h"
22 #include "gsocketcontrolmessage.h"
23 #include "gunixcredentialsmessage.h"
24 #include "gunixfdmessage.h"
25 #include "glibintl.h"
26
27 #include <errno.h>
28 #include <string.h>
29 #ifdef HAVE_UNISTD_H
30 #include <unistd.h>
31 #endif
32
33 /**
34  * SECTION:gunixconnection
35  * @title: GUnixConnection
36  * @short_description: A UNIX domain GSocketConnection
37  * @include: gio/gunixconnection.h
38  * @see_also: #GSocketConnection.
39  *
40  * This is the subclass of #GSocketConnection that is created
41  * for UNIX domain sockets.
42  *
43  * It contains functions to do some of the UNIX socket specific
44  * functionality like passing file descriptors.
45  *
46  * Since GLib 2.72, #GUnixConnection is available on all platforms. It requires
47  * underlying system support (such as Windows 10 with `AF_UNIX`) at run time.
48  *
49  * Before GLib 2.72, `<gio/gunixconnection.h>` belonged to the UNIX-specific GIO
50  * interfaces, thus you had to use the `gio-unix-2.0.pc` pkg-config file when
51  * using it. This is no longer necessary since GLib 2.72.
52  *
53  * Since: 2.22
54  */
55
56 /**
57  * GUnixConnection:
58  *
59  * #GUnixConnection is an opaque data structure and can only be accessed
60  * using the following functions.
61  **/
62
63 G_DEFINE_TYPE_WITH_CODE (GUnixConnection, g_unix_connection,
64                          G_TYPE_SOCKET_CONNECTION,
65   g_socket_connection_factory_register_type (g_define_type_id,
66                                              G_SOCKET_FAMILY_UNIX,
67                                              G_SOCKET_TYPE_STREAM,
68                                              G_SOCKET_PROTOCOL_DEFAULT);
69                          );
70
71 /**
72  * g_unix_connection_send_fd:
73  * @connection: a #GUnixConnection
74  * @fd: a file descriptor
75  * @cancellable: (nullable): optional #GCancellable object, %NULL to ignore.
76  * @error: (nullable): #GError for error reporting, or %NULL to ignore.
77  *
78  * Passes a file descriptor to the receiving side of the
79  * connection. The receiving end has to call g_unix_connection_receive_fd()
80  * to accept the file descriptor.
81  *
82  * As well as sending the fd this also writes a single byte to the
83  * stream, as this is required for fd passing to work on some
84  * implementations.
85  *
86  * Returns: a %TRUE on success, %NULL on error.
87  *
88  * Since: 2.22
89  */
90 gboolean
91 g_unix_connection_send_fd (GUnixConnection  *connection,
92                            gint              fd,
93                            GCancellable     *cancellable,
94                            GError          **error)
95 {
96 #ifdef G_OS_UNIX
97   GSocketControlMessage *scm;
98   GSocket *socket;
99
100   g_return_val_if_fail (G_IS_UNIX_CONNECTION (connection), FALSE);
101   g_return_val_if_fail (fd >= 0, FALSE);
102
103   scm = g_unix_fd_message_new ();
104
105   if (!g_unix_fd_message_append_fd (G_UNIX_FD_MESSAGE (scm), fd, error))
106     {
107       g_object_unref (scm);
108       return FALSE;
109     }
110
111   g_object_get (connection, "socket", &socket, NULL);
112   if (g_socket_send_message (socket, NULL, NULL, 0, &scm, 1, 0, cancellable, error) != 1)
113     /* XXX could it 'fail' with zero? */
114     {
115       g_object_unref (socket);
116       g_object_unref (scm);
117
118       return FALSE;
119     }
120
121   g_object_unref (socket);
122   g_object_unref (scm);
123
124   return TRUE;
125 #else
126   g_set_error_literal (error, G_IO_ERROR, G_IO_ERROR_NOT_SUPPORTED,
127                        _("Sending FD is not supported"));
128   return FALSE;
129 #endif
130 }
131
132 /**
133  * g_unix_connection_receive_fd:
134  * @connection: a #GUnixConnection
135  * @cancellable: (nullable): optional #GCancellable object, %NULL to ignore
136  * @error: (nullable): #GError for error reporting, or %NULL to ignore
137  *
138  * Receives a file descriptor from the sending end of the connection.
139  * The sending end has to call g_unix_connection_send_fd() for this
140  * to work.
141  *
142  * As well as reading the fd this also reads a single byte from the
143  * stream, as this is required for fd passing to work on some
144  * implementations.
145  *
146  * Returns: a file descriptor on success, -1 on error.
147  *
148  * Since: 2.22
149  **/
150 gint
151 g_unix_connection_receive_fd (GUnixConnection  *connection,
152                               GCancellable     *cancellable,
153                               GError          **error)
154 {
155 #ifdef G_OS_UNIX
156   GSocketControlMessage **scms;
157   gint *fds, nfd, fd, nscm;
158   GUnixFDMessage *fdmsg;
159   GSocket *socket;
160
161   g_return_val_if_fail (G_IS_UNIX_CONNECTION (connection), -1);
162
163   g_object_get (connection, "socket", &socket, NULL);
164   if (g_socket_receive_message (socket, NULL, NULL, 0,
165                                 &scms, &nscm, NULL, cancellable, error) != 1)
166     /* XXX it _could_ 'fail' with zero. */
167     {
168       g_object_unref (socket);
169
170       return -1;
171     }
172
173   g_object_unref (socket);
174
175   if (nscm != 1)
176     {
177       gint i;
178
179       g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED,
180                    g_dngettext (NULL,
181                                 "Expecting 1 control message, got %d",
182                                 "Expecting 1 control message, got %d",
183                                 nscm),
184                    nscm);
185
186       for (i = 0; i < nscm; i++)
187         g_object_unref (scms[i]);
188
189       g_free (scms);
190
191       return -1;
192     }
193
194   if (!G_IS_UNIX_FD_MESSAGE (scms[0]))
195     {
196       g_set_error_literal (error, G_IO_ERROR, G_IO_ERROR_FAILED,
197                            _("Unexpected type of ancillary data"));
198       g_object_unref (scms[0]);
199       g_free (scms);
200
201       return -1;
202     }
203
204   fdmsg = G_UNIX_FD_MESSAGE (scms[0]);
205   g_free (scms);
206
207   fds = g_unix_fd_message_steal_fds (fdmsg, &nfd);
208   g_object_unref (fdmsg);
209
210   if (nfd != 1)
211     {
212       gint i;
213
214       g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED,
215                    g_dngettext (NULL,
216                                 "Expecting one fd, but got %d\n",
217                                 "Expecting one fd, but got %d\n",
218                                 nfd),
219                    nfd);
220
221       for (i = 0; i < nfd; i++)
222         close (fds[i]);
223
224       g_free (fds);
225
226       return -1;
227     }
228
229   fd = *fds;
230   g_free (fds);
231
232   if (fd < 0)
233     {
234       g_set_error_literal (error, G_IO_ERROR, G_IO_ERROR_FAILED,
235                            _("Received invalid fd"));
236       fd = -1;
237     }
238
239   return fd;
240 #else
241   g_set_error_literal (error, G_IO_ERROR, G_IO_ERROR_NOT_SUPPORTED,
242                        _("Receiving FD is not supported"));
243   return -1;
244 #endif
245 }
246
247 static void
248 g_unix_connection_init (GUnixConnection *connection)
249 {
250 }
251
252 static void
253 g_unix_connection_class_init (GUnixConnectionClass *class)
254 {
255 }
256
257 /* TODO: Other stuff we might want to add are:
258 void                    g_unix_connection_send_fd_async                 (GUnixConnection      *connection,
259                                                                          gint                  fd,
260                                                                          gboolean              close,
261                                                                          gint                  io_priority,
262                                                                          GAsyncReadyCallback   callback,
263                                                                          gpointer              user_data);
264 gboolean                g_unix_connection_send_fd_finish                (GUnixConnection      *connection,
265                                                                          GError              **error);
266
267 gboolean                g_unix_connection_send_fds                      (GUnixConnection      *connection,
268                                                                          gint                 *fds,
269                                                                          gint                  nfds,
270                                                                          GError              **error);
271 void                    g_unix_connection_send_fds_async                (GUnixConnection      *connection,
272                                                                          gint                 *fds,
273                                                                          gint                  nfds,
274                                                                          gint                  io_priority,
275                                                                          GAsyncReadyCallback   callback,
276                                                                          gpointer              user_data);
277 gboolean                g_unix_connection_send_fds_finish               (GUnixConnection      *connection,
278                                                                          GError              **error);
279
280 void                    g_unix_connection_receive_fd_async              (GUnixConnection      *connection,
281                                                                          gint                  io_priority,
282                                                                          GAsyncReadyCallback   callback,
283                                                                          gpointer              user_data);
284 gint                    g_unix_connection_receive_fd_finish             (GUnixConnection      *connection,
285                                                                          GError              **error);
286
287
288 gboolean                g_unix_connection_send_fake_credentials         (GUnixConnection      *connection,
289                                                                          guint64               pid,
290                                                                          guint64               uid,
291                                                                          guint64               gid,
292                                                                          GError              **error);
293 void                    g_unix_connection_send_fake_credentials_async   (GUnixConnection      *connection,
294                                                                          guint64               pid,
295                                                                          guint64               uid,
296                                                                          guint64               gid,
297                                                                          gint                  io_priority,
298                                                                          GAsyncReadyCallback   callback,
299                                                                          gpointer              user_data);
300 gboolean                g_unix_connection_send_fake_credentials_finish  (GUnixConnection      *connection,
301                                                                          GError              **error);
302
303 gboolean                g_unix_connection_create_pair                   (GUnixConnection     **one,
304                                                                          GUnixConnection     **two,
305                                                                          GError              **error);
306 */
307
308
309 /**
310  * g_unix_connection_send_credentials:
311  * @connection: A #GUnixConnection.
312  * @cancellable: (nullable): A #GCancellable or %NULL.
313  * @error: Return location for error or %NULL.
314  *
315  * Passes the credentials of the current user the receiving side
316  * of the connection. The receiving end has to call
317  * g_unix_connection_receive_credentials() (or similar) to accept the
318  * credentials.
319  *
320  * As well as sending the credentials this also writes a single NUL
321  * byte to the stream, as this is required for credentials passing to
322  * work on some implementations.
323  *
324  * This method can be expected to be available on the following platforms:
325  *
326  * - Linux since GLib 2.26
327  * - FreeBSD since GLib 2.26
328  * - GNU/kFreeBSD since GLib 2.36
329  * - Solaris, Illumos and OpenSolaris since GLib 2.40
330  * - GNU/Hurd since GLib 2.40
331  *
332  * Other ways to exchange credentials with a foreign peer includes the
333  * #GUnixCredentialsMessage type and g_socket_get_credentials() function.
334  *
335  * Returns: %TRUE on success, %FALSE if @error is set.
336  *
337  * Since: 2.26
338  */
339 gboolean
340 g_unix_connection_send_credentials (GUnixConnection      *connection,
341                                     GCancellable         *cancellable,
342                                     GError              **error)
343 {
344   GCredentials *credentials;
345   GSocketControlMessage *scm;
346   GSocket *socket;
347   gboolean ret;
348   GOutputVector vector;
349   guchar nul_byte[1] = {'\0'};
350   gint num_messages;
351
352   g_return_val_if_fail (G_IS_UNIX_CONNECTION (connection), FALSE);
353   g_return_val_if_fail (error == NULL || *error == NULL, FALSE);
354
355   ret = FALSE;
356
357   credentials = g_credentials_new ();
358
359   vector.buffer = &nul_byte;
360   vector.size = 1;
361
362   if (g_unix_credentials_message_is_supported ())
363     {
364       scm = g_unix_credentials_message_new_with_credentials (credentials);
365       num_messages = 1;
366     }
367   else
368     {
369       scm = NULL;
370       num_messages = 0;
371     }
372
373   g_object_get (connection, "socket", &socket, NULL);
374   if (g_socket_send_message (socket,
375                              NULL, /* address */
376                              &vector,
377                              1,
378                              &scm,
379                              num_messages,
380                              G_SOCKET_MSG_NONE,
381                              cancellable,
382                              error) != 1)
383     {
384       g_prefix_error (error, _("Error sending credentials: "));
385       goto out;
386     }
387
388   ret = TRUE;
389
390  out:
391   g_object_unref (socket);
392   if (scm != NULL)
393     g_object_unref (scm);
394   g_object_unref (credentials);
395   return ret;
396 }
397
398 static void
399 send_credentials_async_thread (GTask         *task,
400                                gpointer       source_object,
401                                gpointer       task_data,
402                                GCancellable  *cancellable)
403 {
404   GError *error = NULL;
405
406   if (g_unix_connection_send_credentials (G_UNIX_CONNECTION (source_object),
407                                           cancellable,
408                                           &error))
409     g_task_return_boolean (task, TRUE);
410   else
411     g_task_return_error (task, error);
412   g_object_unref (task);
413 }
414
415 /**
416  * g_unix_connection_send_credentials_async:
417  * @connection: A #GUnixConnection.
418  * @cancellable: (nullable): optional #GCancellable object, %NULL to ignore.
419  * @callback: (scope async): a #GAsyncReadyCallback
420  *   to call when the request is satisfied
421  * @user_data: the data to pass to callback function
422  *
423  * Asynchronously send credentials.
424  *
425  * For more details, see g_unix_connection_send_credentials() which is
426  * the synchronous version of this call.
427  *
428  * When the operation is finished, @callback will be called. You can then call
429  * g_unix_connection_send_credentials_finish() to get the result of the operation.
430  *
431  * Since: 2.32
432  **/
433 void
434 g_unix_connection_send_credentials_async (GUnixConnection      *connection,
435                                           GCancellable         *cancellable,
436                                           GAsyncReadyCallback   callback,
437                                           gpointer              user_data)
438 {
439   GTask *task;
440
441   task = g_task_new (connection, cancellable, callback, user_data);
442   g_task_set_source_tag (task, g_unix_connection_send_credentials_async);
443   g_task_run_in_thread (task, send_credentials_async_thread);
444 }
445
446 /**
447  * g_unix_connection_send_credentials_finish:
448  * @connection: A #GUnixConnection.
449  * @result: a #GAsyncResult.
450  * @error: a #GError, or %NULL
451  *
452  * Finishes an asynchronous send credentials operation started with
453  * g_unix_connection_send_credentials_async().
454  *
455  * Returns: %TRUE if the operation was successful, otherwise %FALSE.
456  *
457  * Since: 2.32
458  **/
459 gboolean
460 g_unix_connection_send_credentials_finish (GUnixConnection *connection,
461                                            GAsyncResult    *result,
462                                            GError         **error)
463 {
464   g_return_val_if_fail (g_task_is_valid (result, connection), FALSE);
465
466   return g_task_propagate_boolean (G_TASK (result), error);
467 }
468
469 /**
470  * g_unix_connection_receive_credentials:
471  * @connection: A #GUnixConnection.
472  * @cancellable: (nullable): A #GCancellable or %NULL.
473  * @error: Return location for error or %NULL.
474  *
475  * Receives credentials from the sending end of the connection.  The
476  * sending end has to call g_unix_connection_send_credentials() (or
477  * similar) for this to work.
478  *
479  * As well as reading the credentials this also reads (and discards) a
480  * single byte from the stream, as this is required for credentials
481  * passing to work on some implementations.
482  *
483  * This method can be expected to be available on the following platforms:
484  *
485  * - Linux since GLib 2.26
486  * - FreeBSD since GLib 2.26
487  * - GNU/kFreeBSD since GLib 2.36
488  * - Solaris, Illumos and OpenSolaris since GLib 2.40
489  * - GNU/Hurd since GLib 2.40
490  *
491  * Other ways to exchange credentials with a foreign peer includes the
492  * #GUnixCredentialsMessage type and g_socket_get_credentials() function.
493  *
494  * Returns: (transfer full): Received credentials on success (free with
495  * g_object_unref()), %NULL if @error is set.
496  *
497  * Since: 2.26
498  */
499 GCredentials *
500 g_unix_connection_receive_credentials (GUnixConnection      *connection,
501                                        GCancellable         *cancellable,
502                                        GError              **error)
503 {
504   GCredentials *ret;
505   GSocketControlMessage **scms;
506   gint nscm;
507   GSocket *socket;
508   gint n;
509   gssize num_bytes_read;
510 #ifdef __linux__
511   gboolean turn_off_so_passcreds;
512 #endif
513
514   g_return_val_if_fail (G_IS_UNIX_CONNECTION (connection), NULL);
515   g_return_val_if_fail (error == NULL || *error == NULL, NULL);
516
517   ret = NULL;
518   scms = NULL;
519
520   g_object_get (connection, "socket", &socket, NULL);
521
522   /* On Linux, we need to turn on SO_PASSCRED if it isn't enabled
523    * already. We also need to turn it off when we're done.  See
524    * #617483 for more discussion.
525    */
526 #ifdef __linux__
527   {
528     gint opt_val;
529
530     turn_off_so_passcreds = FALSE;
531     opt_val = 0;
532     if (!g_socket_get_option (socket,
533                               SOL_SOCKET,
534                               SO_PASSCRED,
535                               &opt_val,
536                               NULL))
537       {
538         int errsv = errno;
539         g_set_error (error,
540                      G_IO_ERROR,
541                      g_io_error_from_errno (errsv),
542                      _("Error checking if SO_PASSCRED is enabled for socket: %s"),
543                      g_strerror (errsv));
544         goto out;
545       }
546     if (opt_val == 0)
547       {
548         if (!g_socket_set_option (socket,
549                                   SOL_SOCKET,
550                                   SO_PASSCRED,
551                                   TRUE,
552                                   NULL))
553           {
554             int errsv = errno;
555             g_set_error (error,
556                          G_IO_ERROR,
557                          g_io_error_from_errno (errsv),
558                          _("Error enabling SO_PASSCRED: %s"),
559                          g_strerror (errsv));
560             goto out;
561           }
562         turn_off_so_passcreds = TRUE;
563       }
564   }
565 #endif
566
567   g_type_ensure (G_TYPE_UNIX_CREDENTIALS_MESSAGE);
568   num_bytes_read = g_socket_receive_message (socket,
569                                              NULL, /* GSocketAddress **address */
570                                              NULL,
571                                              0,
572                                              &scms,
573                                              &nscm,
574                                              NULL,
575                                              cancellable,
576                                              error);
577   if (num_bytes_read != 1)
578     {
579       /* Handle situation where g_socket_receive_message() returns
580        * 0 bytes and not setting @error
581        */
582       if (num_bytes_read == 0 && error != NULL && *error == NULL)
583         {
584           g_set_error_literal (error,
585                                G_IO_ERROR,
586                                G_IO_ERROR_FAILED,
587                                _("Expecting to read a single byte for receiving credentials but read zero bytes"));
588         }
589       goto out;
590     }
591
592   if (g_unix_credentials_message_is_supported () &&
593       /* Fall back on get_credentials if the other side didn't send the credentials */
594       nscm > 0)
595     {
596       if (nscm != 1)
597         {
598           g_set_error (error,
599                        G_IO_ERROR,
600                        G_IO_ERROR_FAILED,
601                        g_dngettext (NULL,
602                                     "Expecting 1 control message, got %d",
603                                     "Expecting 1 control message, got %d",
604                                     nscm),
605                        nscm);
606           goto out;
607         }
608
609       if (!G_IS_UNIX_CREDENTIALS_MESSAGE (scms[0]))
610         {
611           g_set_error_literal (error,
612                                G_IO_ERROR,
613                                G_IO_ERROR_FAILED,
614                                _("Unexpected type of ancillary data"));
615           goto out;
616         }
617
618       ret = g_unix_credentials_message_get_credentials (G_UNIX_CREDENTIALS_MESSAGE (scms[0]));
619       g_object_ref (ret);
620     }
621   else
622     {
623       if (nscm != 0)
624         {
625           g_set_error (error,
626                        G_IO_ERROR,
627                        G_IO_ERROR_FAILED,
628                        _("Not expecting control message, but got %d"),
629                        nscm);
630           goto out;
631         }
632       else
633         {
634           ret = g_socket_get_credentials (socket, error);
635         }
636     }
637
638  out:
639
640 #ifdef __linux__
641   if (turn_off_so_passcreds)
642     {
643       if (!g_socket_set_option (socket,
644                                 SOL_SOCKET,
645                                 SO_PASSCRED,
646                                 FALSE,
647                                 NULL))
648         {
649           int errsv = errno;
650           g_set_error (error,
651                        G_IO_ERROR,
652                        g_io_error_from_errno (errsv),
653                        _("Error while disabling SO_PASSCRED: %s"),
654                        g_strerror (errsv));
655           goto out;
656         }
657     }
658 #endif
659
660   if (scms != NULL)
661     {
662       for (n = 0; n < nscm; n++)
663         g_object_unref (scms[n]);
664       g_free (scms);
665     }
666   g_object_unref (socket);
667   return ret;
668 }
669
670 static void
671 receive_credentials_async_thread (GTask         *task,
672                                   gpointer       source_object,
673                                   gpointer       task_data,
674                                   GCancellable  *cancellable)
675 {
676   GCredentials *creds;
677   GError *error = NULL;
678
679   creds = g_unix_connection_receive_credentials (G_UNIX_CONNECTION (source_object),
680                                                  cancellable,
681                                                  &error);
682   if (creds)
683     g_task_return_pointer (task, creds, g_object_unref);
684   else
685     g_task_return_error (task, error);
686   g_object_unref (task);
687 }
688
689 /**
690  * g_unix_connection_receive_credentials_async:
691  * @connection: A #GUnixConnection.
692  * @cancellable: (nullable): optional #GCancellable object, %NULL to ignore.
693  * @callback: (scope async): a #GAsyncReadyCallback
694  *   to call when the request is satisfied
695  * @user_data: the data to pass to callback function
696  *
697  * Asynchronously receive credentials.
698  *
699  * For more details, see g_unix_connection_receive_credentials() which is
700  * the synchronous version of this call.
701  *
702  * When the operation is finished, @callback will be called. You can then call
703  * g_unix_connection_receive_credentials_finish() to get the result of the operation.
704  *
705  * Since: 2.32
706  **/
707 void
708 g_unix_connection_receive_credentials_async (GUnixConnection      *connection,
709                                               GCancellable         *cancellable,
710                                               GAsyncReadyCallback   callback,
711                                               gpointer              user_data)
712 {
713   GTask *task;
714
715   task = g_task_new (connection, cancellable, callback, user_data);
716   g_task_set_source_tag (task, g_unix_connection_receive_credentials_async);
717   g_task_run_in_thread (task, receive_credentials_async_thread);
718 }
719
720 /**
721  * g_unix_connection_receive_credentials_finish:
722  * @connection: A #GUnixConnection.
723  * @result: a #GAsyncResult.
724  * @error: a #GError, or %NULL
725  *
726  * Finishes an asynchronous receive credentials operation started with
727  * g_unix_connection_receive_credentials_async().
728  *
729  * Returns: (transfer full): a #GCredentials, or %NULL on error.
730  *     Free the returned object with g_object_unref().
731  *
732  * Since: 2.32
733  **/
734 GCredentials *
735 g_unix_connection_receive_credentials_finish (GUnixConnection *connection,
736                                               GAsyncResult    *result,
737                                               GError         **error)
738 {
739   g_return_val_if_fail (g_task_is_valid (result, connection), NULL);
740
741   return g_task_propagate_pointer (G_TASK (result), error);
742 }