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