Coverage Report

Created: 2025-07-23 08:13

/src/pango/subprojects/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
 * 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
0
{
85
0
#ifdef G_OS_UNIX
86
0
  GSocketControlMessage *scm;
87
0
  GSocket *socket;
88
89
0
  g_return_val_if_fail (G_IS_UNIX_CONNECTION (connection), FALSE);
90
0
  g_return_val_if_fail (fd >= 0, FALSE);
91
92
0
  scm = g_unix_fd_message_new ();
93
94
0
  if (!g_unix_fd_message_append_fd (G_UNIX_FD_MESSAGE (scm), fd, error))
95
0
    {
96
0
      g_object_unref (scm);
97
0
      return FALSE;
98
0
    }
99
100
0
  g_object_get (connection, "socket", &socket, NULL);
101
0
  if (g_socket_send_message (socket, NULL, NULL, 0, &scm, 1, 0, cancellable, error) != 1)
102
    /* XXX could it 'fail' with zero? */
103
0
    {
104
0
      g_object_unref (socket);
105
0
      g_object_unref (scm);
106
107
0
      return FALSE;
108
0
    }
109
110
0
  g_object_unref (socket);
111
0
  g_object_unref (scm);
112
113
0
  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
0
}
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
0
{
144
0
#ifdef G_OS_UNIX
145
0
  GSocketControlMessage **scms;
146
0
  gint *fds, nfd, fd, nscm;
147
0
  GUnixFDMessage *fdmsg;
148
0
  GSocket *socket;
149
150
0
  g_return_val_if_fail (G_IS_UNIX_CONNECTION (connection), -1);
151
152
0
  g_object_get (connection, "socket", &socket, NULL);
153
0
  if (g_socket_receive_message (socket, NULL, NULL, 0,
154
0
                                &scms, &nscm, NULL, cancellable, error) != 1)
155
    /* XXX it _could_ 'fail' with zero. */
156
0
    {
157
0
      g_object_unref (socket);
158
159
0
      return -1;
160
0
    }
161
162
0
  g_object_unref (socket);
163
164
0
  if (nscm != 1)
165
0
    {
166
0
      gint i;
167
168
0
      g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED,
169
0
                   g_dngettext (NULL,
170
0
                                "Expecting 1 control message, got %d",
171
0
                                "Expecting 1 control message, got %d",
172
0
                                nscm),
173
0
                   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
0
    }
182
183
0
  if (!G_IS_UNIX_FD_MESSAGE (scms[0]))
184
0
    {
185
0
      g_set_error_literal (error, G_IO_ERROR, G_IO_ERROR_FAILED,
186
0
         _("Unexpected type of ancillary data"));
187
0
      g_object_unref (scms[0]);
188
0
      g_free (scms);
189
190
0
      return -1;
191
0
    }
192
193
0
  fdmsg = G_UNIX_FD_MESSAGE (scms[0]);
194
0
  g_free (scms);
195
196
0
  fds = g_unix_fd_message_steal_fds (fdmsg, &nfd);
197
0
  g_object_unref (fdmsg);
198
199
0
  if (nfd != 1)
200
0
    {
201
0
      gint i;
202
203
0
      g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED,
204
0
                   g_dngettext (NULL,
205
0
                                "Expecting one fd, but got %d\n",
206
0
                                "Expecting one fd, but got %d\n",
207
0
                                nfd),
208
0
                   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
0
    }
217
218
0
  fd = *fds;
219
0
  g_free (fds);
220
221
0
  if (fd < 0)
222
0
    {
223
0
      g_set_error_literal (error, G_IO_ERROR, G_IO_ERROR_FAILED,
224
0
                           _("Received invalid fd"));
225
0
      fd = -1;
226
0
    }
227
228
0
  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
0
}
235
236
static void
237
g_unix_connection_init (GUnixConnection *connection)
238
0
{
239
0
}
240
241
static void
242
g_unix_connection_class_init (GUnixConnectionClass *class)
243
0
{
244
0
}
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
0
{
333
0
  GCredentials *credentials;
334
0
  GSocketControlMessage *scm;
335
0
  GSocket *socket;
336
0
  gboolean ret;
337
0
  GOutputVector vector;
338
0
  guchar nul_byte[1] = {'\0'};
339
0
  gint num_messages;
340
341
0
  g_return_val_if_fail (G_IS_UNIX_CONNECTION (connection), FALSE);
342
0
  g_return_val_if_fail (error == NULL || *error == NULL, FALSE);
343
344
0
  ret = FALSE;
345
346
0
  credentials = g_credentials_new ();
347
348
0
  vector.buffer = &nul_byte;
349
0
  vector.size = 1;
350
351
0
  if (g_unix_credentials_message_is_supported ())
352
0
    {
353
0
      scm = g_unix_credentials_message_new_with_credentials (credentials);
354
0
      num_messages = 1;
355
0
    }
356
0
  else
357
0
    {
358
0
      scm = NULL;
359
0
      num_messages = 0;
360
0
    }
361
362
0
  g_object_get (connection, "socket", &socket, NULL);
363
0
  if (g_socket_send_message (socket,
364
0
                             NULL, /* address */
365
0
                             &vector,
366
0
                             1,
367
0
                             &scm,
368
0
                             num_messages,
369
0
                             G_SOCKET_MSG_NONE,
370
0
                             cancellable,
371
0
                             error) != 1)
372
0
    {
373
0
      g_prefix_error (error, _("Error sending credentials: "));
374
0
      goto out;
375
0
    }
376
377
0
  ret = TRUE;
378
379
0
 out:
380
0
  g_object_unref (socket);
381
0
  if (scm != NULL)
382
0
    g_object_unref (scm);
383
0
  g_object_unref (credentials);
384
0
  return ret;
385
0
}
386
387
static void
388
send_credentials_async_thread (GTask         *task,
389
             gpointer       source_object,
390
             gpointer       task_data,
391
             GCancellable  *cancellable)
