Coverage Report

Created: 2025-07-01 07:09

/src/glib/gio/gunixconnection.c
Line
Count
Source (jump to first uncovered line)
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
84
g_unix_connection_send_fd (GUnixConnection  *connection,
85
                           gint              fd,
86
                           GCancellable     *cancellable,
87
                           GError          **error)
88
0
{
89
0
  GSocketControlMessage *scm;
90
0
  GSocket *socket;
91
92
0
  g_return_val_if_fail (G_IS_UNIX_CONNECTION (connection), FALSE);
93
0
  g_return_val_if_fail (fd >= 0, FALSE);
94
95
0
  scm = g_unix_fd_message_new ();
96
97
0
  if (!g_unix_fd_message_append_fd (G_UNIX_FD_MESSAGE (scm), fd, error))
98
0
    {
99
0
      g_object_unref (scm);
100
0
      return FALSE;
101
0
    }
102
103
0
  g_object_get (connection, "socket", &socket, NULL);
104
0
  if (g_socket_send_message (socket, NULL, NULL, 0, &scm, 1, 0, cancellable, error) != 1)
105
    /* XXX could it 'fail' with zero? */
106
0
    {
107
0
      g_object_unref (socket);
108
0
      g_object_unref (scm);
109
110
0
      return FALSE;
111
0
    }
112
113
0
  g_object_unref (socket);
114
0
  g_object_unref (scm);
115
116
0
  return TRUE;
117
0
}
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
138
g_unix_connection_receive_fd (GUnixConnection  *connection,
139
                              GCancellable     *cancellable,
140
                              GError          **error)
141
0
{
142
0
  GSocketControlMessage **scms;
143
0
  gint *fds, nfd, fd, nscm;
144
0
  GUnixFDMessage *fdmsg;
145
0
  GSocket *socket;
146
147
0
  g_return_val_if_fail (G_IS_UNIX_CONNECTION (connection), -1);
148
149
0
  g_object_get (connection, "socket", &socket, NULL);
150
0
  if (g_socket_receive_message (socket, NULL, NULL, 0,
151
0
                                &scms, &nscm, NULL, cancellable, error) != 1)
152
    /* XXX it _could_ 'fail' with zero. */
153
0
    {
154
0
      g_object_unref (socket);
155
156
0
      return -1;
157
0
    }
158
159
0
  g_object_unref (socket);
160
161
0
  if (nscm != 1)
162
0
    {
163
0
      gint i;
164
165
0
      g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED,
166
0
        ngettext("Expecting 1 control message, got %d",
167
0
                 "Expecting 1 control message, got %d",
168
0
                 nscm),
169
0
        nscm);
170
171
0
      for (i = 0; i < nscm; i++)
172
0
        g_object_unref (scms[i]);
173
174
0
      g_free (scms);
175
176
0
      return -1;
177
0
    }
178
179
0
  if (!G_IS_UNIX_FD_MESSAGE (scms[0]))
180
0
    {
181
0
      g_set_error_literal (error, G_IO_ERROR, G_IO_ERROR_FAILED,
182
0
         _("Unexpected type of ancillary data"));
183
0
      g_object_unref (scms[0]);
184
0
      g_free (scms);
185
186
0
      return -1;
187
0
    }
188
189
0
  fdmsg = G_UNIX_FD_MESSAGE (scms[0]);
190
0
  g_free (scms);
191
192
0
  fds = g_unix_fd_message_steal_fds (fdmsg, &nfd);
193
0
  g_object_unref (fdmsg);
194
195
0
  if (nfd != 1)
196
0
    {
197
0
      gint i;
198
199
0
      g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED,
200
0
                   ngettext("Expecting one fd, but got %d\n",
201
0
                            "Expecting one fd, but got %d\n",
202
0
                            nfd),
203
0
                   nfd);
204
205
0
      for (i = 0; i < nfd; i++)
206
0
        close (fds[i]);
207
208
0
      g_free (fds);
209
210
0
      return -1;
211
0
    }
212
213
0
  fd = *fds;
214
0
  g_free (fds);
215
216
0
  if (fd < 0)
217
0
    {
218
0
      g_set_error_literal (error, G_IO_ERROR, G_IO_ERROR_FAILED,
219
0
                           _("Received invalid fd"));
220
0
      fd = -1;
221
0
    }
222
223
0
  return fd;
224
0
}
225
226
static void
227
g_unix_connection_init (GUnixConnection *connection)
228
0
{
229
0
}
230
231
static void
232
g_unix_connection_class_init (GUnixConnectionClass *class)
233
0
{
234
0
}
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
319
g_unix_connection_send_credentials (GUnixConnection      *connection,
320
                                    GCancellable         *cancellable,
321
                                    GError              **error)
