Add some more cases to the app-id unit tests
[glib.git] / gio / gdbusauthmechanismexternal.c
blobc456ce2b6ae40eafd4540032ddcf322b01c1cf16
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, 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 GCredentials *credentials)
183 gboolean match;
185 match = FALSE;
187 if (credentials == NULL)
188 goto out;
190 if (data == NULL || strlen (data) == 0)
191 goto out;
193 #if defined(G_OS_UNIX)
195 gint64 alleged_uid;
196 gchar *endp;
198 /* on UNIX, this is the uid as a string in base 10 */
199 alleged_uid = g_ascii_strtoll (data, &endp, 10);
200 if (*endp == '\0')
202 if (g_credentials_get_unix_user (credentials, NULL) == alleged_uid)
204 match = TRUE;
208 #else
209 /* TODO: Dont know how to compare credentials on this OS. Please implement. */
210 #endif
212 out:
213 return match;
216 static void
217 mechanism_server_initiate (GDBusAuthMechanism *mechanism,
218 const gchar *initial_response,
219 gsize initial_response_len)
221 GDBusAuthMechanismExternal *m = G_DBUS_AUTH_MECHANISM_EXTERNAL (mechanism);
223 g_return_if_fail (G_IS_DBUS_AUTH_MECHANISM_EXTERNAL (mechanism));
224 g_return_if_fail (!m->priv->is_server && !m->priv->is_client);
226 m->priv->is_server = TRUE;
228 if (initial_response != NULL)
230 if (data_matches_credentials (initial_response, _g_dbus_auth_mechanism_get_credentials (mechanism)))
232 m->priv->state = G_DBUS_AUTH_MECHANISM_STATE_ACCEPTED;
234 else
236 m->priv->state = G_DBUS_AUTH_MECHANISM_STATE_REJECTED;
239 else
241 m->priv->state = G_DBUS_AUTH_MECHANISM_STATE_WAITING_FOR_DATA;
245 static void
246 mechanism_server_data_receive (GDBusAuthMechanism *mechanism,
247 const gchar *data,
248 gsize data_len)
250 GDBusAuthMechanismExternal *m = G_DBUS_AUTH_MECHANISM_EXTERNAL (mechanism);
252 g_return_if_fail (G_IS_DBUS_AUTH_MECHANISM_EXTERNAL (mechanism));
253 g_return_if_fail (m->priv->is_server && !m->priv->is_client);
254 g_return_if_fail (m->priv->state == G_DBUS_AUTH_MECHANISM_STATE_WAITING_FOR_DATA);
256 if (data_matches_credentials (data, _g_dbus_auth_mechanism_get_credentials (mechanism)))
258 m->priv->state = G_DBUS_AUTH_MECHANISM_STATE_ACCEPTED;
260 else
262 m->priv->state = G_DBUS_AUTH_MECHANISM_STATE_REJECTED;
266 static gchar *
267 mechanism_server_data_send (GDBusAuthMechanism *mechanism,
268 gsize *out_data_len)
270 GDBusAuthMechanismExternal *m = G_DBUS_AUTH_MECHANISM_EXTERNAL (mechanism);
272 g_return_val_if_fail (G_IS_DBUS_AUTH_MECHANISM_EXTERNAL (mechanism), NULL);
273 g_return_val_if_fail (m->priv->is_server && !m->priv->is_client, NULL);
274 g_return_val_if_fail (m->priv->state == G_DBUS_AUTH_MECHANISM_STATE_HAVE_DATA_TO_SEND, NULL);
276 /* can never end up here because we are never in the HAVE_DATA_TO_SEND state */
277 g_assert_not_reached ();
279 return NULL;
282 static gchar *
283 mechanism_server_get_reject_reason (GDBusAuthMechanism *mechanism)
285 GDBusAuthMechanismExternal *m = G_DBUS_AUTH_MECHANISM_EXTERNAL (mechanism);
287 g_return_val_if_fail (G_IS_DBUS_AUTH_MECHANISM_EXTERNAL (mechanism), NULL);
288 g_return_val_if_fail (m->priv->is_server && !m->priv->is_client, NULL);
289 g_return_val_if_fail (m->priv->state == G_DBUS_AUTH_MECHANISM_STATE_REJECTED, NULL);
291 /* can never end up here because we are never in the REJECTED state */
292 g_assert_not_reached ();
294 return NULL;
297 static void
298 mechanism_server_shutdown (GDBusAuthMechanism *mechanism)
300 GDBusAuthMechanismExternal *m = G_DBUS_AUTH_MECHANISM_EXTERNAL (mechanism);
302 g_return_if_fail (G_IS_DBUS_AUTH_MECHANISM_EXTERNAL (mechanism));
303 g_return_if_fail (m->priv->is_server && !m->priv->is_client);
305 m->priv->is_server = FALSE;
308 /* ---------------------------------------------------------------------------------------------------- */
310 static GDBusAuthMechanismState
311 mechanism_client_get_state (GDBusAuthMechanism *mechanism)
313 GDBusAuthMechanismExternal *m = G_DBUS_AUTH_MECHANISM_EXTERNAL (mechanism);
315 g_return_val_if_fail (G_IS_DBUS_AUTH_MECHANISM_EXTERNAL (mechanism), G_DBUS_AUTH_MECHANISM_STATE_INVALID);
316 g_return_val_if_fail (m->priv->is_client && !m->priv->is_server, G_DBUS_AUTH_MECHANISM_STATE_INVALID);
318 return m->priv->state;
321 static gchar *
322 mechanism_client_initiate (GDBusAuthMechanism *mechanism,
323 gsize *out_initial_response_len)
325 GDBusAuthMechanismExternal *m = G_DBUS_AUTH_MECHANISM_EXTERNAL (mechanism);
326 gchar *initial_response = NULL;
327 GCredentials *credentials;
329 g_return_val_if_fail (G_IS_DBUS_AUTH_MECHANISM_EXTERNAL (mechanism), NULL);
330 g_return_val_if_fail (!m->priv->is_server && !m->priv->is_client, NULL);
332 m->priv->is_client = TRUE;
333 m->priv->state = G_DBUS_AUTH_MECHANISM_STATE_ACCEPTED;
335 *out_initial_response_len = -1;
337 credentials = _g_dbus_auth_mechanism_get_credentials (mechanism);
338 g_assert (credentials != NULL);
340 /* return the uid */
341 #if defined(G_OS_UNIX)
342 initial_response = g_strdup_printf ("%" G_GINT64_FORMAT, (gint64) g_credentials_get_unix_user (credentials, NULL));
343 #elif defined(G_OS_WIN32)
344 #ifdef __GNUC__
345 #warning Dont know how to send credentials on this OS. The EXTERNAL D-Bus authentication mechanism will not work.
346 #endif
347 m->priv->state = G_DBUS_AUTH_MECHANISM_STATE_REJECTED;
348 #endif
349 return initial_response;
352 static void
353 mechanism_client_data_receive (GDBusAuthMechanism *mechanism,
354 const gchar *data,
355 gsize data_len)
357 GDBusAuthMechanismExternal *m = G_DBUS_AUTH_MECHANISM_EXTERNAL (mechanism);
359 g_return_if_fail (G_IS_DBUS_AUTH_MECHANISM_EXTERNAL (mechanism));
360 g_return_if_fail (m->priv->is_client && !m->priv->is_server);
361 g_return_if_fail (m->priv->state == G_DBUS_AUTH_MECHANISM_STATE_WAITING_FOR_DATA);
363 /* can never end up here because we are never in the WAITING_FOR_DATA state */
364 g_assert_not_reached ();
367 static gchar *
368 mechanism_client_data_send (GDBusAuthMechanism *mechanism,
369 gsize *out_data_len)
371 GDBusAuthMechanismExternal *m = G_DBUS_AUTH_MECHANISM_EXTERNAL (mechanism);
373 g_return_val_if_fail (G_IS_DBUS_AUTH_MECHANISM_EXTERNAL (mechanism), NULL);
374 g_return_val_if_fail (m->priv->is_client && !m->priv->is_server, NULL);
375 g_return_val_if_fail (m->priv->state == G_DBUS_AUTH_MECHANISM_STATE_HAVE_DATA_TO_SEND, NULL);
377 /* can never end up here because we are never in the HAVE_DATA_TO_SEND state */
378 g_assert_not_reached ();
380 return NULL;
383 static void
384 mechanism_client_shutdown (GDBusAuthMechanism *mechanism)
386 GDBusAuthMechanismExternal *m = G_DBUS_AUTH_MECHANISM_EXTERNAL (mechanism);
388 g_return_if_fail (G_IS_DBUS_AUTH_MECHANISM_EXTERNAL (mechanism));
389 g_return_if_fail (m->priv->is_client && !m->priv->is_server);
391 m->priv->is_client = FALSE;
394 /* ---------------------------------------------------------------------------------------------------- */