Coverage Report

Created: 2025-07-01 07:09

/src/glib/gio/gunixcredentialsmessage.c
Line
Count
Source (jump to first uncovered line)
1
/* GIO - GLib Input, Output and Streaming Library
2
 *
3
 * Copyright (C) 2010 Red Hat, Inc.
4
 * Copyright (C) 2009 Codethink Limited
5
 *
6
 * This library is free software; you can redistribute it and/or
7
 * modify it under the terms of the GNU Lesser General Public
8
 * License as published by the Free Software Foundation; either
9
 * version 2.1 of the License, or (at your option) any later version.
10
 *
11
 * See the included COPYING file for more information.
12
 *
13
 * Authors: David Zeuthen <davidz@redhat.com>
14
 */
15
16
/**
17
 * SECTION:gunixcredentialsmessage
18
 * @title: GUnixCredentialsMessage
19
 * @short_description: A GSocketControlMessage containing credentials
20
 * @include: gio/gunixcredentialsmessage.h
21
 * @see_also: #GUnixConnection, #GSocketControlMessage
22
 *
23
 * This #GSocketControlMessage contains a #GCredentials instance.  It
24
 * may be sent using g_socket_send_message() and received using
25
 * g_socket_receive_message() over UNIX sockets (ie: sockets in the
26
 * %G_SOCKET_FAMILY_UNIX family).
27
 *
28
 * For an easier way to send and receive credentials over
29
 * stream-oriented UNIX sockets, see
30
 * g_unix_connection_send_credentials() and
31
 * g_unix_connection_receive_credentials(). To receive credentials of
32
 * a foreign process connected to a socket, use
33
 * g_socket_get_credentials().
34
 */
35
36
#include "config.h"
37
38
/* ---------------------------------------------------------------------------------------------------- */
39
40
#include <fcntl.h>
41
#include <errno.h>
42
#include <string.h>
43
#include <unistd.h>
44
45
#include "gunixcredentialsmessage.h"
46
#include "gcredentials.h"
47
#include "gcredentialsprivate.h"
48
#include "gnetworking.h"
49
50
#include "glibintl.h"
51
52
struct _GUnixCredentialsMessagePrivate
53
{
54
  GCredentials *credentials;
55
};
56
57
enum
58
{
59
  PROP_0,
60
  PROP_CREDENTIALS
61
};
62
63
G_DEFINE_TYPE_WITH_PRIVATE (GUnixCredentialsMessage, g_unix_credentials_message, G_TYPE_SOCKET_CONTROL_MESSAGE)
64
65
static gsize
66
g_unix_credentials_message_get_size (GSocketControlMessage *message)
67
0
{
68
0
#if G_CREDENTIALS_UNIX_CREDENTIALS_MESSAGE_SUPPORTED
69
0
  return G_CREDENTIALS_NATIVE_SIZE;
70
#else
71
  return 0;
72
#endif
73
0
}
74
75
static int
76
g_unix_credentials_message_get_level (GSocketControlMessage *message)
77
0
{
78
0
#if G_CREDENTIALS_UNIX_CREDENTIALS_MESSAGE_SUPPORTED
79
0
  return SOL_SOCKET;
80
#else
81
  return 0;
82
#endif
83
0
}
84
85
static int
86
g_unix_credentials_message_get_msg_type (GSocketControlMessage *message)
87
0
{
88
0
#if G_CREDENTIALS_USE_LINUX_UCRED
89
0
  return SCM_CREDENTIALS;
90
#elif G_CREDENTIALS_USE_FREEBSD_CMSGCRED
91
  return SCM_CREDS;
92
#elif G_CREDENTIALS_USE_NETBSD_UNPCBID
93
  return SCM_CREDS;
94
#elif G_CREDENTIALS_USE_SOLARIS_UCRED
95
  return SCM_UCRED;
96
#elif G_CREDENTIALS_UNIX_CREDENTIALS_MESSAGE_SUPPORTED
97
  #error "G_CREDENTIALS_UNIX_CREDENTIALS_MESSAGE_SUPPORTED is set but there is no msg_type defined for this platform"
98
#else
99
  /* includes G_CREDENTIALS_USE_APPLE_XUCRED */
100
  return 0;
101
#endif
102
0
}
103
104
static GSocketControlMessage *
105
g_unix_credentials_message_deserialize (gint     level,
106
                                        gint     type,
107
                                        gsize    size,
108
                                        gpointer data)