322
0
{
323
0
  GCredentials *credentials;
324
0
  GSocketControlMessage *scm;
325
0
  GSocket *socket;
326
0
  gboolean ret;
327
0
  GOutputVector vector;
328
0
  guchar nul_byte[1] = {'\0'};
329
0
  gint num_messages;
330
331
0
  g_return_val_if_fail (G_IS_UNIX_CONNECTION (connection), FALSE);
332
0
  g_return_val_if_fail (error == NULL || *error == NULL, FALSE);
333
334
0
  ret = FALSE;
335
336
0
  credentials = g_credentials_new ();
337
338
0
  vector.buffer = &nul_byte;
339
0
  vector.size = 1;
340
341
0
  if (g_unix_credentials_message_is_supported ())
342
0
    {
343
0
      scm = g_unix_credentials_message_new_with_credentials (credentials);
344
0
      num_messages = 1;
345
0
    }
346
0
  else
347
0
    {
348
0
      scm = NULL;
349
0
      num_messages = 0;
350
0
    }
351
352
0
  g_object_get (connection, "socket", &socket, NULL);
353
0
  if (g_socket_send_message (socket,
354
0
                             NULL, /* address */
355
0
                             &vector,
356
0
                             1,
357
0
                             &scm,
358
0
                             num_messages,
359
0
                             G_SOCKET_MSG_NONE,
360
0
                             cancellable,
361
0
                             error) != 1)
362
0
    {
363
0
      g_prefix_error (error, _("Error sending credentials: "));
364
0
      goto out;
365
0
    }
366
367
0
  ret = TRUE;
368
369
0
 out:
370
0
  g_object_unref (socket);
371
0
  if (scm != NULL)
372
0
    g_object_unref (scm);
373
0
  g_object_unref (credentials);
374
0
  return ret;
375
0
}
376
377
static void
378
send_credentials_async_thread (GTask         *task,
379
             gpointer       source_object,
380
             gpointer       task_data,
381
             GCancellable  *cancellable)
382
0
{
383
0
  GError *error = NULL;
384
385
0
  if (g_unix_connection_send_credentials (G_UNIX_CONNECTION (source_object),
386
0
            cancellable,
387
0
            &error))
388
0
    g_task_return_boolean (task, TRUE);
389
0
  else
390
0
    g_task_return_error (task, error);
391
0
  g_object_unref (task);
392
0
}
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
412
g_unix_connection_send_credentials_async (GUnixConnection      *connection,
413
                                          GCancellable         *cancellable,
414
                                          GAsyncReadyCallback   callback,
415
                                          gpointer              user_data)
416
0
{
417
0
  GTask *task;
418
419
0
  task = g_task_new (connection, cancellable, callback, user_data);
420
0
  g_task_set_source_tag (task, g_unix_connection_send_credentials_async);
421
0
  g_task_run_in_thread (task, send_credentials_async_thread);
422
0
}
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
438
g_unix_connection_send_credentials_finish (GUnixConnection *connection,
439
                                           GAsyncResult    *result,
440
                                           GError         **error)
441
0
{
442
0
  g_return_val_if_fail (g_task_is_valid (result, connection), FALSE);
443
444
0
  return g_task_propagate_boolean (G_TASK (result), error);
445
0
}
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 *
478
g_unix_connection_receive_credentials (GUnixConnection      *connection,
479
                                       GCancellable         *cancellable,
480
                                       GError              **error)
