3fcb1ee229002624450dcfedf3c57d3881ab8e05
[platform/upstream/glib.git] / gio / gdbusauthmechanismexternal.c
1 /* GDBus - GLib D-Bus Library
2  *
3  * Copyright (C) 2008-2010 Red Hat, Inc.
4  *
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.
9  *
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.
14  *
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.
19  *
20  * Author: David Zeuthen <davidz@redhat.com>
21  */
22
23 #include "config.h"
24
25 #include <string.h>
26 #include <sys/types.h>
27 #ifdef HAVE_UNISTD_H
28 #include <unistd.h>
29 #endif
30
31 #include "gdbusauthmechanismexternal.h"
32 #include "gcredentials.h"
33 #include "gdbuserror.h"
34 #include "gioenumtypes.h"
35
36 #include "glibintl.h"
37
38 struct _GDBusAuthMechanismExternalPrivate
39 {
40   gboolean is_client;
41   gboolean is_server;
42   GDBusAuthMechanismState state;
43 };
44
45 static gint                     mechanism_get_priority              (void);
46 static const gchar             *mechanism_get_name                  (void);
47
48 static gboolean                 mechanism_is_supported              (GDBusAuthMechanism   *mechanism);
49 static gchar                   *mechanism_encode_data               (GDBusAuthMechanism   *mechanism,
50                                                                      const gchar          *data,
51                                                                      gsize                 data_len,
52                                                                      gsize                *out_data_len);
53 static gchar                   *mechanism_decode_data               (GDBusAuthMechanism   *mechanism,
54                                                                      const gchar          *data,
55                                                                      gsize                 data_len,
56                                                                      gsize                *out_data_len);
57 static GDBusAuthMechanismState  mechanism_server_get_state          (GDBusAuthMechanism   *mechanism);
58 static void                     mechanism_server_initiate           (GDBusAuthMechanism   *mechanism,
59                                                                      const gchar          *initial_response,
60                                                                      gsize                 initial_response_len);
61 static void                     mechanism_server_data_receive       (GDBusAuthMechanism   *mechanism,
62                                                                      const gchar          *data,
63                                                                      gsize                 data_len);
64 static gchar                   *mechanism_server_data_send          (GDBusAuthMechanism   *mechanism,
65                                                                      gsize                *out_data_len);
66 static gchar                   *mechanism_server_get_reject_reason  (GDBusAuthMechanism   *mechanism);
67 static void                     mechanism_server_shutdown           (GDBusAuthMechanism   *mechanism);
68 static GDBusAuthMechanismState  mechanism_client_get_state          (GDBusAuthMechanism   *mechanism);
69 static gchar                   *mechanism_client_initiate           (GDBusAuthMechanism   *mechanism,
70                                                                      gsize                *out_initial_response_len);
71 static void                     mechanism_client_data_receive       (GDBusAuthMechanism   *mechanism,
72                                                                      const gchar          *data,
73                                                                      gsize                 data_len);
74 static gchar                   *mechanism_client_data_send          (GDBusAuthMechanism   *mechanism,
75                                                                      gsize                *out_data_len);
76 static void                     mechanism_client_shutdown           (GDBusAuthMechanism   *mechanism);
77
78 /* ---------------------------------------------------------------------------------------------------- */
79
80 G_DEFINE_TYPE (GDBusAuthMechanismExternal, _g_dbus_auth_mechanism_external, G_TYPE_DBUS_AUTH_MECHANISM);
81
82 /* ---------------------------------------------------------------------------------------------------- */
83
84 static void
85 _g_dbus_auth_mechanism_external_finalize (GObject *object)
86 {
87   //GDBusAuthMechanismExternal *mechanism = G_DBUS_AUTH_MECHANISM_EXTERNAL (object);
88
89   if (G_OBJECT_CLASS (_g_dbus_auth_mechanism_external_parent_class)->finalize != NULL)
90     G_OBJECT_CLASS (_g_dbus_auth_mechanism_external_parent_class)->finalize (object);
91 }
92
93 static void
94 _g_dbus_auth_mechanism_external_class_init (GDBusAuthMechanismExternalClass *klass)
95 {
96   GObjectClass *gobject_class;
97   GDBusAuthMechanismClass *mechanism_class;
98
99   g_type_class_add_private (klass, sizeof (GDBusAuthMechanismExternalPrivate));
100
101   gobject_class = G_OBJECT_CLASS (klass);
102   gobject_class->finalize = _g_dbus_auth_mechanism_external_finalize;
103
104   mechanism_class = G_DBUS_AUTH_MECHANISM_CLASS (klass);
105   mechanism_class->get_name                  = mechanism_get_name;
106   mechanism_class->get_priority              = mechanism_get_priority;
107   mechanism_class->is_supported              = mechanism_is_supported;
108   mechanism_class->encode_data               = mechanism_encode_data;
109   mechanism_class->decode_data               = mechanism_decode_data;
110   mechanism_class->server_get_state          = mechanism_server_get_state;
111   mechanism_class->server_initiate           = mechanism_server_initiate;
112   mechanism_class->server_data_receive       = mechanism_server_data_receive;
113   mechanism_class->server_data_send          = mechanism_server_data_send;
114   mechanism_class->server_get_reject_reason  = mechanism_server_get_reject_reason;
115   mechanism_class->server_shutdown           = mechanism_server_shutdown;
116   mechanism_class->client_get_state          = mechanism_client_get_state;
117   mechanism_class->client_initiate           = mechanism_client_initiate;
118   mechanism_class->client_data_receive       = mechanism_client_data_receive;
119   mechanism_class->client_data_send          = mechanism_client_data_send;
120   mechanism_class->client_shutdown           = mechanism_client_shutdown;
121 }
122
123 static void
124 _g_dbus_auth_mechanism_external_init (GDBusAuthMechanismExternal *mechanism)
125 {
126   mechanism->priv = G_TYPE_INSTANCE_GET_PRIVATE (mechanism,
127                                                  G_TYPE_DBUS_AUTH_MECHANISM_EXTERNAL,
128                                                  GDBusAuthMechanismExternalPrivate);
129 }
130
131 /* ---------------------------------------------------------------------------------------------------- */
132
133 static gboolean
134 mechanism_is_supported (GDBusAuthMechanism *mechanism)
135 {
136   g_return_val_if_fail (G_IS_DBUS_AUTH_MECHANISM_EXTERNAL (mechanism), FALSE);
137   /* This mechanism is only available if credentials has been exchanged */
138   if (_g_dbus_auth_mechanism_get_credentials (mechanism) != NULL)
139     return TRUE;
140   else
141     return FALSE;
142 }
143
144 static gint
145 mechanism_get_priority (void)
146 {
147   /* We prefer EXTERNAL to most other mechanism (DBUS_COOKIE_SHA1 and ANONYMOUS) */
148   return 100;
149 }
150
151 static const gchar *
152 mechanism_get_name (void)
153 {
154   return "EXTERNAL";
155 }
156
157 static gchar *
158 mechanism_encode_data (GDBusAuthMechanism   *mechanism,
159                        const gchar          *data,
160                        gsize                 data_len,
161                        gsize                *out_data_len)
162 {
163   return NULL;
164 }
165
166
167 static gchar *
168 mechanism_decode_data (GDBusAuthMechanism   *mechanism,
169                        const gchar          *data,
170                        gsize                 data_len,
171                        gsize                *out_data_len)
172 {
173   return NULL;
174 }
175
176 /* ---------------------------------------------------------------------------------------------------- */
177
178 static GDBusAuthMechanismState
179 mechanism_server_get_state (GDBusAuthMechanism   *mechanism)
180 {
181   GDBusAuthMechanismExternal *m = G_DBUS_AUTH_MECHANISM_EXTERNAL (mechanism);
182
183   g_return_val_if_fail (G_IS_DBUS_AUTH_MECHANISM_EXTERNAL (mechanism), G_DBUS_AUTH_MECHANISM_STATE_INVALID);
184   g_return_val_if_fail (m->priv->is_server && !m->priv->is_client, G_DBUS_AUTH_MECHANISM_STATE_INVALID);
185
186   return m->priv->state;
187 }
188
189 static gboolean
190 data_matches_credentials (const gchar *data,
191                           GCredentials *credentials)
192 {
193   gboolean match;
194
195   match = FALSE;
196
197   if (credentials == NULL)
198     goto out;
199
200   if (data == NULL || strlen (data) == 0)
201     goto out;
202
203 #if defined(G_OS_UNIX)
204   {
205     gint64 alleged_uid;
206     gchar *endp;
207
208     /* on UNIX, this is the uid as a string in base 10 */
209     alleged_uid = g_ascii_strtoll (data, &endp, 10);
210     if (*endp == '\0')
211       {
212         if (g_credentials_get_unix_user (credentials, NULL) == alleged_uid)
213           {
214             match = TRUE;
215           }
216       }
217   }
218 #else
219   /* TODO: Dont know how to compare credentials on this OS. Please implement. */
220 #endif
221
222  out:
223   return match;
224 }
225
226 static void
227 mechanism_server_initiate (GDBusAuthMechanism   *mechanism,
228                            const gchar          *initial_response,
229                            gsize                 initial_response_len)
230 {
231   GDBusAuthMechanismExternal *m = G_DBUS_AUTH_MECHANISM_EXTERNAL (mechanism);
232
233   g_return_if_fail (G_IS_DBUS_AUTH_MECHANISM_EXTERNAL (mechanism));
234   g_return_if_fail (!m->priv->is_server && !m->priv->is_client);
235
236   m->priv->is_server = TRUE;
237
238   if (initial_response != NULL)
239     {
240       if (data_matches_credentials (initial_response, _g_dbus_auth_mechanism_get_credentials (mechanism)))
241         {
242           m->priv->state = G_DBUS_AUTH_MECHANISM_STATE_ACCEPTED;
243         }
244       else
245         {
246           m->priv->state = G_DBUS_AUTH_MECHANISM_STATE_REJECTED;
247         }
248     }
249   else
250     {
251       m->priv->state = G_DBUS_AUTH_MECHANISM_STATE_WAITING_FOR_DATA;
252     }
253 }
254
255 static void
256 mechanism_server_data_receive (GDBusAuthMechanism   *mechanism,
257                                const gchar          *data,
258                                gsize                 data_len)
259 {
260   GDBusAuthMechanismExternal *m = G_DBUS_AUTH_MECHANISM_EXTERNAL (mechanism);
261
262   g_return_if_fail (G_IS_DBUS_AUTH_MECHANISM_EXTERNAL (mechanism));
263   g_return_if_fail (m->priv->is_server && !m->priv->is_client);
264   g_return_if_fail (m->priv->state == G_DBUS_AUTH_MECHANISM_STATE_WAITING_FOR_DATA);
265
266   if (data_matches_credentials (data, _g_dbus_auth_mechanism_get_credentials (mechanism)))
267     {
268       m->priv->state = G_DBUS_AUTH_MECHANISM_STATE_ACCEPTED;
269     }
270   else
271     {
272       m->priv->state = G_DBUS_AUTH_MECHANISM_STATE_REJECTED;
273     }
274 }
275
276 static gchar *
277 mechanism_server_data_send (GDBusAuthMechanism   *mechanism,
278                             gsize                *out_data_len)
279 {
280   GDBusAuthMechanismExternal *m = G_DBUS_AUTH_MECHANISM_EXTERNAL (mechanism);
281
282   g_return_val_if_fail (G_IS_DBUS_AUTH_MECHANISM_EXTERNAL (mechanism), NULL);
283   g_return_val_if_fail (m->priv->is_server && !m->priv->is_client, NULL);
284   g_return_val_if_fail (m->priv->state == G_DBUS_AUTH_MECHANISM_STATE_HAVE_DATA_TO_SEND, NULL);
285
286   /* can never end up here because we are never in the HAVE_DATA_TO_SEND state */
287   g_assert_not_reached ();
288
289   return NULL;
290 }
291
292 static gchar *
293 mechanism_server_get_reject_reason (GDBusAuthMechanism   *mechanism)
294 {
295   GDBusAuthMechanismExternal *m = G_DBUS_AUTH_MECHANISM_EXTERNAL (mechanism);
296
297   g_return_val_if_fail (G_IS_DBUS_AUTH_MECHANISM_EXTERNAL (mechanism), NULL);
298   g_return_val_if_fail (m->priv->is_server && !m->priv->is_client, NULL);
299   g_return_val_if_fail (m->priv->state == G_DBUS_AUTH_MECHANISM_STATE_REJECTED, NULL);
300
301   /* can never end up here because we are never in the REJECTED state */
302   g_assert_not_reached ();
303
304   return NULL;
305 }
306
307 static void
308 mechanism_server_shutdown (GDBusAuthMechanism   *mechanism)
309 {
310   GDBusAuthMechanismExternal *m = G_DBUS_AUTH_MECHANISM_EXTERNAL (mechanism);
311
312   g_return_if_fail (G_IS_DBUS_AUTH_MECHANISM_EXTERNAL (mechanism));
313   g_return_if_fail (m->priv->is_server && !m->priv->is_client);
314
315   m->priv->is_server = FALSE;
316 }
317
318 /* ---------------------------------------------------------------------------------------------------- */
319
320 static GDBusAuthMechanismState
321 mechanism_client_get_state (GDBusAuthMechanism   *mechanism)
322 {
323   GDBusAuthMechanismExternal *m = G_DBUS_AUTH_MECHANISM_EXTERNAL (mechanism);
324
325   g_return_val_if_fail (G_IS_DBUS_AUTH_MECHANISM_EXTERNAL (mechanism), G_DBUS_AUTH_MECHANISM_STATE_INVALID);
326   g_return_val_if_fail (m->priv->is_client && !m->priv->is_server, G_DBUS_AUTH_MECHANISM_STATE_INVALID);
327
328   return m->priv->state;
329 }
330
331 static gchar *
332 mechanism_client_initiate (GDBusAuthMechanism   *mechanism,
333                            gsize                *out_initial_response_len)
334 {
335   GDBusAuthMechanismExternal *m = G_DBUS_AUTH_MECHANISM_EXTERNAL (mechanism);
336   gchar *initial_response;
337   GCredentials *credentials;
338
339   g_return_val_if_fail (G_IS_DBUS_AUTH_MECHANISM_EXTERNAL (mechanism), NULL);
340   g_return_val_if_fail (!m->priv->is_server && !m->priv->is_client, NULL);
341
342   m->priv->is_client = TRUE;
343   m->priv->state = G_DBUS_AUTH_MECHANISM_STATE_ACCEPTED;
344
345   *out_initial_response_len = -1;
346
347   credentials = _g_dbus_auth_mechanism_get_credentials (mechanism);
348   g_assert (credentials != NULL);
349
350   /* return the uid */
351 #if defined(G_OS_UNIX)
352   initial_response = g_strdup_printf ("%" G_GINT64_FORMAT, (gint64) g_credentials_get_unix_user (credentials, NULL));
353 #elif defined(G_OS_WIN32)
354 #ifdef __GNUC__
355 #warning Dont know how to send credentials on this OS. The EXTERNAL D-Bus authentication mechanism will not work.
356 #endif
357   m->priv->state = G_DBUS_AUTH_MECHANISM_STATE_REJECTED;
358 #endif
359   return initial_response;
360 }
361
362 static void
363 mechanism_client_data_receive (GDBusAuthMechanism   *mechanism,
364                                const gchar          *data,
365                                gsize                 data_len)
366 {
367   GDBusAuthMechanismExternal *m = G_DBUS_AUTH_MECHANISM_EXTERNAL (mechanism);
368
369   g_return_if_fail (G_IS_DBUS_AUTH_MECHANISM_EXTERNAL (mechanism));
370   g_return_if_fail (m->priv->is_client && !m->priv->is_server);
371   g_return_if_fail (m->priv->state == G_DBUS_AUTH_MECHANISM_STATE_WAITING_FOR_DATA);
372
373   /* can never end up here because we are never in the WAITING_FOR_DATA state */
374   g_assert_not_reached ();
375 }
376
377 static gchar *
378 mechanism_client_data_send (GDBusAuthMechanism   *mechanism,
379                             gsize                *out_data_len)
380 {
381   GDBusAuthMechanismExternal *m = G_DBUS_AUTH_MECHANISM_EXTERNAL (mechanism);
382
383   g_return_val_if_fail (G_IS_DBUS_AUTH_MECHANISM_EXTERNAL (mechanism), NULL);
384   g_return_val_if_fail (m->priv->is_client && !m->priv->is_server, NULL);
385   g_return_val_if_fail (m->priv->state == G_DBUS_AUTH_MECHANISM_STATE_HAVE_DATA_TO_SEND, NULL);
386
387   /* can never end up here because we are never in the HAVE_DATA_TO_SEND state */
388   g_assert_not_reached ();
389
390   return NULL;
391 }
392
393 static void
394 mechanism_client_shutdown (GDBusAuthMechanism   *mechanism)
395 {
396   GDBusAuthMechanismExternal *m = G_DBUS_AUTH_MECHANISM_EXTERNAL (mechanism);
397
398   g_return_if_fail (G_IS_DBUS_AUTH_MECHANISM_EXTERNAL (mechanism));
399   g_return_if_fail (m->priv->is_client && !m->priv->is_server);
400
401   m->priv->is_client = FALSE;
402 }
403
404 /* ---------------------------------------------------------------------------------------------------- */