Branch data Line data Source code
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 : 9591 : 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 : 1 : 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 : 1 : g_return_val_if_fail (G_IS_UNIX_CONNECTION (connection), FALSE);
90 : 1 : g_return_val_if_fail (fd >= 0, FALSE);
91 : :
92 : 1 : scm = g_unix_fd_message_new ();
93 : :
94 : 1 : if (!g_unix_fd_message_append_fd (G_UNIX_FD_MESSAGE (scm), fd, error))
95 : : {
96 : 0 : g_object_unref (scm);
97 : 0 : return FALSE;
98 : : }
99 : :
100 : 1 : g_object_get (connection, "socket", &socket, NULL);
101 : 1 : if (g_socket_send_message (socket, NULL, NULL, 0, &scm, 1, 0, cancellable, error) != 1)
102 : : /* XXX could it 'fail' with zero? */
103 : : {
104 : 0 : g_object_unref (socket);
105 : 0 : g_object_unref (scm);
106 : :
107 : 0 : return FALSE;
108 : : }
109 : :
110 : 1 : g_object_unref (socket);
111 : 1 : g_object_unref (scm);
112 : :
113 : 1 : 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 : 1 : 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 : 1 : g_return_val_if_fail (G_IS_UNIX_CONNECTION (connection), -1);
151 : :
152 : 1 : g_object_get (connection, "socket", &socket, NULL);
153 : 1 : 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 : 0 : g_object_unref (socket);
158 : :
159 : 0 : return -1;
160 : : }
161 : :
162 : 1 : g_object_unref (socket);
163 : :
164 : 1 : if (nscm != 1)
165 : : {
166 : : gint i;
167 : :
168 : 0 : 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 : 0 : for (i = 0; i < nscm; i++)
176 : 0 : g_object_unref (scms[i]);
177 : :
178 : 0 : g_free (scms);
179 : :
180 : 0 : return -1;
181 : : }
182 : :
183 : 1 : if (!G_IS_UNIX_FD_MESSAGE (scms[0]))
184 : : {
185 : 0 : g_set_error_literal (error, G_IO_ERROR, G_IO_ERROR_FAILED,
186 : : _("Unexpected type of ancillary data"));
187 : 0 : g_object_unref (scms[0]);
188 : 0 : g_free (scms);
189 : :
190 : 0 : return -1;
191 : : }
192 : :
193 : 1 : fdmsg = G_UNIX_FD_MESSAGE (scms[0]);
194 : 1 : g_free (scms);
195 : :
196 : 1 : fds = g_unix_fd_message_steal_fds (fdmsg, &nfd);
197 : 1 : g_object_unref (fdmsg);
198 : :
199 : 1 : if (nfd != 1)
200 : : {
201 : : gint i;
202 : :
203 : 0 : 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 : 0 : for (i = 0; i < nfd; i++)
211 : 0 : close (fds[i]);
212 : :
213 : 0 : g_free (fds);
214 : :
215 : 0 : return -1;
216 : : }
217 : :
218 : 1 : fd = *fds;
219 : 1 : g_free (fds);
220 : :
221 : 1 : if (fd < 0)
222 : : {
223 : 0 : g_set_error_literal (error, G_IO_ERROR, G_IO_ERROR_FAILED,
224 : : _("Received invalid fd"));
225 : 0 : fd = -1;
226 : : }
227 : :
228 : 1 : 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 : 1783 : g_unix_connection_init (GUnixConnection *connection)
238 : : {
239 : 1783 : }
240 : :
241 : : static void
242 : 119 : g_unix_connection_class_init (GUnixConnectionClass *class)
243 : : {
244 : 119 : }
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 : 1599 : 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 : 1599 : guchar nul_byte[1] = {'\0'};
339 : : gint num_messages;
340 : :
341 : 1599 : g_return_val_if_fail (G_IS_UNIX_CONNECTION (connection), FALSE);
342 : 1599 : g_return_val_if_fail (error == NULL || *error == NULL, FALSE);
343 : :
344 : 1599 : ret = FALSE;
345 : :
346 : 1599 : credentials = g_credentials_new ();
347 : :
348 : 1599 : vector.buffer = &nul_byte;
349 : 1599 : vector.size = 1;
350 : :
351 : 1599 : if (g_unix_credentials_message_is_supported ())
352 : : {
353 : 1599 : scm = g_unix_credentials_message_new_with_credentials (credentials);
354 : 1599 : num_messages = 1;
355 : : }
356 : : else
357 : : {
358 : 0 : scm = NULL;
359 : 0 : num_messages = 0;
360 : : }
361 : :
362 : 1599 : g_object_get (connection, "socket", &socket, NULL);
363 : 1599 : 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 : 1 : g_prefix_error (error, _("Error sending credentials: "));
374 : 1 : goto out;
375 : : }
376 : :
377 : 1598 : ret = TRUE;
378 : :
379 : 1599 : out:
380 : 1599 : g_object_unref (socket);
381 : 1599 : if (scm != NULL)
382 : 1599 : g_object_unref (scm);
383 : 1599 : g_object_unref (credentials);
384 : 1599 : return ret;
385 : : }
386 : :
387 : : static void
388 : 0 : send_credentials_async_thread (GTask *task,
389 : : gpointer source_object,
390 : : gpointer task_data,
391 : : GCancellable *cancellable)
392 : : {
393 : 0 : GError *error = NULL;
394 : :
395 : 0 : if (g_unix_connection_send_credentials (G_UNIX_CONNECTION (source_object),
396 : : cancellable,
397 : : &error))
398 : 0 : g_task_return_boolean (task, TRUE);
399 : : else
400 : 0 : g_task_return_error (task, error);
401 : 0 : g_object_unref (task);
402 : 0 : }
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 : 0 : g_unix_connection_send_credentials_async (GUnixConnection *connection,
424 : : GCancellable *cancellable,
425 : : GAsyncReadyCallback callback,
426 : : gpointer user_data)
427 : : {
428 : : GTask *task;
429 : :
430 : 0 : task = g_task_new (connection, cancellable, callback, user_data);
431 : 0 : g_task_set_source_tag (task, g_unix_connection_send_credentials_async);
432 : 0 : g_task_run_in_thread (task, send_credentials_async_thread);
433 : 0 : }
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 : 0 : g_unix_connection_send_credentials_finish (GUnixConnection *connection,
450 : : GAsyncResult *result,
451 : : GError **error)
452 : : {
453 : 0 : g_return_val_if_fail (g_task_is_valid (result, connection), FALSE);
454 : :
455 : 0 : 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 : 0 : 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 : 0 : g_return_val_if_fail (G_IS_UNIX_CONNECTION (connection), NULL);
504 : 0 : g_return_val_if_fail (error == NULL || *error == NULL, NULL);
505 : :
506 : 0 : ret = NULL;
507 : 0 : scms = NULL;
508 : :
509 : 0 : 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 : 0 : turn_off_so_passcreds = FALSE;
520 : 0 : opt_val = 0;
521 : 0 : if (!g_socket_get_option (socket,
522 : : SOL_SOCKET,
523 : : SO_PASSCRED,
524 : : &opt_val,
525 : : NULL))
526 : : {
527 : 0 : int errsv = errno;
528 : 0 : g_set_error (error,
529 : : G_IO_ERROR,
530 : 0 : g_io_error_from_errno (errsv),
531 : : _("Error checking if SO_PASSCRED is enabled for socket: %s"),
532 : : g_strerror (errsv));
533 : 0 : goto out;
534 : : }
535 : 0 : if (opt_val == 0)
536 : : {
537 : 0 : if (!g_socket_set_option (socket,
538 : : SOL_SOCKET,
539 : : SO_PASSCRED,
540 : : TRUE,
541 : : NULL))
542 : : {
543 : 0 : int errsv = errno;
544 : 0 : g_set_error (error,
545 : : G_IO_ERROR,
546 : 0 : g_io_error_from_errno (errsv),
547 : : _("Error enabling SO_PASSCRED: %s"),
548 : : g_strerror (errsv));
549 : 0 : goto out;
550 : : }
551 : 0 : turn_off_so_passcreds = TRUE;
552 : : }
553 : : }
554 : : #endif
555 : :
556 : 0 : g_type_ensure (G_TYPE_UNIX_CREDENTIALS_MESSAGE);
557 : 0 : 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 : 0 : if (num_bytes_read != 1)
567 : : {
568 : : /* Handle situation where g_socket_receive_message() returns
569 : : * 0 bytes and not setting @error
570 : : */
571 : 0 : if (num_bytes_read == 0 && error != NULL && *error == NULL)
572 : : {
573 : 0 : 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 : 0 : goto out;
579 : : }
580 : :
581 : 0 : if (g_unix_credentials_message_is_supported () &&
582 : : /* Fall back on get_credentials if the other side didn't send the credentials */
583 : 0 : nscm > 0)
584 : : {
585 : 0 : if (nscm != 1)
586 : : {
587 : 0 : 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 : 0 : goto out;
596 : : }
597 : :
598 : 0 : if (!G_IS_UNIX_CREDENTIALS_MESSAGE (scms[0]))
599 : : {
600 : 0 : g_set_error_literal (error,
601 : : G_IO_ERROR,
602 : : G_IO_ERROR_FAILED,
603 : : _("Unexpected type of ancillary data"));
604 : 0 : goto out;
605 : : }
606 : :
607 : 0 : ret = g_unix_credentials_message_get_credentials (G_UNIX_CREDENTIALS_MESSAGE (scms[0]));
608 : 0 : g_object_ref (ret);
609 : : }
610 : : else
611 : : {
612 : 0 : if (nscm != 0)
613 : : {
614 : 0 : g_set_error (error,
615 : : G_IO_ERROR,
616 : : G_IO_ERROR_FAILED,
617 : : _("Not expecting control message, but got %d"),
618 : : nscm);
619 : 0 : goto out;
620 : : }
621 : : else
622 : : {
623 : 0 : ret = g_socket_get_credentials (socket, error);
624 : : }
625 : : }
626 : :
627 : 0 : out:
628 : :
629 : : #ifdef __linux__
630 : 0 : if (turn_off_so_passcreds)
631 : : {
632 : 0 : if (!g_socket_set_option (socket,
633 : : SOL_SOCKET,
634 : : SO_PASSCRED,
635 : : FALSE,
636 : : NULL))
637 : : {
638 : 0 : int errsv = errno;
639 : 0 : g_set_error (error,
640 : : G_IO_ERROR,
641 : 0 : g_io_error_from_errno (errsv),
642 : : _("Error while disabling SO_PASSCRED: %s"),
643 : : g_strerror (errsv));
644 : 0 : goto out;
645 : : }
646 : : }
647 : : #endif
648 : :
649 : 0 : if (scms != NULL)
650 : : {
651 : 0 : for (n = 0; n < nscm; n++)
652 : 0 : g_object_unref (scms[n]);
653 : 0 : g_free (scms);
654 : : }
655 : 0 : g_object_unref (socket);
656 : 0 : return ret;
657 : : }
658 : :
659 : : static void
660 : 0 : receive_credentials_async_thread (GTask *task,
661 : : gpointer source_object,
662 : : gpointer task_data,
663 : : GCancellable *cancellable)
664 : : {
665 : : GCredentials *creds;
666 : 0 : GError *error = NULL;
667 : :
668 : 0 : creds = g_unix_connection_receive_credentials (G_UNIX_CONNECTION (source_object),
669 : : cancellable,
670 : : &error);
671 : 0 : if (creds)
672 : 0 : g_task_return_pointer (task, creds, g_object_unref);
673 : : else
674 : 0 : g_task_return_error (task, error);
675 : 0 : g_object_unref (task);
676 : 0 : }
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 : 0 : g_unix_connection_receive_credentials_async (GUnixConnection *connection,
698 : : GCancellable *cancellable,
699 : : GAsyncReadyCallback callback,
700 : : gpointer user_data)
701 : : {
702 : : GTask *task;
703 : :
704 : 0 : task = g_task_new (connection, cancellable, callback, user_data);
705 : 0 : g_task_set_source_tag (task, g_unix_connection_receive_credentials_async);
706 : 0 : g_task_run_in_thread (task, receive_credentials_async_thread);
707 : 0 : }
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 : 0 : g_unix_connection_receive_credentials_finish (GUnixConnection *connection,
725 : : GAsyncResult *result,
726 : : GError **error)
727 : : {
728 : 0 : g_return_val_if_fail (g_task_is_valid (result, connection), NULL);
729 : :
730 : 0 : return g_task_propagate_pointer (G_TASK (result), error);
731 : : }
|