Check for overflow when allocating RcBox
[glib.git] / gio / gdbusauthmechanismexternal.c
blob182c57278e90a00428685679b0ce6cbc24787019
1 /* GDBus - GLib D-Bus Library
3 * Copyright (C) 2008-2010 Red Hat, Inc.
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.
10 * This library is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 * Lesser General Public License for more details.
15 * You should have received a copy of the GNU Lesser General
16 * Public License along with this library; if not, see <http://www.gnu.org/licenses/>.
18 * Author: David Zeuthen <davidz@redhat.com>
21 #include "config.h"
23 #include <string.h>
25 #include "gdbusauthmechanismexternal.h"
26 #include "gcredentials.h"
27 #include "gdbuserror.h"
28 #include "gioenumtypes.h"
30 #include "glibintl.h"
32 struct _GDBusAuthMechanismExternalPrivate
34 gboolean is_client;
35 gboolean is_server;
36 GDBusAuthMechanismState state;
39 static gint mechanism_get_priority (void);
40 static const gchar *mechanism_get_name (void);
42 static gboolean mechanism_is_supported (GDBusAuthMechanism *mechanism);
43 static gchar *mechanism_encode_data (GDBusAuthMechanism *mechanism,
44 const gchar *data,
45 gsize data_len,
46 gsize *out_data_len);
47 static gchar *mechanism_decode_data (GDBusAuthMechanism *mechanism,
48 const gchar *data,
49 gsize data_len,
50 gsize *out_data_len);
51 static GDBusAuthMechanismState mechanism_server_get_state (GDBusAuthMechanism *mechanism);
52 static void mechanism_server_initiate (GDBusAuthMechanism *mechanism,
53 const gchar *initial_response,
54 gsize initial_response_len);
55 static void mechanism_server_data_receive (GDBusAuthMechanism *mechanism,
56 const gchar *data,
57 gsize data_len);
58 static gchar *mechanism_server_data_send (GDBusAuthMechanism *mechanism,
59 gsize *out_data_len);
60 static gchar *mechanism_server_get_reject_reason (GDBusAuthMechanism *mechanism);
61 static void mechanism_server_shutdown (GDBusAuthMechanism *mechanism);
62 static GDBusAuthMechanismState mechanism_client_get_state (GDBusAuthMechanism *mechanism);
63 static gchar *mechanism_client_initiate (GDBusAuthMechanism *mechanism,
64 gsize *out_initial_response_len);
65 static void mechanism_client_data_receive (GDBusAuthMechanism *mechanism,
66 const gchar *data,
67 gsize data_len);
68 static gchar *mechanism_client_data_send (GDBusAuthMechanism *mechanism,
69 gsize *out_data_len);
70 static void mechanism_client_shutdown (GDBusAuthMechanism *mechanism);
72 /* ---------------------------------------------------------------------------------------------------- */
74 G_DEFINE_TYPE_WITH_PRIVATE (GDBusAuthMechanismExternal, _g_dbus_auth_mechanism_external, G_TYPE_DBUS_AUTH_MECHANISM)
76 /* ---------------------------------------------------------------------------------------------------- */
78 static void
79 _g_dbus_auth_mechanism_external_finalize (GObject *object)
81 //GDBusAuthMechanismExternal *mechanism = G_DBUS_AUTH_MECHANISM_EXTERNAL (object);
83 if (G_OBJECT_CLASS (_g_dbus_auth_mechanism_external_parent_class)->finalize != NULL)
84 G_OBJECT_CLASS (_g_dbus_auth_mechanism_external_parent_class)->finalize (object);
87 static void
88 _g_dbus_auth_mechanism_external_class_init (GDBusAuthMechanismExternalClass *klass)
90 GObjectClass *gobject_class;
91 GDBusAuthMechanismClass *mechanism_class;
93 gobject_class = G_OBJECT_CLASS (klass);
94 gobject_class->finalize = _g_dbus_auth_mechanism_external_finalize;
96 mechanism_class = G_DBUS_AUTH_MECHANISM_CLASS (klass);
97 mechanism_class->get_name = mechanism_get_name;
98 mechanism_class->get_priority = mechanism_get_priority;
99 mechanism_class->is_supported = mechanism_is_supported;
100 mechanism_class->encode_data = mechanism_encode_data;
101 mechanism_class->decode_data = mechanism_decode_data;
102 mechanism_class->server_get_state = mechanism_server_get_state;
103 mechanism_class->server_initiate = mechanism_server_initiate;
104 mechanism_class->server_data_receive = mechanism_server_data_receive;
105 mechanism_class->server_data_send = mechanism_server_data_send;
106 mechanism_class->server_get_reject_reason = mechanism_server_get_reject_reason;
107 mechanism_class->server_shutdown = mechanism_server_shutdown;
108 mechanism_class->client_get_state = mechanism_client_get_state;
109 mechanism_class->client_initiate = mechanism_client_initiate;
110 mechanism_class->client_data_receive = mechanism_client_data_receive;
111 mechanism_class->client_data_send = mechanism_client_data_send;
112 mechanism_class->client_shutdown = mechanism_client_shutdown;
115 static void
116 _g_dbus_auth_mechanism_external_init (GDBusAuthMechanismExternal *mechanism)
118 mechanism->priv = _g_dbus_auth_mechanism_external_get_instance_private (mechanism);
121 /* ---------------------------------------------------------------------------------------------------- */
123 static gboolean
124 mechanism_is_supported (GDBusAuthMechanism *mechanism)
126 g_return_val_if_fail (G_IS_DBUS_AUTH_MECHANISM_EXTERNAL (mechanism), FALSE);
127 /* This mechanism is only available if credentials has been exchanged */
128 if (_g_dbus_auth_mechanism_get_credentials (mechanism) != NULL)
129 return TRUE;
130 else
131 return FALSE;
134 static gint
135 mechanism_get_priority (void)
137 /* We prefer EXTERNAL to most other mechanism (DBUS_COOKIE_SHA1 and ANONYMOUS) */
138 return 100;
141 static const gchar *
142 mechanism_get_name (void)
144 return "EXTERNAL";
147 static gchar *
148 mechanism_encode_data (GDBusAuthMechanism *mechanism,
149 const gchar *data,
150 gsize data_len,
151 gsize *out_data_len)
153 return NULL;
157 static gchar *
158 mechanism_decode_data (GDBusAuthMechanism *mechanism,
159 const gchar *data,
160 gsize data_len,
161 gsize *out_data_len)
163 return NULL;
166 /* ---------------------------------------------------------------------------------------------------- */
168 static GDBusAuthMechanismState
169 mechanism_server_get_state (GDBusAuthMechanism *mechanism)
171 GDBusAuthMechanismExternal *m = G_DBUS_AUTH_MECHANISM_EXTERNAL (mechanism);
173 g_return_val_if_fail (G_IS_DBUS_AUTH_MECHANISM_EXTERNAL (mechanism), G_DBUS_AUTH_MECHANISM_STATE_INVALID);
174 g_return_val_if_fail (m->priv->is_server && !m->priv->is_client, G_DBUS_AUTH_MECHANISM_STATE_INVALID);
176 return m->priv->state;
179 static gboolean
180 data_matches_credentials (const gchar *data,
181 gsize data_len,
182 GCredentials *credentials)
184 gboolean match;
186 match = FALSE;
188 if (credentials == NULL)
189 goto out;
191 if (data == NULL || data_len == 0)
192 goto out;
194 #if defined(G_OS_UNIX)
196 gint64 alleged_uid;
197 gchar *endp;
199 /* on UNIX, this is the uid as a string in base 10 */
200 alleged_uid = g_ascii_strtoll (data, &endp, 10);
201 if (*endp == '\0')
203 if (g_credentials_get_unix_user (credentials, NULL) == alleged_uid)
205 match = TRUE;
209 #else
210 /* TODO: Dont know how to compare credentials on this OS. Please implement. */
211 #endif
213 out:
214 return match;
217 static void
218 mechanism_server_initiate (GDBusAuthMechanism *mechanism,
219 const gchar *initial_response,
220 gsize initial_response_len)
222 GDBusAuthMechanismExternal *m = G_DBUS_AUTH_MECHANISM_EXTERNAL (mechanism);
224 g_return_if_fail (G_IS_DBUS_AUTH_MECHANISM_EXTERNAL (mechanism));
225 g_return_if_fail (!m->priv->is_server && !m->priv->is_client);
227 m->priv->is_server = TRUE;
229 if (initial_response != NULL)
231 if (data_matches_credentials (initial_response,
232 initial_response_len,
233 _g_dbus_auth_mechanism_get_credentials (mechanism)))
235 m->priv->state = G_DBUS_AUTH_MECHANISM_STATE_ACCEPTED;
237 else
239 m->priv->state = G_DBUS_AUTH_MECHANISM_STATE_REJECTED;
242 else
244 m->priv->state = G_DBUS_AUTH_MECHANISM_STATE_WAITING_FOR_DATA;
248 static void
249 mechanism_server_data_receive (GDBusAuthMechanism *mechanism,
250 const gchar *data,
251 gsize data_len)
253 GDBusAuthMechanismExternal *m = G_DBUS_AUTH_MECHANISM_EXTERNAL (mechanism);
255 g_return_if_fail (G_IS_DBUS_AUTH_MECHANISM_EXTERNAL (mechanism));
256 g_return_if_fail (m->priv->is_server && !m->priv->is_client);
257 g_return_if_fail (m->priv->state == G_DBUS_AUTH_MECHANISM_STATE_WAITING_FOR_DATA);
259 if (data_matches_credentials (data,
260 data_len,
261 _g_dbus_auth_mechanism_get_credentials (mechanism)))
263 m->priv->state = G_DBUS_AUTH_MECHANISM_STATE_ACCEPTED;
265 else
267 m->priv->state = G_DBUS_AUTH_MECHANISM_STATE_REJECTED;
271 static gchar *
272 mechanism_server_data_send (GDBusAuthMechanism *mechanism,
273 gsize *out_data_len)
275 GDBusAuthMechanismExternal *m = G_DBUS_AUTH_MECHANISM_EXTERNAL (mechanism);
277 g_return_val_if_fail (G_IS_DBUS_AUTH_MECHANISM_EXTERNAL (mechanism), NULL);
278 g_return_val_if_fail (m->priv->is_server && !m->priv->is_client, NULL);
279 g_return_val_if_fail (m->priv->state == G_DBUS_AUTH_MECHANISM_STATE_HAVE_DATA_TO_SEND, NULL);
281 /* can never end up here because we are never in the HAVE_DATA_TO_SEND state */
282 g_assert_not_reached ();
284 return NULL;
287 static gchar *
288 mechanism_server_get_reject_reason (GDBusAuthMechanism *mechanism)
290 GDBusAuthMechanismExternal *m = G_DBUS_AUTH_MECHANISM_EXTERNAL (mechanism);
292 g_return_val_if_fail (G_IS_DBUS_AUTH_MECHANISM_EXTERNAL (mechanism), NULL);
293 g_return_val_if_fail (m->priv->is_server && !m->priv->is_client, NULL);
294 g_return_val_if_fail (m->priv->state == G_DBUS_AUTH_MECHANISM_STATE_REJECTED, NULL);
296 /* can never end up here because we are never in the REJECTED state */
297 g_assert_not_reached ();
299 return NULL;
302 static void
303 mechanism_server_shutdown (GDBusAuthMechanism *mechanism)
305 GDBusAuthMechanismExternal *m = G_DBUS_AUTH_MECHANISM_EXTERNAL (mechanism);
307 g_return_if_fail (G_IS_DBUS_AUTH_MECHANISM_EXTERNAL (mechanism));
308 g_return_if_fail (m->priv->is_server && !m->priv->is_client);
310 m->priv->is_server = FALSE;
313 /* ---------------------------------------------------------------------------------------------------- */
315 static GDBusAuthMechanismState
316 mechanism_client_get_state (GDBusAuthMechanism *mechanism)
318 GDBusAuthMechanismExternal *m = G_DBUS_AUTH_MECHANISM_EXTERNAL (mechanism);
320 g_return_val_if_fail (G_IS_DBUS_AUTH_MECHANISM_EXTERNAL (mechanism), G_DBUS_AUTH_MECHANISM_STATE_INVALID);
321 g_return_val_if_fail (m->priv->is_client && !m->priv->is_server, G_DBUS_AUTH_MECHANISM_STATE_INVALID);
323 return m->priv->state;
326 static gchar *
327 mechanism_client_initiate (GDBusAuthMechanism *mechanism,
328 gsize *out_initial_response_len)
330 GDBusAuthMechanismExternal *m = G_DBUS_AUTH_MECHANISM_EXTERNAL (mechanism);
331 gchar *initial_response = NULL;
332 GCredentials *credentials;
334 g_return_val_if_fail (G_IS_DBUS_AUTH_MECHANISM_EXTERNAL (mechanism), NULL);
335 g_return_val_if_fail (!m->priv->is_server && !m->priv->is_client, NULL);
337 m->priv->is_client = TRUE;
338 m->priv->state = G_DBUS_AUTH_MECHANISM_STATE_ACCEPTED;
340 *out_initial_response_len = 0;
342 credentials = _g_dbus_auth_mechanism_get_credentials (mechanism);
343 g_assert (credentials != NULL);
345 /* return the uid */
346 #if defined(G_OS_UNIX)
347 initial_response = g_strdup_printf ("%" G_GINT64_FORMAT, (gint64) g_credentials_get_unix_user (credentials, NULL));
348 *out_initial_response_len = strlen (initial_response);
349 #elif defined(G_OS_WIN32)
350 #ifdef __GNUC__
351 #pragma GCC diagnostic push
352 #pragma GCC diagnostic warning "-Wcpp"
353 #warning Dont know how to send credentials on this OS. The EXTERNAL D-Bus authentication mechanism will not work.
354 #pragma GCC diagnostic pop
355 #endif
356 m->priv->state = G_DBUS_AUTH_MECHANISM_STATE_REJECTED;
357 #endif
358 return initial_response;
361 static void
362 mechanism_client_data_receive (GDBusAuthMechanism *mechanism,
363 const gchar *data,
364 gsize data_len)
366 GDBusAuthMechanismExternal *m = G_DBUS_AUTH_MECHANISM_EXTERNAL (mechanism);
368 g_return_if_fail (G_IS_DBUS_AUTH_MECHANISM_EXTERNAL (mechanism));
369 g_return_if_fail (m->priv->is_client && !m->priv->is_server);
370 g_return_if_fail (m->priv->state == G_DBUS_AUTH_MECHANISM_STATE_WAITING_FOR_DATA);
372 /* can never end up here because we are never in the WAITING_FOR_DATA state */
373 g_assert_not_reached ();
376 static gchar *
377 mechanism_client_data_send (GDBusAuthMechanism *mechanism,
378 gsize *out_data_len)
380 GDBusAuthMechanismExternal *m = G_DBUS_AUTH_MECHANISM_EXTERNAL (mechanism);
382 g_return_val_if_fail (G_IS_DBUS_AUTH_MECHANISM_EXTERNAL (mechanism), NULL);
383 g_return_val_if_fail (m->priv->is_client && !m->priv->is_server, NULL);
384 g_return_val_if_fail (m->priv->state == G_DBUS_AUTH_MECHANISM_STATE_HAVE_DATA_TO_SEND, NULL);
386 /* can never end up here because we are never in the HAVE_DATA_TO_SEND state */
387 g_assert_not_reached ();
389 return NULL;
392 static void
393 mechanism_client_shutdown (GDBusAuthMechanism *mechanism)
395 GDBusAuthMechanismExternal *m = G_DBUS_AUTH_MECHANISM_EXTERNAL (mechanism);
397 g_return_if_fail (G_IS_DBUS_AUTH_MECHANISM_EXTERNAL (mechanism));
398 g_return_if_fail (m->priv->is_client && !m->priv->is_server);
400 m->priv->is_client = FALSE;
403 /* ---------------------------------------------------------------------------------------------------- */