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
56G_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 */
83gboolean
84g_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 (object: scm);
100 return FALSE;
101 }
102
103 g_object_get (object: connection, first_property_name: "socket", &socket, NULL);
104 if (g_socket_send_message (socket, NULL, NULL, num_vectors: 0, messages: &scm, num_messages: 1, flags: 0, cancellable, error) != 1)
105 /* XXX could it 'fail' with zero? */
106 {
107 g_object_unref (object: socket);
108 g_object_unref (object: scm);
109
110 return FALSE;
111 }
112
113 g_object_unref (object: socket);
114 g_object_unref (object: 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 **/
137gint
138g_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 (object: connection, first_property_name: "socket", &socket, NULL);
150 if (g_socket_receive_message (socket, NULL, NULL, num_vectors: 0,
151 messages: &scms, num_messages: &nscm, NULL, cancellable, error) != 1)
152 /* XXX it _could_ 'fail' with zero. */
153 {
154 g_object_unref (object: socket);
155
156 return -1;
157 }
158
159 g_object_unref (object: socket);
160
161 if (nscm != 1)
162 {
163 gint i;
164
165 g_set_error (err: error, G_IO_ERROR, code: 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 (object: scms[i]);
173
174 g_free (mem: scms);
175
176 return -1;
177 }
178
179 if (!G_IS_UNIX_FD_MESSAGE (scms[0]))
180 {
181 g_set_error_literal (err: error, G_IO_ERROR, code: G_IO_ERROR_FAILED,
182 _("Unexpected type of ancillary data"));
183 g_object_unref (object: scms[0]);
184 g_free (mem: scms);
185
186 return -1;
187 }
188
189 fdmsg = G_UNIX_FD_MESSAGE (scms[0]);
190 g_free (mem: scms);
191
192 fds = g_unix_fd_message_steal_fds (message: fdmsg, length: &nfd);
193 g_object_unref (object: fdmsg);
194
195 if (nfd != 1)
196 {
197 gint i;
198
199 g_set_error (err: error, G_IO_ERROR, code: 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 (fd: fds[i]);
207
208 g_free (mem: fds);
209
210 return -1;
211 }
212
213 fd = *fds;
214 g_free (mem: fds);
215
216 if (fd < 0)
217 {
218 g_set_error_literal (err: error, G_IO_ERROR, code: G_IO_ERROR_FAILED,
219 _("Received invalid fd"));
220 fd = -1;
221 }
222
223 return fd;
224}
225
226static void
227g_unix_connection_init (GUnixConnection *connection)
228{
229}
230
231static void
232g_unix_connection_class_init (GUnixConnectionClass *class)
233{
234}
235
236/* TODO: Other stuff we might want to add are:
237void 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);
243gboolean g_unix_connection_send_fd_finish (GUnixConnection *connection,
244 GError **error);
245
246gboolean g_unix_connection_send_fds (GUnixConnection *connection,
247 gint *fds,
248 gint nfds,
249 GError **error);
250void 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);
256gboolean g_unix_connection_send_fds_finish (GUnixConnection *connection,
257 GError **error);
258
259void g_unix_connection_receive_fd_async (GUnixConnection *connection,
260 gint io_priority,
261 GAsyncReadyCallback callback,
262 gpointer user_data);
263gint g_unix_connection_receive_fd_finish (GUnixConnection *connection,
264 GError **error);
265
266
267gboolean g_unix_connection_send_fake_credentials (GUnixConnection *connection,
268 guint64 pid,
269 guint64 uid,
270 guint64 gid,
271 GError **error);
272void 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);
279gboolean g_unix_connection_send_fake_credentials_finish (GUnixConnection *connection,
280 GError **error);
281
282gboolean 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 */
318gboolean
319g_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 (object: connection, first_property_name: "socket", &socket, NULL);
353 if (g_socket_send_message (socket,
354 NULL, /* address */
355 vectors: &vector,
356 num_vectors: 1,
357 messages: &scm,
358 num_messages,
359 flags: G_SOCKET_MSG_NONE,
360 cancellable,
361 error) != 1)
362 {
363 g_prefix_error (err: error, _("Error sending credentials: "));
364 goto out;
365 }
366
367 ret = TRUE;
368
369 out:
370 g_object_unref (object: socket);
371 if (scm != NULL)
372 g_object_unref (object: scm);
373 g_object_unref (object: credentials);
374 return ret;
375}
376
377static void
378send_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: &error))
388 g_task_return_boolean (task, TRUE);
389 else
390 g_task_return_error (task, error);
391 g_object_unref (object: 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 **/
411void
412g_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 (source_object: connection, cancellable, callback, callback_data: user_data);
420 g_task_set_source_tag (task, g_unix_connection_send_credentials_async);
421 g_task_run_in_thread (task, task_func: 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 **/
437gboolean
438g_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 */
477GCredentials *
478g_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 (object: connection, first_property_name: "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 value: &opt_val,
514 NULL))
515 {
516 int errsv = errno;
517 g_set_error (err: error,
518 G_IO_ERROR,
519 code: g_io_error_from_errno (err_no: errsv),
520 _("Error checking if SO_PASSCRED is enabled for socket: %s"),
521 g_strerror (errnum: 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 (err: error,
534 G_IO_ERROR,
535 code: g_io_error_from_errno (err_no: errsv),
536 _("Error enabling SO_PASSCRED: %s"),
537 g_strerror (errnum: 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 num_vectors: 0,
550 messages: &scms,
551 num_messages: &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 (err: error,
563 G_IO_ERROR,
564 code: 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 (err: error,
577 G_IO_ERROR,
578 code: 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 (err: error,
589 G_IO_ERROR,
590 code: 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 (err: error,
603 G_IO_ERROR,
604 code: 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 (err: error,
628 G_IO_ERROR,
629 code: g_io_error_from_errno (err_no: errsv),
630 _("Error while disabling SO_PASSCRED: %s"),
631 g_strerror (errnum: 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 (object: scms[n]);
641 g_free (mem: scms);
642 }
643 g_object_unref (object: socket);
644 return ret;
645}
646
647static void
648receive_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: &error);
659 if (creds)
660 g_task_return_pointer (task, result: creds, result_destroy: g_object_unref);
661 else
662 g_task_return_error (task, error);
663 g_object_unref (object: 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 **/
683void
684g_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 (source_object: connection, cancellable, callback, callback_data: user_data);
692 g_task_set_source_tag (task, g_unix_connection_receive_credentials_async);
693 g_task_run_in_thread (task, task_func: 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 **/
710GCredentials *
711g_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

source code of gtk/subprojects/glib/gio/gunixconnection.c