481
0
{
482
0
  GCredentials *ret;
483
0
  GSocketControlMessage **scms;
484
0
  gint nscm;
485
0
  GSocket *socket;
486
0
  gint n;
487
0
  gssize num_bytes_read;
488
0
#ifdef __linux__
489
0
  gboolean turn_off_so_passcreds;
490
0
#endif
491
492
0
  g_return_val_if_fail (G_IS_UNIX_CONNECTION (connection), NULL);
493
0
  g_return_val_if_fail (error == NULL || *error == NULL, NULL);
494
495
0
  ret = NULL;
496
0
  scms = NULL;
497
498
0
  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
0
#ifdef __linux__
505
0
  {
506
0
    gint opt_val;
507
508
0
    turn_off_so_passcreds = FALSE;
509
0
    opt_val = 0;
510
0
    if (!g_socket_get_option (socket,
511
0
            SOL_SOCKET,
512
0
            SO_PASSCRED,
513
0
            &opt_val,
514
0
            NULL))
515
0
      {
516
0
        int errsv = errno;
517
0
        g_set_error (error,
518
0
                     G_IO_ERROR,
519
0
                     g_io_error_from_errno (errsv),
520
0
                     _("Error checking if SO_PASSCRED is enabled for socket: %s"),
521
0
                     g_strerror (errsv));
522
0
        goto out;
523
0
      }
524
0
    if (opt_val == 0)
525
0
      {
526
0
        if (!g_socket_set_option (socket,
527
0
          SOL_SOCKET,
528
0
          SO_PASSCRED,
529
0
          TRUE,
530
0
          NULL))
531
0
          {
532
0
            int errsv = errno;
533
0
            g_set_error (error,
534
0
                         G_IO_ERROR,
535
0
                         g_io_error_from_errno (errsv),
536
0
                         _("Error enabling SO_PASSCRED: %s"),
537
0
                         g_strerror (errsv));
538
0
            goto out;
539
0
          }
540
0
        turn_off_so_passcreds = TRUE;
541
0
      }
542
0
  }
543
0
#endif
544
545
0
  g_type_ensure (G_TYPE_UNIX_CREDENTIALS_MESSAGE);
546
0
  num_bytes_read = g_socket_receive_message (socket,
547
0
                                             NULL, /* GSocketAddress **address */
548
0
                                             NULL,
549
0
                                             0,
550
0
                                             &scms,
551
0
                                             &nscm,
552
0
                                             NULL,
553
0
                                             cancellable,
554
0
                                             error);
555
0
  if (num_bytes_read != 1)
556
0
    {
557
      /* Handle situation where g_socket_receive_message() returns
558
       * 0 bytes and not setting @error
559
       */
560
0
      if (num_bytes_read == 0 && error != NULL && *error == NULL)
561
0
        {
562
0
          g_set_error_literal (error,
563
0
                               G_IO_ERROR,
564
0
                               G_IO_ERROR_FAILED,
565
0
                               _("Expecting to read a single byte for receiving credentials but read zero bytes"));
566
0
        }
567
0
      goto out;
568
0
    }
569
570
0
  if (g_unix_credentials_message_is_supported () &&
571
      /* Fall back on get_credentials if the other side didn't send the credentials */
572
0
      nscm > 0)
573
0
    {
574
0
      if (nscm != 1)
575
0
        {
576
0
          g_set_error (error,
577
0
                       G_IO_ERROR,
578
0
                       G_IO_ERROR_FAILED,
579
0
                       ngettext("Expecting 1 control message, got %d",
580
0
                                "Expecting 1 control message, got %d",
581
0
                                nscm),
582
0
                       nscm);
583
0
          goto out;
584
0
        }
585
586
0
      if (!G_IS_UNIX_CREDENTIALS_MESSAGE (scms[0]))
587
0
        {
588
0
          g_set_error_literal (error,
589
0
                               G_IO_ERROR,
590
0
                               G_IO_ERROR_FAILED,
591
0
                               _("Unexpected type of ancillary data"));
592
0
          goto out;
593
0
        }
594
595
0
      ret = g_unix_credentials_message_get_credentials (G_UNIX_CREDENTIALS_MESSAGE (scms[0]));
596
0
      g_object_ref (ret);
597
0
    }
598
0
  else
599
0
    {
600
0
      if (nscm != 0)
601
0
        {
602
0
          g_set_error (error,
603
0
                       G_IO_ERROR,
604
0
                       G_IO_ERROR_FAILED,
605
0
                       _("Not expecting control message, but got %d"),
606
0
                       nscm);
607
0
          goto out;
608
0
        }
609
0
      else
610
0
        {
611
0
          ret = g_socket_get_credentials (socket, error);
612
0
        }
613
0
    }
614
615
0
 out:
616
617
0
#ifdef __linux__
618
0
  if (turn_off_so_passcreds)
619
0
    {
620
0
      if (!g_socket_set_option (socket,
621
0
        SOL_SOCKET,
622
0
        SO_PASSCRED,
623
0
        FALSE,
624
0
        NULL))
625
0
        {
626
0
          int errsv = errno;
627
0
          g_set_error (error,
628
0
                       G_IO_ERROR,
629
0
                       g_io_error_from_errno (errsv),
630
0
                       _("Error while disabling SO_PASSCRED: %s"),
631
0
                       g_strerror (errsv));
632
0
          goto out;
633
0
        }
634
0
    }
635
0
#endif
636
637
0
  if (scms != NULL)
638
0
    {
639
0
      for (n = 0; n < nscm; n++)
640
0
        g_object_unref (scms[n]);
641
0
      g_free (scms);
642
0
    }
643
0
  g_object_unref (socket);
644
0
  return ret;
645
0
}
646
647
static void
648
receive_credentials_async_thread (GTask         *task,
649
          gpointer       source_object,
650
          gpointer       task_data,
651
          GCancellable  *cancellable)
652
0
{
653
0
  GCredentials *creds;
654
0
  GError *error = NULL;
655
656
0
  creds = g_unix_connection_receive_credentials (G_UNIX_CONNECTION (source_object),
657
0
                                                 cancellable,
658
0
                                                 &error);
659
0
  if (creds)
660
0
    g_task_return_pointer (task, creds, g_object_unref);
661
0
  else
662
0
    g_task_return_error (task, error);
663
0
  g_object_unref (task);
664
0
}
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
684
g_unix_connection_receive_credentials_async (GUnixConnection      *connection,
685
                                              GCancellable         *cancellable,
686
                                              GAsyncReadyCallback   callback,
687
                                              gpointer              user_data)
688
0
{
689
0
  GTask *task;
690
691
0
  task = g_task_new (connection, cancellable, callback, user_data);
692
0
  g_task_set_source_tag (task, g_unix_connection_receive_credentials_async);
693
0
  g_task_run_in_thread (task, receive_credentials_async_thread);
694
0
}
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 *
711
g_unix_connection_receive_credentials_finish (GUnixConnection *connection,
712
                                              GAsyncResult    *result,
713
                                              GError         **error)
714
0
{
715
0
  g_return_val_if_fail (g_task_is_valid (result, connection), NULL);
716
717
0
  return g_task_propagate_pointer (G_TASK (result), error);
718
0
}