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