109
0
{
110
0
#if G_CREDENTIALS_UNIX_CREDENTIALS_MESSAGE_SUPPORTED
111
0
  GSocketControlMessage *message;
112
0
  GCredentials *credentials;
113
114
0
  if (level != SOL_SOCKET || type != g_unix_credentials_message_get_msg_type (NULL))
115
0
    return NULL;
116
117
0
  if (size != G_CREDENTIALS_NATIVE_SIZE)
118
0
    {
119
0
      g_warning ("Expected a credentials struct of %" G_GSIZE_FORMAT " bytes but "
120
0
                 "got %" G_GSIZE_FORMAT " bytes of data",
121
0
                 G_CREDENTIALS_NATIVE_SIZE, size);
122
0
      return NULL;
123
0
    }
124
125
0
  credentials = g_credentials_new ();
126
0
  g_credentials_set_native (credentials, G_CREDENTIALS_NATIVE_TYPE, data);
127
128
0
  if (g_credentials_get_unix_user (credentials, NULL) == (uid_t) -1)
129
0
    {
130
      /* This happens on Linux if the remote side didn't pass the credentials */
131
0
      g_object_unref (credentials);
132
0
      return NULL;
133
0
    }
134
135
0
  message = g_unix_credentials_message_new_with_credentials (credentials);
136
0
  g_object_unref (credentials);
137
138
0
  return message;
139
140
#else /* !G_CREDENTIALS_UNIX_CREDENTIALS_MESSAGE_SUPPORTED */
141
142
  return NULL;
143
#endif
144
0
}
145
146
static void
147
g_unix_credentials_message_serialize (GSocketControlMessage *_message,
148
                                      gpointer               data)
149
0
{
150
0
#if G_CREDENTIALS_UNIX_CREDENTIALS_MESSAGE_SUPPORTED
151
0
  GUnixCredentialsMessage *message = G_UNIX_CREDENTIALS_MESSAGE (_message);
152
153
0
  memcpy (data,
154
0
          g_credentials_get_native (message->priv->credentials,
155
0
                                    G_CREDENTIALS_NATIVE_TYPE),
156
0
          G_CREDENTIALS_NATIVE_SIZE);
157
0
#endif
158
0
}
159
160
static void
161
g_unix_credentials_message_finalize (GObject *object)
162
0
{
163
0
  GUnixCredentialsMessage *message = G_UNIX_CREDENTIALS_MESSAGE (object);
164
165
0
  if (message->priv->credentials != NULL)
166
0
    g_object_unref (message->priv->credentials);
167
168
0
  G_OBJECT_CLASS (g_unix_credentials_message_parent_class)->finalize (object);
169
0
}
170
171
static void
172
g_unix_credentials_message_init (GUnixCredentialsMessage *message)
173
0
{
174
0
  message->priv = g_unix_credentials_message_get_instance_private (message);
175
0
}
176
177
static void
178
g_unix_credentials_message_get_property (GObject    *object,
179
                                         guint       prop_id,
180
                                         GValue     *value,
181
                                         GParamSpec *pspec)
182
0
{
183
0
  GUnixCredentialsMessage *message = G_UNIX_CREDENTIALS_MESSAGE (object);
184
185
0
  switch (prop_id)
186
0
    {
187
0
    case PROP_CREDENTIALS:
188
0
      g_value_set_object (value, message->priv->credentials);
189
0
      break;
190
191
0
    default:
192
0
      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
193
0
      break;
194
0
    }
195
0
}
196
197
static void
198
g_unix_credentials_message_set_property (GObject      *object,
199
                                         guint         prop_id,
200
                                         const GValue *value,
201
                                         GParamSpec   *pspec)
