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 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, write to the
17 * Free Software Foundation, Inc., 59 Temple Place, Suite 330,
18 * Boston, MA 02111-1307, USA.
20 * Author: David Zeuthen <davidz@redhat.com>
26 #include <sys/types.h>
31 #include "gdbusauthmechanismexternal.h"
32 #include "gcredentials.h"
33 #include "gdbuserror.h"
34 #include "gioenumtypes.h"
39 struct _GDBusAuthMechanismExternalPrivate
43 GDBusAuthMechanismState state;
46 static gint mechanism_get_priority (void);
47 static const gchar *mechanism_get_name (void);
49 static gboolean mechanism_is_supported (GDBusAuthMechanism *mechanism);
50 static gchar *mechanism_encode_data (GDBusAuthMechanism *mechanism,
54 static gchar *mechanism_decode_data (GDBusAuthMechanism *mechanism,
58 static GDBusAuthMechanismState mechanism_server_get_state (GDBusAuthMechanism *mechanism);
59 static void mechanism_server_initiate (GDBusAuthMechanism *mechanism,
60 const gchar *initial_response,
61 gsize initial_response_len);
62 static void mechanism_server_data_receive (GDBusAuthMechanism *mechanism,
65 static gchar *mechanism_server_data_send (GDBusAuthMechanism *mechanism,
67 static gchar *mechanism_server_get_reject_reason (GDBusAuthMechanism *mechanism);
68 static void mechanism_server_shutdown (GDBusAuthMechanism *mechanism);
69 static GDBusAuthMechanismState mechanism_client_get_state (GDBusAuthMechanism *mechanism);
70 static gchar *mechanism_client_initiate (GDBusAuthMechanism *mechanism,
71 gsize *out_initial_response_len);
72 static void mechanism_client_data_receive (GDBusAuthMechanism *mechanism,
75 static gchar *mechanism_client_data_send (GDBusAuthMechanism *mechanism,
77 static void mechanism_client_shutdown (GDBusAuthMechanism *mechanism);
79 /* ---------------------------------------------------------------------------------------------------- */
81 G_DEFINE_TYPE (GDBusAuthMechanismExternal, _g_dbus_auth_mechanism_external, G_TYPE_DBUS_AUTH_MECHANISM);
83 /* ---------------------------------------------------------------------------------------------------- */
86 _g_dbus_auth_mechanism_external_finalize (GObject *object)
88 //GDBusAuthMechanismExternal *mechanism = G_DBUS_AUTH_MECHANISM_EXTERNAL (object);
90 if (G_OBJECT_CLASS (_g_dbus_auth_mechanism_external_parent_class)->finalize != NULL)
91 G_OBJECT_CLASS (_g_dbus_auth_mechanism_external_parent_class)->finalize (object);
95 _g_dbus_auth_mechanism_external_class_init (GDBusAuthMechanismExternalClass *klass)
97 GObjectClass *gobject_class;
98 GDBusAuthMechanismClass *mechanism_class;
100 g_type_class_add_private (klass, sizeof (GDBusAuthMechanismExternalPrivate));
102 gobject_class = G_OBJECT_CLASS (klass);
103 gobject_class->finalize = _g_dbus_auth_mechanism_external_finalize;
105 mechanism_class = G_DBUS_AUTH_MECHANISM_CLASS (klass);
106 mechanism_class->get_name = mechanism_get_name;
107 mechanism_class->get_priority = mechanism_get_priority;
108 mechanism_class->is_supported = mechanism_is_supported;
109 mechanism_class->encode_data = mechanism_encode_data;
110 mechanism_class->decode_data = mechanism_decode_data;
111 mechanism_class->server_get_state = mechanism_server_get_state;
112 mechanism_class->server_initiate = mechanism_server_initiate;
113 mechanism_class->server_data_receive = mechanism_server_data_receive;
114 mechanism_class->server_data_send = mechanism_server_data_send;
115 mechanism_class->server_get_reject_reason = mechanism_server_get_reject_reason;
116 mechanism_class->server_shutdown = mechanism_server_shutdown;
117 mechanism_class->client_get_state = mechanism_client_get_state;
118 mechanism_class->client_initiate = mechanism_client_initiate;
119 mechanism_class->client_data_receive = mechanism_client_data_receive;
120 mechanism_class->client_data_send = mechanism_client_data_send;
121 mechanism_class->client_shutdown = mechanism_client_shutdown;
125 _g_dbus_auth_mechanism_external_init (GDBusAuthMechanismExternal *mechanism)
127 mechanism->priv = G_TYPE_INSTANCE_GET_PRIVATE (mechanism,
128 G_TYPE_DBUS_AUTH_MECHANISM_EXTERNAL,
129 GDBusAuthMechanismExternalPrivate);
132 /* ---------------------------------------------------------------------------------------------------- */
135 mechanism_is_supported (GDBusAuthMechanism *mechanism)
137 g_return_val_if_fail (G_IS_DBUS_AUTH_MECHANISM_EXTERNAL (mechanism), FALSE);
138 /* This mechanism is only available if credentials has been exchanged */
139 if (_g_dbus_auth_mechanism_get_credentials (mechanism) != NULL)
146 mechanism_get_priority (void)
148 /* We prefer EXTERNAL to most other mechanism (DBUS_COOKIE_SHA1 and ANONYMOUS) */
153 mechanism_get_name (void)
159 mechanism_encode_data (GDBusAuthMechanism *mechanism,
169 mechanism_decode_data (GDBusAuthMechanism *mechanism,
177 /* ---------------------------------------------------------------------------------------------------- */
179 static GDBusAuthMechanismState
180 mechanism_server_get_state (GDBusAuthMechanism *mechanism)
182 GDBusAuthMechanismExternal *m = G_DBUS_AUTH_MECHANISM_EXTERNAL (mechanism);
184 g_return_val_if_fail (G_IS_DBUS_AUTH_MECHANISM_EXTERNAL (mechanism), G_DBUS_AUTH_MECHANISM_STATE_INVALID);
185 g_return_val_if_fail (m->priv->is_server && !m->priv->is_client, G_DBUS_AUTH_MECHANISM_STATE_INVALID);
187 return m->priv->state;
191 data_matches_credentials (const gchar *data,
192 GCredentials *credentials)
198 if (credentials == NULL)
201 if (data == NULL || strlen (data) == 0)
204 #if defined(G_OS_UNIX)
209 /* on UNIX, this is the uid as a string in base 10 */
210 alleged_uid = g_ascii_strtoll (data, &endp, 10);
213 if (g_credentials_get_unix_user (credentials, NULL) == alleged_uid)
220 /* TODO: Dont know how to compare credentials on this OS. Please implement. */
228 mechanism_server_initiate (GDBusAuthMechanism *mechanism,
229 const gchar *initial_response,
230 gsize initial_response_len)
232 GDBusAuthMechanismExternal *m = G_DBUS_AUTH_MECHANISM_EXTERNAL (mechanism);
234 g_return_if_fail (G_IS_DBUS_AUTH_MECHANISM_EXTERNAL (mechanism));
235 g_return_if_fail (!m->priv->is_server && !m->priv->is_client);
237 m->priv->is_server = TRUE;
239 if (initial_response != NULL)
241 if (data_matches_credentials (initial_response, _g_dbus_auth_mechanism_get_credentials (mechanism)))
243 m->priv->state = G_DBUS_AUTH_MECHANISM_STATE_ACCEPTED;
247 m->priv->state = G_DBUS_AUTH_MECHANISM_STATE_REJECTED;
252 m->priv->state = G_DBUS_AUTH_MECHANISM_STATE_WAITING_FOR_DATA;
257 mechanism_server_data_receive (GDBusAuthMechanism *mechanism,
261 GDBusAuthMechanismExternal *m = G_DBUS_AUTH_MECHANISM_EXTERNAL (mechanism);
263 g_return_if_fail (G_IS_DBUS_AUTH_MECHANISM_EXTERNAL (mechanism));
264 g_return_if_fail (m->priv->is_server && !m->priv->is_client);
265 g_return_if_fail (m->priv->state == G_DBUS_AUTH_MECHANISM_STATE_WAITING_FOR_DATA);
267 if (data_matches_credentials (data, _g_dbus_auth_mechanism_get_credentials (mechanism)))
269 m->priv->state = G_DBUS_AUTH_MECHANISM_STATE_ACCEPTED;
273 m->priv->state = G_DBUS_AUTH_MECHANISM_STATE_REJECTED;
278 mechanism_server_data_send (GDBusAuthMechanism *mechanism,
281 GDBusAuthMechanismExternal *m = G_DBUS_AUTH_MECHANISM_EXTERNAL (mechanism);
283 g_return_val_if_fail (G_IS_DBUS_AUTH_MECHANISM_EXTERNAL (mechanism), NULL);
284 g_return_val_if_fail (m->priv->is_server && !m->priv->is_client, NULL);
285 g_return_val_if_fail (m->priv->state == G_DBUS_AUTH_MECHANISM_STATE_HAVE_DATA_TO_SEND, NULL);
287 /* can never end up here because we are never in the HAVE_DATA_TO_SEND state */
288 g_assert_not_reached ();
294 mechanism_server_get_reject_reason (GDBusAuthMechanism *mechanism)
296 GDBusAuthMechanismExternal *m = G_DBUS_AUTH_MECHANISM_EXTERNAL (mechanism);
298 g_return_val_if_fail (G_IS_DBUS_AUTH_MECHANISM_EXTERNAL (mechanism), NULL);
299 g_return_val_if_fail (m->priv->is_server && !m->priv->is_client, NULL);
300 g_return_val_if_fail (m->priv->state == G_DBUS_AUTH_MECHANISM_STATE_REJECTED, NULL);
302 /* can never end up here because we are never in the REJECTED state */
303 g_assert_not_reached ();
309 mechanism_server_shutdown (GDBusAuthMechanism *mechanism)
311 GDBusAuthMechanismExternal *m = G_DBUS_AUTH_MECHANISM_EXTERNAL (mechanism);
313 g_return_if_fail (G_IS_DBUS_AUTH_MECHANISM_EXTERNAL (mechanism));
314 g_return_if_fail (m->priv->is_server && !m->priv->is_client);
316 m->priv->is_server = FALSE;
319 /* ---------------------------------------------------------------------------------------------------- */
321 static GDBusAuthMechanismState
322 mechanism_client_get_state (GDBusAuthMechanism *mechanism)
324 GDBusAuthMechanismExternal *m = G_DBUS_AUTH_MECHANISM_EXTERNAL (mechanism);
326 g_return_val_if_fail (G_IS_DBUS_AUTH_MECHANISM_EXTERNAL (mechanism), G_DBUS_AUTH_MECHANISM_STATE_INVALID);
327 g_return_val_if_fail (m->priv->is_client && !m->priv->is_server, G_DBUS_AUTH_MECHANISM_STATE_INVALID);
329 return m->priv->state;
333 mechanism_client_initiate (GDBusAuthMechanism *mechanism,
334 gsize *out_initial_response_len)
336 GDBusAuthMechanismExternal *m = G_DBUS_AUTH_MECHANISM_EXTERNAL (mechanism);
337 gchar *initial_response;
338 GCredentials *credentials;
340 g_return_val_if_fail (G_IS_DBUS_AUTH_MECHANISM_EXTERNAL (mechanism), NULL);
341 g_return_val_if_fail (!m->priv->is_server && !m->priv->is_client, NULL);
343 m->priv->is_client = TRUE;
344 m->priv->state = G_DBUS_AUTH_MECHANISM_STATE_ACCEPTED;
346 *out_initial_response_len = -1;
348 credentials = _g_dbus_auth_mechanism_get_credentials (mechanism);
349 g_assert (credentials != NULL);
352 #if defined(G_OS_UNIX)
353 initial_response = g_strdup_printf ("%" G_GINT64_FORMAT, (gint64) g_credentials_get_unix_user (credentials, NULL));
354 #elif defined(G_OS_WIN32)
355 #warning Dont know how to send credentials on this OS. The EXTERNAL D-Bus authentication mechanism will not work.
356 m->priv->state = G_DBUS_AUTH_MECHANISM_STATE_REJECTED;
358 return initial_response;
362 mechanism_client_data_receive (GDBusAuthMechanism *mechanism,
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 ();
377 mechanism_client_data_send (GDBusAuthMechanism *mechanism,
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 ();
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 /* ---------------------------------------------------------------------------------------------------- */
405 #define __G_DBUS_AUTH_MECHANISM_EXTERNAL_C__
406 #include "gioaliasdef.c"