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