202
0
{
203
0
  GUnixCredentialsMessage *message = G_UNIX_CREDENTIALS_MESSAGE (object);
204
205
0
  switch (prop_id)
206
0
    {
207
0
    case PROP_CREDENTIALS:
208
0
      message->priv->credentials = g_value_dup_object (value);
209
0
      break;
210
211
0
    default:
212
0
      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
213
0
      break;
214
0
    }
215
0
}
216
217
static void
218
g_unix_credentials_message_constructed (GObject *object)
219
0
{
220
0
  GUnixCredentialsMessage *message = G_UNIX_CREDENTIALS_MESSAGE (object);
221
222
0
  if (message->priv->credentials == NULL)
223
0
    message->priv->credentials = g_credentials_new ();
224
225
0
  if (G_OBJECT_CLASS (g_unix_credentials_message_parent_class)->constructed != NULL)
226
0
    G_OBJECT_CLASS (g_unix_credentials_message_parent_class)->constructed (object);
227
0
}
228
229
static void
230
g_unix_credentials_message_class_init (GUnixCredentialsMessageClass *class)
231
0
{
232
0
  GSocketControlMessageClass *scm_class;
233
0
  GObjectClass *gobject_class;
234
235
0
  gobject_class = G_OBJECT_CLASS (class);
236
0
  gobject_class->get_property = g_unix_credentials_message_get_property;
237
0
  gobject_class->set_property = g_unix_credentials_message_set_property;
238
0
  gobject_class->finalize = g_unix_credentials_message_finalize;
239
0
  gobject_class->constructed = g_unix_credentials_message_constructed;
240
241
0
  scm_class = G_SOCKET_CONTROL_MESSAGE_CLASS (class);
242
0
  scm_class->get_size = g_unix_credentials_message_get_size;
243
0
  scm_class->get_level = g_unix_credentials_message_get_level;
244
0
  scm_class->get_type = g_unix_credentials_message_get_msg_type;
245
0
  scm_class->serialize = g_unix_credentials_message_serialize;
246
0
  scm_class->deserialize = g_unix_credentials_message_deserialize;
247
248
  /**
249
   * GUnixCredentialsMessage:credentials:
250
   *
251
   * The credentials stored in the message.
252
   *
253
   * Since: 2.26
254
   */
255
0
  g_object_class_install_property (gobject_class,
256
0
                                   PROP_CREDENTIALS,
257
0
                                   g_param_spec_object ("credentials",
258
0
                                                        P_("Credentials"),
259
0
                                                        P_("The credentials stored in the message"),
260
0
                                                        G_TYPE_CREDENTIALS,
261
0
                                                        G_PARAM_READABLE |
262
0
                                                        G_PARAM_WRITABLE |
263
0
                                                        G_PARAM_CONSTRUCT_ONLY |
264
0
                                                        G_PARAM_STATIC_NAME |
265
0
                                                        G_PARAM_STATIC_BLURB |
266
0
                                                        G_PARAM_STATIC_NICK));
267
268
0
}
269
270
/* ---------------------------------------------------------------------------------------------------- */
271
272
/**
273
 * g_unix_credentials_message_is_supported:
274
 *
275
 * Checks if passing #GCredentials on a #GSocket is supported on this platform.
276
 *
277
 * Returns: %TRUE if supported, %FALSE otherwise
278
 *
279
 * Since: 2.26
280
 */
281
gboolean
282
g_unix_credentials_message_is_supported (void)
283
0
{
284
0
#if G_CREDENTIALS_UNIX_CREDENTIALS_MESSAGE_SUPPORTED
285
0
  return TRUE;
286
#else
287
  return FALSE;
288
#endif
289
0
}
290
291
/* ---------------------------------------------------------------------------------------------------- */
292
293
/**
294
 * g_unix_credentials_message_new:
295
 *
296
 * Creates a new #GUnixCredentialsMessage with credentials matching the current processes.
297
 *
298
 * Returns: a new #GUnixCredentialsMessage
299
 *
300
 * Since: 2.26
301
 */
302
GSocketControlMessage *
303
g_unix_credentials_message_new (void)
304
0
{
305
0
  g_return_val_if_fail (g_unix_credentials_message_is_supported (), NULL);
306
0
  return g_object_new (G_TYPE_UNIX_CREDENTIALS_MESSAGE,
307
0
                       NULL);
308
0
}
309
310
/**
311
 * g_unix_credentials_message_new_with_credentials:
312
 * @credentials: A #GCredentials object.
313
 *
314
 * Creates a new #GUnixCredentialsMessage holding @credentials.
315
 *
316
 * Returns: a new #GUnixCredentialsMessage
317
 *
318
 * Since: 2.26
319
 */
320
GSocketControlMessage *
321
g_unix_credentials_message_new_with_credentials (GCredentials *credentials)
322
0
{
323
0
  g_return_val_if_fail (G_IS_CREDENTIALS (credentials), NULL);
324
0
  g_return_val_if_fail (g_unix_credentials_message_is_supported (), NULL);
325
0
  return g_object_new (G_TYPE_UNIX_CREDENTIALS_MESSAGE,
326
0
                       "credentials", credentials,
327
0
                       NULL);
328
0
}
329
330
/**
331
 * g_unix_credentials_message_get_credentials:
332
 * @message: A #GUnixCredentialsMessage.
333
 *
334
 * Gets the credentials stored in @message.
335
 *
336
 * Returns: (transfer none): A #GCredentials instance. Do not free, it is owned by @message.
337
 *
338
 * Since: 2.26
339
 */
340
GCredentials *
341
g_unix_credentials_message_get_credentials (GUnixCredentialsMessage *message)
342
0
{
343
0
  g_return_val_if_fail (G_IS_UNIX_CREDENTIALS_MESSAGE (message), NULL);
344
0
  return message->priv->credentials;
345
0
}