392
0
{
393
0
  GError *error = NULL;
394
395
0
  if (g_unix_connection_send_credentials (G_UNIX_CONNECTION (source_object),
396
0
            cancellable,
397
0
            &error))
398
0
    g_task_return_boolean (task, TRUE);
399
0
  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
g_unix_connection_send_credentials_async (GUnixConnection      *connection,
424
                                          GCancellable         *cancellable,
425
                                          GAsyncReadyCallback   callback,
426
                                          gpointer              user_data)
427
0
{
428
0
  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
g_unix_connection_send_credentials_finish (GUnixConnection *connection,
450
                                           GAsyncResult    *result,
451
                                           GError         **error)
452
0
{
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
0
}
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
0
{
493
0
  GCredentials *ret;
494
0
  GSocketControlMessage **scms;
495
0
  gint nscm;
496
0
  GSocket *socket;
497
0
  gint n;
498
0
  gssize num_bytes_read;
499
0
#ifdef __linux__
500
0
  gboolean turn_off_so_passcreds;
501
0
#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
0
#ifdef __linux__
516
0
  {
517
0
    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
0
            SOL_SOCKET,
523
0
            SO_PASSCRED,
524
0
            &opt_val,
525
0
            NULL))
526
0
      {
527
0
        int errsv = errno;
528
0
        g_set_error (error,
529
0
                     G_IO_ERROR,
530
0
                     g_io_error_from_errno (errsv),
531
0
                     _("Error checking if SO_PASSCRED is enabled for socket: %s"),
532
0
                     g_strerror (errsv));
533
0
        goto out;
534
0
      }
535
0
    if (opt_val == 0)
536
0
      {
537
0
        if (!g_socket_set_option (socket,
538
0
          SOL_SOCKET,
539
0
          SO_PASSCRED,
540
0
          TRUE,
541
0
          NULL))
542
0
          {
543
0
            int errsv = errno;
544
0
            g_set_error (error,
545
0
                         G_IO_ERROR,
546
0
                         g_io_error_from_errno (errsv),
547
0
                         _("Error enabling SO_PASSCRED: %s"),
548
0
                         g_strerror (errsv));
549
0
            goto out;
550
0
          }
551
0
        turn_off_so_passcreds = TRUE;
552
0
      }
553
0
  }
554
0
#endif
555
556
0
  g_type_ensure (G_TYPE_UNIX_CREDENTIALS_MESSAGE);
557
0
  num_bytes_read = g_socket_receive_message (socket,
558
0
                                             NULL, /* GSocketAddress **address */
559
0
                                             NULL,
560
0
                                             0,
561
0
                                             &scms,
562
0
                                             &nscm,
563
0
                                             NULL,
564
0
                                             cancellable,
565
0
                                             error);
566
0
  if (num_bytes_read != 1)
567
0
    {
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
0
        {
573
0
          g_set_error_literal (error,
574
0
                               G_IO_ERROR,
575
0
                               G_IO_ERROR_FAILED,
576
0
                               _("Expecting to read a single byte for receiving credentials but read zero bytes"));
577
0
        }
578
0
      goto out;
579
0
    }
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
0
    {
585
0
      if (nscm != 1)
586
0
        {
587
0
          g_set_error (error,
588
0
                       G_IO_ERROR,
589
0
                       G_IO_ERROR_FAILED,
590
0
                       g_dngettext (NULL,
591
0
                                    "Expecting 1 control message, got %d",
592
0
                                    "Expecting 1 control message, got %d",
593
0
                                    nscm),
594
0
                       nscm);
595
0
          goto out;
596
0
        }
597
598
0
      if (!G_IS_UNIX_CREDENTIALS_MESSAGE (scms[0]))
599
0
        {
600
0
          g_set_error_literal (error,
601
0
                               G_IO_ERROR,
602
0
                               G_IO_ERROR_FAILED,
603
0
                               _("Unexpected type of ancillary data"));
604
0
          goto out;
605
0
        }
606
607
0
      ret = g_unix_credentials_message_get_credentials (G_UNIX_CREDENTIALS_MESSAGE (scms[0]));
608
0
      g_object_ref (ret);
609
0
    }
610
0
  else
611
0
    {
612
0
      if (nscm != 0)
613
0
        {
614
0
          g_set_error (error,
615
0
                       G_IO_ERROR,
616
0
                       G_IO_ERROR_FAILED,
617
0
                       _("Not expecting control message, but got %d"),
618
0
                       nscm);
619
0
          goto out;
620
0
        }
621
0
      else
622
0
        {
623
0
          ret = g_socket_get_credentials (socket, error);
624
0
        }
625
0
    }
626
627
0
 out:
628
629
0
#ifdef __linux__
630
0
  if (turn_off_so_passcreds)
631
0
    {
632
0
      if (!g_socket_set_option (socket,
633
0
        SOL_SOCKET,
634
0
        SO_PASSCRED,
635
0
        FALSE,
636
0
        NULL))
637
0
        {
638
0
          int errsv = errno;
639
0
          g_set_error (error,
640
0
                       G_IO_ERROR,
641
0
                       g_io_error_from_errno (errsv),
642
0
                       _("Error while disabling SO_PASSCRED: %s"),
643
0
                       g_strerror (errsv));
644
0
          goto out;
645
0
        }
646
0
    }
647
0
#endif
648
649
0
  if (scms != NULL)
650
0
    {
651
0
      for (n = 0; n < nscm; n++)
652
0
        g_object_unref (scms[n]);
653
0
      g_free (scms);
654
0
    }
655
0
  g_object_unref (socket);
656
0
  return ret;
657
0
}
658
659
static void
660
receive_credentials_async_thread (GTask         *task,
661
          gpointer       source_object,
662
          gpointer       task_data,
663
          GCancellable  *cancellable)
664
0
{
665
0
  GCredentials *creds;
666
0
  GError *error = NULL;
667
668
0
  creds = g_unix_connection_receive_credentials (G_UNIX_CONNECTION (source_object),
669
0
                                                 cancellable,
670
0
                                                 &error);
671
0
  if (creds)
672
0
    g_task_return_pointer (task, creds, g_object_unref);
673
0
  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
g_unix_connection_receive_credentials_async (GUnixConnection      *connection,
698
                                              GCancellable         *cancellable,
699
                                              GAsyncReadyCallback   callback,
700
                                              gpointer              user_data)
701
0
{
702
0
  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
g_unix_connection_receive_credentials_finish (GUnixConnection *connection,
725
                                              GAsyncResult    *result,
726
                                              GError         **error)
727
0
{
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
0
}