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